c.org 73 KB

C cheatsheat

How to say complicated C declarations

http://www.programmerinterview.com/index.php/c-cplusplus/c-declarations/

Begin looking at the variable name. 1) without skipping a right parenthesis, look right and say what you see. 2) Without skipping a left parenthesis, look left and say what you see. 3) If you are inside a parenthesis, move out of it move to the right to see what you see. 4) Look left and see what you see. Start again from 1 if need be.

int (*a)[3];

Begin by looking at a. 1) Go right and a and hit a right parenthesis. Do not say anything. 2) Go left of a and say what you see. Do not pass a left parenthesis. A pointer. 3) Go outside the parenthesis and see an array of size 3. 4) Go left and see an int.

SO, a is a pointer to an array of 3 ints.

~char *i[2][8];~ 1) Move right of i and say array of size 2 and an array of size 8. 2) move let of i and say pointer 3) a char

i is an array composed of 2 arrays of 8 pointers to chars.

char *(*a[ 3 ])();

a is an array of size 3 pointers to functions, returning an char pointer

int (*t[])();

t

tersely written while loops

t is an array of points to function returning an int.


  while (c == getchar())
    putchar (c);

variables and scope

automatic variables aka the default variable scope

Most variables are local to the function that calls them. That is, any variables declared in a function die when the function exits. For example, the following function add, creates the variables a and b in the main function. BUT they disappear after the function ends.


  int
  add (int a, int b) {
    return a + b;
  }

  int
  main () {
    printf ("the sum is %s", add (3, 4));
    printf ("a is %s, b is %s", a, b); /* results in error,
                                          because main can't
                                          access a or b. */
    return 0;
  }

Static varibles

There are also static variables that are static, which keep their values each time they are called. If you are trying to write functional code, then only use these variables.


#include <stdio.h>
  int count () {
    static int b = 0;
    return b++;
  }

  int
  main () {
    printf ("b is %s\n", count());
    printf ("b is %s\n", count());
    printf ("b is %s\n", count());
    printf ("b is %s\n", count());
    return 0;
  }

The output of the above would be


"b is 1"
"b is 2"
"b is 3"
"b is 4"

external variables (global)

External variables are variables that are accessible to any function. They can be thought of as global variables, because any function has access to these global variables. Never use this functionality. This is NOT functional programming. Using global variables usually means that your program will have to run synchrously and not use any threads. It can also lead to some odd errors.


#include <stdio.h>

//this is an external variable.  It exists outside all the other functions that call it.
int count = 5;

int add (int a) {
  extern int count;
  return count + a;
}

int
main () {
  extern int count;
  printf ("count == %d\n", count);
  printf ("add (1) == %d \n", add(1));
}

types

char

a singly byte capable of holding 1 character. A character is any character in ASCII. It's the english alphabet plus some other characters like "@", "!", "#", "$", "%", etc.

#+BEGIN_SRC C /* Is the ASCII number representing x. char number = 'x'; is the char array "x\0" */ char x [] = "x"; #+END_SRC

int

A whole number that can be negative or positive. One can also use octal or hexidecimal to define a number #+BEGIN_SRC C int x = 31; /* the same value in octal int x = 037; int the same value in hexidecimal. */ int x = 0x1f; int x = 0X1F; #+END_SRC

float

double

const

  • short int
  • long int
  • unsigned int
  • This number is only positive.
  • signed int
  • This number is positive and negative. Dy default "int" is equivalent to "signed int". This means that the value will not change. #+BEGIN_SRC C /* this value cannot be changed. */ const int x = 6; #+END_SRC

I believe that this is a constant too.


#define NEWLINE '\n'

enum

The Enumeration constant is a list of constant integer values. It can often be used for boolean values:


enum boolean { NO, YES };

By default the first element in the list has a value of 0, the next 1, and so on.

You can enumerate the months like so,


enum months { JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };

printing arrays


printf ("%s", "Hello World\n");

Declarations

Hello World

A variable must be defined, before it can be used. The following two snippets are identical:


char my, how, why;
float a, x[1000];

char my;
char how;
char why;
float a;
float x[1000];

You can also declare variables with a value:


char a, b, c = 5;
int o, y, z = 8;

control flow

if, else if, else

switch

switch (expression) { case const-expr: statements case const-expr: statements default: statements }

The switch statement is a cool way have multiple if else statements in a better fashion.

I normally use it like so:


  switch (opt)
    {
      // if this parser function is called on an option that it doesn't recognize, then don't do anything.
    default:
      return ARGP_ERR_UNKNOWN;
    case 'j':
      {
        printf ("What do you call a box full of ducks?\n");
        printf ("A bunch of quackers.\n");
        break;
      }

    case 'm':
      {
        //some code
        break;
      }
    }

BUT there are cooler ways to use the switch statement!


  switch (digit) {
   case: 'A' case: 'B' case 'C':
     {
       //some code
     }

   case: 5 case: 7 case: 9
       {
         //some code
         break;
       }
   default:
     //some code
     break;
   }

for loops

initialize i to be equal to 0, while i is less than 5, do some code.


for (int i = 0; i < 5; i++) {
//code
}

cool libraries

ctype


isdigit ('c'); //returns false aka non-0.

tolower ('Y'); // returns y

toupper ('z');; // returns z

functions

functions may be defined within other functions

macros


#define max(A,B)  ((A) > (B) ? (A) : (B))

You can also undefine macros. You might do this to make sure that you are using a function and not a macro:


#undef max

max (a, b);

virtual memory and paging

A common method of managing memory is by using virtual memory. Virtual memory is memory that is mapped to physical memory, but usually there is more virtual memory than there is physical memory. A computer may have 5 GB of real memory, but 6 GB of virtual memory.

Virtual memory is split up into pages, which are normally 4KB each. A virtual memory page references a real memory page, which is called a frame. So frames are real memory and pages are virtual memory.

It's like a mormon marriage. You're supposed to have 1 wife, but the husband gets multiple women.

A process has a page associated with it, but sometimes memory is short and the process' page is not connected to a frame. When the process tries to use the virtual page, and the virtual page tries to access the frame, this is called a page fault. When this happens the kernel suspends the process and connects the page to a frame. Then the kernel starts the process again, and the process thinks that the page was connected to a frame.

argp (argument parsing)

It's actually possible to lock pages. Suppose you have a realtime application that cannot accept page faults, then you can lock that page. You could also do the same for security sensitive information. If a process has stored your password, you want that memory only in real memory. You never want it to get sent to swap... But locking pages can cause a performance penalty. If all programs lock pages, then no programs can run.

Many C command line programs accept arguments. Just type git --help in a command line to see what I mean. argp is GNU's standard for dealing with arguments passed to C programs. Most people will probably only need to call argp_parse in the main function to start using it.

It's a good idea to set some default variables:

creating argument parsers

const char * argp_program_version "VERSION_NUMBER";= =const char * argp_program_bug_address = "EMAIL_ADDRESS";=

An argument parser is a struct. You probably will need to define options, parser, args_doc, and doc.


struct argp argp;

options

The options is just a list of options that this program understands. Options can be -CHAR or -NAME.

-CHAR is of the form "-g" or "-h" or "-i".

-NAME is of the form "--get" or "--help" or "--i"

For example, one can create an arg_options struct like so:


  struct argp_option argp_options_joke;

Let's suppose you want to make an option that prints a silly joke. To make the long option be "--joke" you need:


  argp_options_joke.name = "joke";

To have the short option be "-j" :


  argp_options_joke.key  = 'j';

This field needs a name so that argp can associate the option with a parser.


  argp_options_joke.arg  = "joke";

And a doc string


  argp_options_joke.doc  = "Print a funny joke.";

You can also make the option NOT need an argument. For example the "--help" does not have an argument, but the "rm -r" does require an argument. In this case "rm -r" requires the file/directory to delete.


  argp_options_joke.flags = OPTION_ARG_OPTIONAL;  // this option does not need an argument.

Now you need to turn this option into an array that can be passed to your argp.options variable.

Notice that the "{ 0 }". struct argp_option options [2] needs to be a list with the last element in the list having 0 in all of its fields. "{ 0 }" is the C shortcut for that.


struct argp_option options [2] = { argp_options_joke, { 0 } };
argp.options = options.

args_doc

This is the usage string that you print when someone calls your program with PROGRAMNAME --help.


argp.args_doc = "argp [options]";

doc

This is the documentation paragraph that explains what your program does.


argp.doc = "Just a simple test argp program!";

argp parser functions

argp_parse parses the arguments via an argument parser. The argument parser could be a null pointer.

The easiest way to use argp to parse options is to use one function to parse all options. This function needs to look like this:

error_t PARSER (int KEY, char *ARG, struct argp_state *STATE)

The options field in a struct argp points to a function. Every time this parsing function is called, it parses a command line option. If the user typed in -j, then KEY equals 'j'. If the user typed in -g, then the key field equals 'k'. So you could implement a basic parser function to parse each argument based on what KEY equals. ie:


error_t
     parse_opt (int key, char *arg, struct argp_state *state)
     {
       switch (key)
         {
         case 'j':
           //some ACTION code here
           break;
         case 'g':
           //some different ACTION code here.
Daisy theme documentation: [[gnus:nnimap+imap.fastmail.com:INBOX#CAHD1g8WjE_jHcX211TYbjZvZWoZdcQF_+2u5s6yq+eaKoDE4XQ@mail.gmail.com][Email from Lindsay V.: Re: Doing some updates]]
           break;
         default:
           return ARGP_ERR_UNKNOWN;
         }
       return 0;
     }

writing a test to prove I know C

[2018-10-30 Tue] I took this test and got a 71%

what is the abort function?

:answer: It is a way to abnormally terminate a program.

It does not allow cleanup functions registered with atexit or on_exit.

This function actually terminates with the SIGABRT signal. My program can include a handler to intercept this signal. :END:

types

What's the differance between a double, float, short, int, long, char, etc.

Write some examples of floating numbers, etc.

ie: 9f

How do you write a long double constant? What letter to you put at the end of the number?

Write some hex numbers...

:ANSWER: #+HEADERS :includes #+BEGIN_SRC C int a = 500L;

How do you write a unsigned long constant? How do you postfix the number?

int b = 500l; #+END_SRC :END: :ANSWER: #+HEADERS :includes #+BEGIN_SRC C int a = 240UL;

What is wrong with this statement

int b = 212ul; #+END_SRC :END: #+HEADERS :includes #+BEGIN_SRC C short int a = 240UL; #+END_SRC

What is wrong with this statement

:ANSWER: The declaration (aka "short int a"), implies that a is a short integer. But the definition (240UL), implies that A is an unsigned long. The compiler will probably complain that our declaration and definition do not match. :END: #+HEADERS :includes #+BEGIN_SRC C short int a = 240f; #+END_SRC

Why does C include Hex and octal numbers? Why don't they just use decimal numbers?

:ANSWER: The declaration (aka "short int a"), implies that a is a short integer. But the definition (240f), implies that A is a floating integer. The compiler will probably complain that our declaration and definition do not match. :END:

Because computers only understand 1s and 0s. There is a conversion penalty every time the computer has to convert back and forth between binary numbers and decimal digits.

Using Hex numbers can be useful when printing pointer addresses. A program pointer points to a region of memory. Suppose that a pointer address is at the 10,995 byte. One can write this is binary like 0b0010101011110011 or in hex 0x2AF3

every 4 bits (a nibble), can be represented by one digit in Hex. This saves space.

I still don't know why pointer address's aren't just printed in decimal form though.

do some function pointers

When I read about string literals on page 194 of the C book, it implies that the below code should work...

#+HEADERS: :includes #+BEGIN_SRC C printf ("%s", 'a''b''c'); #+END_SRC

#+RESULTS:

Perhaps it was talking about this.

#+HEADERS: :includes #+BEGIN_SRC C printf ("%s", "abc" "defg" "hijk"); #+END_SRC

#+RESULTS:

abcdefghijk

#+HEADERS: :includes #+BEGIN_SRC C char * x = "abc"; char * y = "def"; char * z = "g"; printf ("%s", x y z); #+END_SRC

#+RESULTS:

if I add in "type.h", then it refuses to compile

:PROPERTIES: :ID: 9ac4e026-d625-43cc-acec-ba39de698537 :END:

why would you use the '#' in macro definitions?

why don't

I found these code snippets in the C coding book #+BEGIN_SRC C #define tempfile(dir) #dir "/%s"

#define cat(x,y) x ## y #+END_SRC

make some new types aka typedefs

:ANSWER: C does not allow one to extend the language by creating unique new definitions. Rather, it allows one to extend existing types: int, long, double, etc.

This is useful for aesthetic and portability reasons. Consider the following:

#+BEGIN_SRC C typedef struct complicatedStruct { char ** bread; int toppings [5]; double *weight; float *size; } burger;

// now we can create as many burgers as we want

burger quarterPounder, halfPound, heavyBurger;

#+END_SRC

This can be helpful for portability reasons as well. Consider a machine that does not have the "float" value. Then to port the program, all we need to change would be the various typedefs. Typedefs can also be useful with complicated structures and function pointers like my function pointer.c files shows.

create a function pointer tydedef

:END: :ANSWER:


typedef int (*functionPointer) (int *, int);

:END:

create a structure typedef


  typedef struct {
  char *word;
  char **string;
  char array [];
  } tnode;

what is a multibyte character?

what is a multibyte string?

:answer: A multibyte character is a character that takes more than 1 byte to encode. Unicode for example, uses numerous bytes to encode '✯' or 'ϖ' for example. :END:

:answer: This is a string that is composed of entirely multibyte strings. :END:

How do you create a string in C that can hold a unicode character?

:answer: L"✡" :END:

What is a wide string?

:answer: A wide string is a string that is composed of wchar_t objects. A wide string is usually declared like so: wchar_t * Also most unicode strings are going to be wide strings. :END:

What is the equivalent of EOF for wide strings?

:answer: 'WEOF' :END:

what is wrong with this program?

This program should not be executing! Malloc is not allocating enough memory to hold the string... #+HEADERS: :includes #+BEGIN_SRC C :results output const char * create_hello_string (const char * string) { char * local_string = (char *) malloc (sizeof (char)); strcpy (local_string, string); return local_string; }

int main () { char * hello_string = create_hello_string ("hello this string is long."); printf("%s\n", hello_string); return 0; } #+END_SRC

#+RESULTS:

hello this string is lon

what is the value of i here?

#+HEADERS: :includes #+BEGIN_SRC C if (1) { int i = 5; }

printf ("i is %d\n", i); #+END_SRC

#+RESULTS:

:answer: i is defined in the if statement scope. It is not defined in the print statement. :END:

How about here?

#+HEADERS: :includes #+BEGIN_SRC C for (int i = 0; i < 3; i++) ; printf ("i is %d\n", i); #+END_SRC

#+RESULTS:

:answer: 'i' is not defined. 'i' is defined inside the scope of the for block. Outside of that block, 'i' does not exist. :END:

This should cause errors but it does not!? Why!?

#+HEADERS: :includes #+BEGIN_SRC C :results output char * copy_string (char * to, char * from) { while (*to++ = *from++) ; }

int main () { char hello [1]; hello [0] = 'h'; hello [1] = 'e'; hello [2] = 'l'; hello [3] = 'l'; hello [4] = 'o'; hello [1000] = '8'; //copy_string (hello, "hello"); printf ("hello[] is %s\n", hello); putchar (hello [1000]); putchar (hello [1001]); return 0; } #+END_SRC

#+RESULTS:

hello[] is hello
8

what does "const" in this function declaration mean?

#+BEGIN_SRC C int strlen (const char[]); #+END_SRC

:answer: This means that the function strlen, will not modify the string that is passed to it. :END:

vocab

what's the stack?

what's the heap?

The stack is what you get your automatic variables. AKA variable that you don't have to allocate space for via malloc.

what's the difference between the stack and the heap

The heap contains all of the variables you have got via malloc calls.

The stack is automatic variables, but the heap is global variables...

The heap are variables that you get via calls to malloc.

difference between a union and a struct

The stack are variables you don't have have to use malloc, aka normal or automatic variables.

what's a declaration and a definition and an assignment?

:ANSWER: Both a union and a struct are an easy way of collecting variables under one variable name. The difference is a struct's collection can define all values simultaneously. A union's collection is only allowed to define one variable at a time. :END:

:ANSWER: A declaration is a promise to the compiler that a function or variable exists.

A definition is the section of code that allocates a region of memory for the variable or function.

#+BEGIN_SRC C #include int a; // declaration int add (int a, int b);

int main () { a = 5; //this is the assignment statement int b = 10; //I am also an assignment statement

int c = add (a, b); printf("%d\n", c); return 0; }

//definition int add (int a, int b) { return a + b; } #+END_SRC

#+RESULTS:

15

what's a segmentation fault

:END: :ANSWER: Your program tried to access memory to which it did not have access. :END:

what are the 4 common types of segmentation faults otherwise known as segfaults?

# retrieved from https://www.cprogramming.com/debugging/segfaults.html

    :ANSWER: There are four common mistakes that lead to segmentation faults:
  • dereferencing NULL
  • dereferencing an uninitialized pointer
  • dereferencing a pointer that has been freed (or deleted, in C++)
  • or that has gone out of scope (in the case of arrays declared in functions)
  • writing off the end of an array.
  • :END:

what's a stack overflow?

:ANSWER: Your recursive function used up all of the stack space. You have no more memory to continue recursing. :END:

parameter

:ANSWER: The parameters are the local variables that are shown in the function definition. :END:

argument

:ANSWER: An argument is the value that is passed to the function. :END:

what is a statement?

Functions are made up of statements, which specify computing operations to be done. Statements are usually one line long and end in ";".

demonstrate proficiency in multidemensional arrays

argp

what is the /etc/nsswitch.conf file?

:answer: It is a place to store various information about the system so that applications work smoothly together.

/etc/hostname stores the computer's hostname. That's how the C library and everything else know the computer's hostname.

/etc/nsswitch.conf configures other things. :END:

what are some things you could put in the /etc/nsswitch.conf file?

    :answer:
  • email aliases
  • passwords
  • public keys
  • groups of users
  • etc.
  • :END:

threading

what's the differance between malloc and alloc?

:answer: malloc lets you explicitly allocate memory, and you are responsible for destroying that memory.

With alloc you can get memory for yourself, and when you leave the function that alloc is called from, the memory is freed automatically! So it's really easy to use, and maybe better! :END:

multi-processing

do some of the coding challenges provides in my C book

what's the differance between a pipe and a FIFO?

A pipe has no name. Only the parent and it's children can communicate with the pipe.

learn valgrind

A FIFO is a communication that names a name. Anyone can open it and communicate to it. http://valgrind.org/docs/manual/quick-start.html#quick-start.mcrun

If run your program with arguments like: main arg1 arg2,

Then you can run valgrind to test for memory errors like this:

valgrind --leak-check=yes myprog arg1 arg2

learn complicated declarations

memcheck is the default tool. --leak-check=yes turns on the detailed memory checker.

They are read right to left.

learn programs that tell you how fast your C code is.

what are signals?

What does it mean when a program is given an error signal from the OS?

:answer: Signals are ways for your programs to declare certain events to have happened. :END: :answer: This generally means that the program must stop executing. Some massive problem has broken significant program logic, exposed a security vulnerability, etc. Programs can at this time write a core dump file and then return control to the OS to end the program. This dump file is useful for investigating what caused the crash. :END:

how does a C compiler work? initialization

recursion

type conversion

Suppose you wish to add an int and a float. C does a conversion for you. Generally, the automatic conversions convert a small type to a larger type, so you won't lose information. IE: C will convert an int into a float to add an int and a float.


    int i = 2;
    float f = 3.0;

    printf("%f\n", i + f);
5.0

how to code functionally in C?

#include vs. #include "filename"?

:ANSWER: =#include = is for standard libraries.

#include "filename" is for libraries that I write. :END:

make a multi-filed C program

make a portable C program

learn autotools

learn macros

learn glibc macros

conditional inclusion:

#+BEGIN_SRC C #if !defined (HDR) #if SYSTEM == BSD #define HDR "bsd.h" #elif SYSTEM == LINUX #define HDR == "linux.h" #else #define HDR "msdos.h" #endif

learn printf

#include HDR #+END_SRC

#+HEADERS: :includes #+BEGIN_SRC C float f = 39403.29304; printf ("%%f %f\n", f); printf ("%%2f %2f\n", f); printf ("%%2.0f %2.0f\n", f); printf ("%%100.100f %100.100f\n", f); #+END_SRC

#+RESULTS: | %f | 39403.292969 | | %2f | 39403.292969 | | %2.0f | 39403 | | %100.100f | 39403.29296875 |

:ANSWER: %d is for decimal %6d is a decimal integer at least 6 characters wide %f floating point %6f is a floating point at least 6 characters wide %.2f print as a floating point and add two characters after the decimal point %6.2f print as a floating point. Print 6 characters before the decimal and 2 after %o is for octal %x for hexadecimal %c for character %% is for the "%" character. :END:

file descriptors

Convert these mathematical statements to C statements

specific questions

How many bytes does the following string array need?

  • (3 / (2 * 4 ^ 9)) - 23 * (4 - 3)
  • π / 23 * (4 / 23)
  • ℇ * 33 (that is Euler's constant)

"Hello\n"

:ANSWER:

What is a global variable in C called? And how would you declare "int n;" to be global?

byte
H e l l o \n \0
END

:ANSWER: external


extern int n;

How would you define an extern variable inside the function main?

:END:

:ANSWER: You can't.

External variables must be declared outside any function, and they must be declared inside any function that wants to use them.

You can do this though:


  #include <stdio.h>
  int n;

  int main () {
    extern int n;
    n = 10;

    return n;
  }

what's the difference between these definitions/definitions 'char string [] = "hello";' 'char * string = "hello";'

:END:

:ANSWER: This is a string array.


char string [] = "hello";
printf("%s\n", string);
hello

It is stored in continuous, read/write region of memory like this:

h e l l o \0

I am allowed to alter any character in the string. So


char string[] = "hello";
string[2] = 'w';
printf ("%s\n", string);
hewlo

This is a string literal


char * string = "hello";

It is stored in a continuous, readonly section of memory like this:

hello\0

So trying to modify the string results in an error


//char * string = "hello";
string[2] = 'w';
printf ("%s\n", string);

What is the function to break a string into tokens?

:END:

:answer: strtok :END:

Describe C's presidence rules...

:ANSWER: Highest presidence to lowest. The arithmatic rules are PEMDAS. So C does not need parenthesis when evaluating basic arithmetic.

what's the difference between a void function and a static void function?

    ,* /
  • -
  • > >= < <= ,== != && || :END:

what's MT-safe, AS-safe, and AC-safe mean?

A void function, can be called by any bit of code in your project. A static void function, can only be used in the source code file it is in. This is useful for large projects. Many drivers in the linux kernel are named static void, so that they do not conflict with any other functions in the linux kernel.

:answer: In POSIX safety terms these refer to if it is safe to call various functions.

What is the difference between 'a' and "a"?

MT-safe means that it is safe to call this function inside a thread. This does not mean that the function is atomic. :END:

:answer: 'a' is a character. "a" is a string. "a" is internally represented as {'a','\0'}. :END:

which hurd library is great to develop virtual directory structures like /proc?

:answer: libnetfs

what is the following output of this C program

This is the library that NFS is built on. :END:


#include <stdio.h>

int main () {
   int *p = 15;
   printf("%d",*p);
   return 0;
}

What is the output of these lines of code?

:answer: A runtime error. The pointer is not pointing to a proper location in memory. Trying to read from an undefined point in memory, will cause a segmentation fault. :END:

#+HEADERS: :includes #+BEGIN_SRC C printf ("%d\n", 5/9); printf ("%d\n", 5.0/9.0); printf ("%f\n", 5.0/9.0); #+END_SRC

:answer: #+RESULTS: | 0 | | 4202507 | | 0.555556 | :END:

Why do they have different output?

:answer: The integers 5 and 9 are integers. However 5.0 and 9.0 are considered floating point numbers. Floating point numbers may have information after the decimal point. :END:

I/O

Input is reading data. Output is writing data. Glibc provides several functions for doing both!

I can read/write to a file by using a stream or a file descriptor. The stream is supposed to be easier to use. The file descriptor method is very low level, and streams are built a-top it. Streams allow 3 different types of buffering.

Streams allow for getting in character by character, or by line by line.

Apparently I should focus on formatted input and formatted output programs...

I will also have file positions. Whenever I am reading a file, some integer keeps track of where I am in the file. If I read a byte forward, then that integer increases by 1.

Streams use file pointers. This is stuff in stdio.h. I can check to see if I have found the end of the file by calling:

int feof (FILE * STREAM) it returns non-0 if the end of file is found.

When I call my main function, three streams are defined: stdin, stdout, and stderr. cool eh?

I can even re-direct stderr to a file:


  fclose (stdout);
  stdout = fopen ("standard-output-file", "w");

streams

Open a stream

file * fopen (const char * FILE, const char * OPENTYPE)

Opentype can be: "r", "w", "a", "r+", "w+", "a+", "m".

"r" is just for reading a file.

"w" is just for writing a file and the previous file contents are discarded.

"a" is for appending at the end of the file.

"r+" is for reading and writing to a file. This is probably the most useful.

fclose closes the file stream.

putc and fputc

"m" is for opening files via mmap. It is only used for reading. This is the function that the Hurd hello program uses. int fclose (FILE * stream)

These are how to write one character. Pretty easy.

puts and fputs

put c (int C, FILE * STREAM)

This writes a string to a FILE *.

fgetc or getc

puts (const char S, FILE STREAM)

moving the position of the file pointer

These functions get one character from a stream. It's normally best to use getc, because it's faster.

fseek (FILE * STREAM, long int OFFSET, int WHENCE)

perror

pattern matching via regexp

WHENCE can be SEEK_SET, SEEK_CUR, SEEK_END to indicate if the offset is the relative to current file pointer position, the end of the file, or the beginning of the file. is a function that lets you write an error message to the stderr stream. info:libc#Regular Expressions

This is all stored in regex.h

One first needs to compile a regexp via regcomp (), then one needs to search for matches via regexec (). Regexec will store the matches in an array that you pass into it.

compiled regular expressions are stored in the data structure regex_t. Every regex_t has one field that I need: a re_nsub, which holds the compiled regular expressions.

The array has elements of type regmatch_t. It has two fields:

  • rm_so the offset from the beginning of the string. Add the pointer to the string + rm_so to get the match.
  • rm_eo the offset from the end of the string.

After you have found your matches, be sure to free up the space your compiled regex was using via regfree


regfree (regex);

troubleshooting

grep shows the proper matches in the white-space.txt file:


grep -E '[^ ] +$' white-space.txt
This line has extra white space
this one does bro
This line definitely has some white space.

searching and strings

BUT this regex doesn't match when I use the C version. But it does match when I remove the "$".

#+HEADERS: :includes #+BEGIN_SRC C char hello [32] = "Hello World!"; char * string; string = memchr (hello, '!', strlen(hello)); printf ("%s\n", string); #+END_SRC

#+RESULTS:

How do you search trees?

!

:answer: tsearch :END:

watch some C videos

data types

char

int

float single precision floating point

double double precision floating point

qualifiers

https://www.youtube.com/user/jstrosch/videos?sort=dd&view=0&shelf_id=1 These data types do have some qualifiers that can be applied to them.


short int n;
long int m;

The above is the same as:


short n;
long m;

You can think of this like sql data types. a short may have a value between -128-127. "int" is no smaller than a short, and no larger than a long. The compiler is free to determine these sizes, based on the hardware.

unsigned or signed may be used for chars and any integer. An unsigned variable's value can never be negative. A signed variable's value can be negative or positive.


signed int n;
unsigned char c;
signed float f;
long unsigned double d;

The qualifier long applied to a double means to make the variable extra precise.

I can specify that a value in C will not change. If this value is changed, the program will probably abort.


const int n = 5;

Writing in hexadecimal or octal or scientific notation

Writing a number is scientific notation


int n = 101e2;
printf ("%d\n", n);
10100

float f = 1.01e2;
printf ("%f\n", f);

writing in binary this is a GNU extension

101.0

int n = 0b11;
printf ("%d\n", n);
3

structs

A struct is a collection of data grouped under one variable name. This is convenient for large programs with lots of data. Consider a registration program that is responsible for registering many users. Each user has a name, address, phone number, etc. A convenient method for handling this kind of problem is to use a struct.


  struct human {
    char * phone_number;
    char * name;
    char * address;
  };

Then to declare variables of this type one would do the following:


struct human phil, john, james;

Now we have three variables "phil", "john", and "james". We could now start filling in their information:


phil.name = "Phil";
john.name = "John";
james.name = "James";

We could also do all of the above like this:


  struct {
    char * name;
    char * phone_number;
    char * address;
  } james, john, phil;

  phil.name = "Phil";
  john.name = "John";
  james.name = "James";

But it's more convenient to give the struct a tag. The tag in this case is "human".

Probably the easier way to do all of the above is to do the following:


  struct human {
    char * name;
    char * phone_number;
    char * address;
  };

  struct human james =  { "James" , "7652834019", "1128 Liby Way New York"   };
  struct human john  =  { "James" , "7642824513", "1128 Liby Way New Jersey" };
  struct human phil  =  { "Phil"  , "7652434074", "1128 Liby Way New York"   };

An even easier way would probably be to use a typedef.


  typedef struct shuman {
    char * name;
    char * phone_number;
    char * address;
  } human_t;  //the "_t" is a hint that this is a typedef

  human james =  { "James" , "7652834019", "1128 Liby Way New York"   };
  human john  =  { "James" , "7642824513", "1128 Liby Way New Jersey" };
  human phil  =  { "Phil"  , "7652434074", "1128 Liby Way New York"   };

Here's we've created a structure, and we have given it the typedef "human". Now we can use this as a way to create new struct "shuman".

nested structures

C coding projects

writing a basic html parser with the goal of minimizing html files

We can also nest structures. Suppose we wanted to create a structure that is a family! We can do that pretty easily too!

The way I had thought about doing it at first was to use the libc function strtok, which takes a string, and returns many substrings based on a set of string of characters.

In other words, strtok removes special characters and only returns the strings between those special characters.

So if the string is " and ", and the delimiters are "<" and ">", then multiple calls to strtok returns

strtok () --> Hello strtok () --> and strtok () --> Hello

This method worked when I was testing my logic. Instead of specifying an html file, I hardcoded an html string in the file:

#+BEGIN_SRC C const char * string = "real simple"; #+END_SRC

BUT now that I want to parse an html file, I may have found a better function: getdelim. getdelim let you read a token from a file. So I probably won't have to use strtok anymore! I can just read the file via getdelim and specify that "<>" are my delimiters. The only problem is the getdelim is get delimiter not get "delimeters". So getdelimiter only supports setting a char delimeter. Not a string of delimeters.

I have three possible solutions:

    I could ask online...
  • I could write a getdelimeters function...
  • search based (lots of back and forth of the file)...
  • two different streams for the same file ()
  • pass over the file with getdelim once with "<", then pass over the file with ">"
  • I could use two loops. The first loop, uses getdelim "<" and the inner loop uses getdelim ">".
  • parse the whole file into a string, and then use
  • strtok. https://stackoverflow.com/questions/174531/easiest-way-to-get-files-contents-in-c
  • memory map the file into memory via mmap

The main problem with this technique is that the function has a hard time processing elements with contents.

ie:

Hello World

In the nested while loop, getdelim("<") will return the opening p element, but may forget about the p's content. I could use static variables to get around this.

#+HEADERS: :includes #+BEGIN_SRC C :dir ~/programming/c/ FILE * file = fopen ("simple.html", "r"); char ** token;

const char * getdelimeters (FILE * file, char ** token) { while ((token = getdelim (token, 128, "<", file)) != NULL) { //if token does not contain ">" return token; while ((token = getdelim (token, 128, ">", file)) != NULL) { //I'll use a static variable here to store the content... return token; } } return NULL; }

while ((token = getdelimeters (file, token)) != NULL) { printf ("Hello%s\n", token); }

fclose (file); //getdelim (char ** lineptr, size_t n, int delimiter, FILE stream);

#+END_SRC

#+RESULTS:

write dummy C compiler that looks for simple problems in C files. ATTACH

  • I could use a combo of strtok and getline
  • copy each line into a const char * and pass it to strtok
  • :PROPERTIES: :ID: 0c70de7f-6ab0-45d2-8353-1366680f4cf3 :END:

The reference in the back of the C book has some tips about how I can compile C.

needed datastructes:

groups of code

expression
comparison

An expression is what is contained inside of parenthesis (also can be found inside a printf statement). Can be of a few types #+BEGIN_SRC C if (1 < 5) ; else if (3 == 3) ; else if (2 != 6 ) ; #+END_SRC

#+RESULTS:

assignment
arithmetic

#+BEGIN_SRC C if (x = 1) ; else if (z = 3 != EOF) ; else if (2 + 6 == 8) ; #+END_SRC

function call

#+BEGIN_SRC C if (x + 1) ; else if (z = 1) ; else if (y+) ; #+END_SRC

statement
block (aka a compound statement)

#+BEGIN_SRC C if (isdigit (1)) ; else if (isupper('a')) ; else if (islower ('b')) ; #+END_SRC A statement is any bit of code that ends in a semicolon. These are all statements. #+BEGIN_SRC C int x = 5; x++; int b = x - 2; int c = x % b; #+END_SRC

Any region of code that is contained between two braces {}, is considered a compound statement or a block. C considers a block and a statement as syntactically equivalent. The braces around the main function is one block. An if else statement contains two or more blocks.

struct function

return_type
name
struct argument
type
name

struct data type

char
int
float
double

symbolic constants

const bool

register bool

array escape sequences

array keywords

array operators p. 53

should also include order of operations

array types

#+BEGIN_SRC C if (1) { //first block } else if (2) { //second block } else { //third block } #+END_SRC #+BEGIN_SRC C #define name replacement text #+END_SRC |----+-----------------+------+--------------------| | \a | alert bell | \\ | backslash | | \b | backspace | \? | question mark | | \f | formfeed | \' | single quote | | \n | newline | \" | double quote | | \r | carriage return | \ooo | octal number | | \v | vertical tab | \xhh | hexadecimal number | |----+-----------------+------+--------------------| |----------+--------+----------+----------| | auto | double | int | struct | | break | else | long | switch | | case | enum | register | typedef | | char | extern | return | union | | const | float | short | unsigned | | continue | for | signed | void | | default | goto | sizeof | volatile | | do | if | static | while | |----------+--------+----------+----------|

array type qualifiers

|--------+---------| | void | char | | short | int | | long | float | | double | signed | | struct | union | | enum | typedef | |--------+---------|

|----------+----------| | register | volatile | |----------+----------|

array storage class specifiers

| auto | register | | static | extern | | typedef | |

struct statement

struct declaration

struct definiton

scanf printf, fprintf special

what std libs provide which functions

stdio.h
printf
fprintf
getchar
putchar
stdlib.h
malloc
ctype
isupper
islower
isdigit
isalpha
assert.h
assert
errno.h
program_name
program_short name
argp.h

loops

do while
for
while

conditional expressions

if
switch
?

preprocessing things that I can do before parsing

replace '\''\n' with ''

the whole file is split into tokens that are each separated by a white space

comments are replaced by a single space

macros are expanded

copying SIZE bytes from one array to another

#+HEADERS: :includes #+BEGIN_SRC C :dir ~/programming/c/

char string [16] = "hello World\0"; char other_string [16];

memcpy (other_string, string, 7);

fwrite (other_string, 1, 7, stdout);

#+END_SRC

#+RESULTS:

more ways to learn C

The 5 things I could try to learn C faster

hello W

man pages provide C code examples! Check out "man getdelim"

learning how to code https://www.cprogramming.com/how_to_learn_to_program.html

c reference library http://en.cppreference.com/w/

c function reference https://www.cprogramming.com/function.html

c understanding compiler errors https://www.cprogramming.com/tutorial/compiler_linker_errors.html

learning how to debug C code https://www.cprogramming.com/debugging/segfaults.html

C programming forum https://cboard.cprogramming.com/cplusplus-programming/69086-parsing-html-files.html

simple C programs

creating a simple C program and deleting crucial bits to see what the compiler says

https://www.cprogramming.com/how_to_learn_to_program.html

#+HEADERS :includes #+BEGIN_SRC C int main () { printf ("Hello World\n"); return 0; } #+END_SRC

#+RESULTS:

Hello World

#+HEADERS :includes #+BEGIN_SRC C printf ("Hello World\n") #+END_SRC

#+RESULTS:

#+BEGIN_SRC C #include

main () { printf ("Hello World\n"); } #+END_SRC

#+RESULTS:

#+BEGIN_SRC C #include

int main () { printf ("Hello World\n"); } #+END_SRC

#+RESULTS:

Hello World

#+BEGIN_SRC C #include

void main () { printf ("Hello World\n"); } #+END_SRC

#+RESULTS:

#+BEGIN_SRC C include

int main () { printf ("hello World\n"); return 0; } #+END_SRC

#+RESULTS:

#+BEGIN_SRC C #include

int main () { printf ("hello World\n"); return 0; } #+END_SRC

#+RESULTS:

#+BEGIN_SRC C #include

int main () { printf ("hello \e \a \f \< \( < \@ \5 World\n"); return 0; } #+END_SRC

#+RESULTS:

a function that reverses a string

hello    < ( < @  World

#+HEADERS: :includes #+BEGIN_SRC C char * reverse (char * to, char * from) { int i, j; for (j = 0, i = strlen (from) - 1; (*(to + j) = *(from + i)) && i > 0; i--, j++) ; }

int main () { char * str = (char *) malloc (sizeof("hello")); reverse (str, "hello"); printf ("%s\n", str); putchar (*(str + 10)); //why does this not cause an error? return 0; } #+END_SRC

strlen

#+RESULTS: | olleh | | |

#+HEADERS: :includes #+BEGIN_SRC C printf ("strlen is %d\n", strlen("ab")); #+END_SRC

#+RESULTS:

subtracting 'char's

strlen is 2

#+HEADERS: :includes #+BEGIN_SRC C printf ("'c' - 'a' = %d\n", 'c' - 'a'); #+END_SRC

#+RESULTS:

'c' - 'a' = 2

outputting an ASCII chart

#+BEGIN_SRC C #include

int main() { char a [] = "abcdefghijklmnopqrstuvwxyz"; char A [] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

for (int i = 0; i < 26; i++) { printf ("%c %d %c %d %d %d\n", a[i], a[i], A[i], A[i], i < 10 ? i : 0, i < 10 ? (int) (i+48) : ' '); } return 0; }

#+END_SRC

#+RESULTS: | a | 97 | A | 65 | 0 | 48 | | 48 | 49 | | | | | | b | 98 | B | 66 | 1 | 49 | | 48 | 49 | | | | | | c | 99 | C | 67 | 2 | 50 | | 48 | 49 | | | | | | d | 100 | D | 68 | 3 | 51 | | 48 | 49 | | | | | | e | 101 | E | 69 | 4 | 52 | | 48 | 49 | | | | | | f | 102 | F | 70 | 5 | 53 | | 48 | 49 | | | | | | g | 103 | G | 71 | 6 | 54 | | 48 | 49 | | | | | | h | 104 | H | 72 | 7 | 55 | | 48 | 49 | | | | | | i | 105 | I | 73 | 8 | 56 | | 48 | 49 | | | | | | j | 106 | J | 74 | 9 | 57 | | 48 | 49 | | | | | | k | 107 | K | 75 | 0 | 32 | | 48 | 49 | | | | | | l | 108 | L | 76 | 0 | 32 | | 48 | 49 | | | | | | m | 109 | M | 77 | 0 | 32 | | 48 | 49 | | | | | | n | 110 | N | 78 | 0 | 32 | | 48 | 49 | | | | | | o | 111 | O | 79 | 0 | 32 | | 48 | 49 | | | | | | p | 112 | P | 80 | 0 | 32 | | 48 | 49 | | | | | | q | 113 | Q | 81 | 0 | 32 | | 48 | 49 | | | | | | r | 114 | R | 82 | 0 | 32 | | 48 | 49 | | | | | | s | 115 | S | 83 | 0 | 32 | | 48 | 49 | | | | | | t | 116 | T | 84 | 0 | 32 | | 48 | 49 | | | | | | u | 117 | U | 85 | 0 | 32 | | 48 | 49 | | | | | | v | 118 | V | 86 | 0 | 32 | | 48 | 49 | | | | | | w | 119 | W | 87 | 0 | 32 | | 48 | 49 | | | | | | x | 120 | X | 88 | 0 | 32 | | 48 | 49 | | | | | | y | 121 | Y | 89 | 0 | 32 | | 48 | 49 | | | | | | z | 122 | Z | 90 | 0 | 32 | | 48 | 49 | | | | |

#+HEADERS: :include #+BEGIN_SRC C #include

int main () { printf ("%d", (26 % 26)); return 0; } #+END_SRC

#+RESULTS:

expand string

0

This simple function will try to expand strings like "a-d" into "abcd". Eventually try to handle "0-9" and even "a-z0-9"

!*p is how you can test if your pointer currently points at the '\0' character. #+HEADERS: :includes #+BEGIN_SRC C // sequence_t will store the information from an encoded string the // encoded strings looks like "[a-zA-Z0-9]-[a-zA-Z0-9]". So an // encoded string of "a-z", represents the whole alphabet.

A struct of //sequence_t = {beginning_char = 'a', end_char = 'z', next = sequence_t { beginning_char = '0', end_char = '9', next = 0 }} // represents a string that contains the alphabet followed by the // numbers 1-9. The original string would have been "a-z0-9". struct sequence_t { char beginning_char, end_char; unsigned int sequence_length; struct sequence_t *next; };

struct sequence_t * allocate_sequence () { struct sequence_t * sequence = (struct sequence_t *) malloc (sizeof (struct sequence_t)); return sequence; }

struct sequence_t * parse_string (char * str) { struct sequence_t * sequence = allocate_sequence(); sequence->beginning_char = *str; sequence->end_char = *(str + 2); }

    char * expand (char * input_string) { struct sequence_t * sequence = parse_string (input_string); char * loop_str; char * temp_str; char * return_string = 0; while (!sequence->next) { loop_str = (char *) malloc (sizeof (char) * 32); int i = 0; // for (char c = sequence->beginning_char; c <= sequence->end_char; c++, i++) ,*(loop_str + i) = c; ,*(loop_str + i) = '\0'; if (!return_string) return_string = loop_str; else { return_string = (char *) realloc (return_string, (sizeof (char) * strlen (return_string)
  • (sizeof (char) * 32)));
  • strcpy ((return_string + strlen (return_string)), loop_str); } } return return_string; }

int main () { char * string = expand ("a-z"); printf ("%s\n", string); return 0; } #+END_SRC

#+RESULTS:

temperature

temperature printing and integer truncating

#+HEADERS: :includes #+BEGIN_SRC C int main () { int fahr, celsius; int lower, upper, step;

lower = 0; * lower limit of temperature table upper = 300; upper limit step = 20; step size *

fahr = lower; printf ("Fahrenheit Celsius\n"); while (fahr <= upper) { celsius = 5 * (fahr - 30) / 9; celsius = (fahr - 30) * (5/9); //this is wrong //in C integer division, truncates any remainder aka 5 / 9 = .55555, but in C 5/9 == 0 printf ("%d %d\n", fahr, celsius); fahr = fahr + step; } return 0; } #+END_SRC

temperature conversion more accurate

#+RESULTS: | Fahrenheit | Celsius | | 0 | -16 | | 20 | -5 | | 40 | 5 | | 60 | 16 | | 80 | 27 | | 100 | 38 | | 120 | 50 | | 140 | 61 | | 160 | 72 | | 180 | 83 | | 200 | 94 | | 220 | 105 | | 240 | 116 | | 260 | 127 | | 280 | 138 | | 300 | 150 |



  int main ()
  {
    float fahr, celsius;
    int lower, upper, step;

    lower = 0;
    upper = 300;
    step = 10;

    fahr = lower;
    printf ("Fahrenheit Celsius\n");
    while (fahr <= upper)
      {
        /* 5.0 / 9.0 is not truncated to 0, because 5.0 is a floating number not an int */
        celsius = (5.0 / 9.0) * (fahr - 32.0);
        /* 3.0, means print at least 3 characters wide with no decimal digit */
        /* 6.1 means print at least 8 characters wide with 3 decimal digits */
        printf ("%3.0f %8.3f\n", fahr, celsius);
        fahr = fahr + step;
      }
    return 0;
  }

temperature conversion more accurate celsius --> fahrenheit

Fahrenheit Celsius
0 -17.778
10 -12.222
20 -6.667
30 -1.111
40 4.444
50 10.0
60 15.556
70 21.111
80 26.667
90 32.222
100 37.778
110 43.333
120 48.889
130 54.444
140 60.0
150 65.556
160 71.111
170 76.667
180 82.222
190 87.778
200 93.333
210 98.889
220 104.444
230 110.0
240 115.556
250 121.111
260 126.667
270 132.222
280 137.778
290 143.333
300 148.889


  int main ()
  {
    float fahr, celsius;
    int lower, upper, step;

    lower = 0;
    upper = 300;
    step = 10;

    celsius = lower;
    printf ("Celsius Fahrenheit\n");
    while (celsius <= upper)
      {
        /* 5.0 / 9.0 is not truncated to 0, because 5.0 is a floating number not an int */
        fahr = (5.0 / 9.0) * celsius + 32;
        /* 3.0, means print at least 3 characters wide with no decimal digit */
        /* 6.1 means print at least 8 characters wide with 3 decimal digits */
        printf ("%3.0f %5.1f\n", celsius, fahr);
        celsius = celsius + step;
      }
    return 0;
  }

temperature via for loop

Celsius Fahrenheit
0 32.0
10 37.6
20 43.1
30 48.7
40 54.2
50 59.8
60 65.3
70 70.9
80 76.4
90 82.0
100 87.6
110 93.1
120 98.7
130 104.2
140 109.8
150 115.3
160 120.9
170 126.4
180 132.0
190 137.6
200 143.1
210 148.7
220 154.2
230 159.8
240 165.3
250 170.9
260 176.4
270 182.0
280 187.6
290 193.1
300 198.7

  #include <stdio.h>

  int main ()
  {
    int fahr;

    for (fahr = 0; fahr <= 300; fahr = fahr + 20)
      {
        printf ("%d %6.1f\n", fahr, (5.0/9.0) * (fahr - 32));
      }
    return 0;
  }

temperature via for loop with constants

0 -17.8
20 -6.7
40 4.4
60 15.6
80 26.7
100 37.8
120 48.9
140 60.0
160 71.1
180 82.2
200 93.3
220 104.4
240 115.6
260 126.7
280 137.8
300 148.9

  #include <stdio.h>

  #define LOWER 0
  #define UPPER 300
  #define STEP 20

  int main ()
  {
    int fahr;

    for (fahr = LOWER; fahr <= UPPER; fahr = fahr + STEP)
      {
        printf ("%d %6.1f\n", fahr, (5.0/9.0) * (fahr - 32));
      }
    return 0;
  }

printing chars

what's wrong with this code?

0 -17.8
20 -6.7
40 4.4
60 15.6
80 26.7
100 37.8
120 48.9
140 60.0
160 71.1
180 82.2
200 93.3
220 104.4
240 115.6
260 126.7
280 137.8
300 148.9

A program that outputs it's input



  char c;

  c = getchar ();
  while (c != EOF)
    {
      putchar (c);
      c = getchar ();
    }

simpler version

char c; That's the problem. char c can only hold 128 characters. It is not large enough to hold the EOF character. So c must be declared in int.


  #include <stdio.h>

  int main ()
  {
    int c;

    while ((c = getchar()) != EOF)
      putchar (c);

    return 0;
  }

program to print value of EOF


  #include <stdio.h>

  int main ()
  {
    printf("%d\n", EOF);
    return 0;
  }

counting lines

-1

  #include <stdio.h>

  int main ()
  {

    char string [16] = "silly.txt";

    FILE * stream = fopen (string, "r");

    int c, nl;

    nl = 0;

    while ((c = fgetc(stream)) != EOF)
      if (c == '\n')
        ++nl;

    printf ("number of lines in %s is %d\n", string, nl);

    return 0;
  }

counting lines, blanks, tabs

number of lines in silly.txt is 9

  #include <stdio.h>

  int main ()
  {

    char string [16] = "silly.txt";

    FILE * stream = fopen (string, "r");

    int c, nl, tabs, blanks = 0;

    while ((c = fgetc(stream)) != EOF)
      switch (c)
        {
        case '\n':
          ++nl;
          break;

        case '\t':
          ++tabs;
          break;

        case ' ':
          ++blanks;
          break;
        }
    printf ("number of lines in %s is %d\n", string, nl);
    printf ("number of blanks in %s is %d\n", string, blanks);
    printf ("number of tabs in %s is %d\n", string, tabs);

    return 0;
  }

counting words and characters there's something wrong here

number of lines in silly.txt is 9
number of blanks in silly.txt is 16
number of tabs in silly.txt is 0

   #include <stdio.h>

   #define IN  1
   #define OUT 0

   int main ()
   {

     char string [16] = "silly.txt";

     FILE * stream = fopen (string, "r");

     int c, nc, nl, nw, state = 0;

     while ((c = fgetc (stream)) != EOF)
       {
         ++nc;
         if (c == '\n')
           ++nl;

         if (c == '\n' || c == ' ' || c == '\t')
           state = OUT;
         else
           {
             if (state == OUT)
               state = IN;
             ++nw;
           }
       }

     printf ("%s has %d lines, %d words, and %d characters\n", string, nl, nw, nc);

     return 0;
   }
silly.txt has 9 lines 32934 words and 193 characters


    char string [16] = "silly.txt";

    FILE * stream = fopen (string, "r");

    int c, nc, nl, nw, state = 0;

    while ((c = fgetc (stream)) != EOF)
      {
        if (c == ' ')
          {
            state = OUT;
            printf("\n");
          }
        else
          {
            if (state == OUT)
              state = IN;
            fputc (c, stdout);
            state = IN;
            ++nw;
          }
      }
#+AUTHOR:Joshua
Branson
#+TITLE:
#+LATEX_HEADER:
\usepackage{lmodern}
#+LATEX_HEADER:
\usepackage[QX]{fontenc}
#+OPTIONS:
H:10
toc:nil
*
This
is
a
silly
Text
File
I'm
using
it
to
count
lines
to
to
to

  #include <stdio.h>

  #define IN  1
  #define OUT 0
  #define MAX_WORD_LENGTH  32

  int main ()
  {

    char string [16] = "silly.txt";
    /* word_length[5] = 7, means that there were 7 words of length 5; */
    int word_lengths [MAX_WORD_LENGTH];

    /* initialize word_lengths to 0 */
    for (int i = 0; i < MAX_WORD_LENGTH; i++)
      word_lengths[i] = 0;


    FILE * stream = fopen (string, "r");

    /* nw == new word */
    /* wl == word length */
    int c, nw, wl, state = 0;

    while ((c = fgetc (stream)) != EOF)
      {
        /* if this is NOT a word, state is now OUT of word */
        if (c == '\n' || c == ' ' || c == '\t')
          {
            state = OUT;
            if (wl > 0)
              {
                word_lengths[wl] = word_lengths[wl] + 1;
              }
            wl = 0;
          }
        else //state is now IN a word
          {
            if (state == OUT)
              {
                state = IN;
                ++nw;
              }
            ++wl;
          }
      }

    printf ("%s has %d words\n", string, nw);

    //print the histogram of word lengths
    //ie:
    /* word_lengths = {0, 1, 4, 5}
       output is :

       1 -
       2 ----
       3 -----
    ,*/

    for (int i = 1; i < MAX_WORD_LENGTH; i++)
      {
        if (word_lengths[i])
          {
            printf("%d ", i);
            for (int j = 0; j < word_lengths[i]; j++)
              fputc ('-', stdout);
            printf("\n");
          }
      }

    return 0;
  }

write a C program to determine the size of float, double, and long double.

Bitwise programs

Turning off the lower 7 bits of a number

The headers and should be helpful to do this.


  int b = 0b111111111111;

  printf("%d %d %d\n", b, 0177, b & 0177);

  int c = 0b111110000000;

  printf("%d %u\n", c, c);

write a program to use alloc info:libc#Variable Size Automatic

make a C function to print a decimal number in binary

4095 127 127
3968 3968

  /* This function takes an int and prints its binary representation */
  int return_highest_power_of_2 (int i)
  {
    /* find the highest power of 2 <= i */
    short int n = 0;
    for (; pow(2 , n) <= i; ++n)
    {

    }
    return --n;
  }

  int * return_b_number (int n)
  {
    if (n == 0)
      {
        return 0;
      }
    if (n == 1)
      {
        return 1;
      }
    short highest_power_of_2 = return_highest_power_of_2 (n);
    //this needs to be turned into something interesting...
    return return_b_number (n - pow(2, highest_power_of_2)) + pow (2, highest_power_of_2);
  }

  print_b_number (int n)
  {
    //printf("%d\n", return_b_number (n));
  }

  int main ()
  {
    //print_b_number (2);
    //printf ("%d\n", return_highest_power_of_2 (32));
    printf ("%3.0f\n", return_b_number (2));
    printf ("%d\n", (int) return_b_number (2));
    return 0;
  }

printing different things based on the value of variables COOL

#+HEADERS: :includes #+BEGIN_SRC C for (int i = 0; i < 3; i++) printf ("You have %d item%s\n", i, i==1 ? "" : "s"); #+END_SRC

#+RESULTS: | You | have | 0 | items | | You | have | 1 | item | | You | have | 2 | items |

What is using strcat is bad idea?

:ANSWER: strcat concatenates two strings. It is a bad idea, but strcat is a slow method of concatenating two strings. C does not store the length of strings. Instead, it has to calculate the length of the strings each time, one attempts to copy a string.

It may be a better idea to use mempcpy. :END:

messing with arrays

Ok, so org-babel should be throwing an error here, but it is not...


int a [8];
a[7] = 3;
a[6] = 4;
a[55] = 1;
a[0] = 2;
printf ("%d %d %d %d\n", a[7], a[6], a[8], a[0]);

highest power of 2

3 4 4198752 2

  int return_highest_power_of_2 (int i)
  {
    /* find the highest power of 2 <= i */
    short int n = 0;
    for (; pow(2 , n) <= i; ++n)
      {

      }
    return --n;
  }

  int main ()
  {
    short a = return_highest_power_of_2 (0);
    short b = return_highest_power_of_2 (1);
    short c = return_highest_power_of_2 (2);
    short d = return_highest_power_of_2 (3);
    short e = return_highest_power_of_2 (4);
    short f = return_highest_power_of_2 (5);
    short g = return_highest_power_of_2 (6);
    short h = return_highest_power_of_2 (8);
    short i = return_highest_power_of_2 (9);
    short j = return_highest_power_of_2 (10);
    short k = return_highest_power_of_2 (11);
    short l = return_highest_power_of_2 (16);

    printf ("0 %d\n", a);
    printf ("1 %d\n", b);
    printf ("2 %d\n", c);
    printf ("3 %d\n", d);
    printf ("4 %d\n", e);
    printf ("5 %d\n", f);
    printf ("6 %d\n", g);
    printf ("8 %d\n", h);
    printf ("9 %d\n", i);
    printf ("10 %d\n", j);
    printf ("11 %d\n", k);
    printf ("16 %d\n", l);

    return 0;
  }

programs with IPC

sockets

PIPES & FIFOs

Threads

Processes

Signals

controlling paging

syslog

caesar cipher and decrypt program

0 -1
1 0
2 1
3 1
4 2
5 2
6 2
8 3
9 3
10 3
11 3
16 4
ll of these things are discussed in the libc manual

#+HEADERS: :include #+BEGIN_SRC C unsigned int c = 'z';

printf ("%d", c + 7); #+END_SRC

#+RESULTS:

129

| a | 97 | A | 65 |

#+HEADERS: :include #+BEGIN_SRC C enum lower_letters { a = 97, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z };

enum upper_letters { A = 65, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z };

enum upper_letters letter = Z;

putchar ((int)'z' + 7); #+END_SRC

#+RESULTS:

a

  echo "Probably the simplest case is to decrypt a short sentence." | ./caesar -s 1 | ./caesar -s 25
Probably the simplest case is to decrypt a short sentence.

  echo "GNU Emacs is Free" | ./caesar -s 1
HOV Fnbdt jt Gsff

  echo "GNU Emacs is Free" | ./caesar -s 1 | ./decrypt
GNU Emacs is Free

C bitwise operators

Bitwise &

The & operator takes two integers, and outputs the bits that are both 1.

13 & 11
1111 1100

Now the bitwise & operation

13 1101
11 1011
& &
9 1001

  int main ()
  {
    int a, b;
    a = 13;
    b = 11;

    printf("%d\n", a & b);

    a = 0b1101;  //binary 13
    b = 0b1101;  //binary 11

    return 0;
  }

Bitwise OR |

9

Bitwise OR is like the propositional logic "\/".

For two binary numbers, the if one bit is a 1, then the answer will have a 1.

15 OR 3
1111 11
15 1111
13 0011
OR OR
15 1111

  int main ()
  {
    int a = 15;
    int b = 13;

    printf("%d\n", a|b);

    a = 0b1111;
    b = 0b1101;

    printf("%d\n", a|b);

    return 0;
  }

Bitwise Exclusive OR XOR ^

15
15
17 OR 9
1111 1001
17 10001
9 01001
^ ^
25 11000

  int main ()
  {
    int a = 17;
    int b = 9;

    printf("%d\n", a|b);

    a = 0b10001;
    b = 0b1001;

    printf("%d\n", a|b);

    return 0;
  }

Bitwise complement Operator ~

25
25

I don't understand this one. I thought ~13 = 2.

It only works on one operand. It inverts all bits of one number to the opposite bit.

13 1101
~ ~
-14 0010 ????

    int main ()
    {
      int i = 13;

      printf("%d\n", ~i);

      i = 0b1101;
      printf("%d\n", ~i);

      return 0;
    }

Shift operators << and >>

-14
-14
1 <<2 1 <<2
100 4

The left shift operator moves bits in a number to the left.


    int main ()
    {
      int a = 1;
      int b = 0b1;

      printf("%d %d\n", a<<2, b<<2);

      return 0;
    }

The autoconf manual has some examples of buffer overflow and null pointers

4 4

info:autoconf#Portable C and C++

#+HEADERS: :include #+BEGIN_SRC C printf("%c", (char) ((int) 'z' + 1)); #+END_SRC

#+RESULTS:

Writing userspace C libraries

{

http://0pointer.de/blog/projects/libabc.html

https://git.kernel.org/pub/scm/linux/kernel/git/kay/libabc.git/plain/README