& The C Programming Language -----------------------------: @@ http://c-faq.com/ this is essential reading @@ http://www.cs.cf.ac.uk/Dave/C/ a badly formatted introduction to c @@ nntp://comp.lang.c to be read regularly @@ http://www.iu.hio.no/~mark/CTutorial/CTutorial.html a pretty basic tutorial about c, doesnt go into dynamic memory allocation or anything like that @@ http://ee.hawaii.edu/~tep/EE160/Book/ an online book about c @@ http://www.acm.uiuc.edu/webmonkeys/book/c_guide/ not a bad guide to c but pretty old @@ http://www.java2s.com/Code/C/CatalogC.htm lots of example c programs @@ http://www.lysator.liu.se/c/pikestyle.html rob pikes notes on c * possibly the simplest possible c program ------------------------------- #include int main () { printf ("This is a C program\n"); return(0); } ,,, HISTORY C was invented, circa 1972, by Denis Ritchie et al, at Bell labs, as part of the process of creating the Unix operating system. One of the motivations of c was to aleviate the work of porting the Unix operating system to new computer architectures. NOTES C is both a low level and high level computer language. It is the original 'write once, compile anywhere' language. C is just high enough level to be portable and low enough level to be efficient. C is still the most important language for writing virtual machines and operating systems. API @@ http://www.cppreference.com/wiki/ a complete looking api reference oriented to c++ * search for a character within a string ---------------------------------------- #include wchar_t *wcschr(const wchar_t *ws, wchar_t wc); ,,, INTERNATIONALIZATION LOCALES .... * set the locale for all categories to the environment of the computer >> setlocale (LC_ALL, ""); ##(the default is the 'c' locale) * find out the current locale --------------------------- #include #include int main() { printf("Current locale is: %s\n", setlocale(LC_ALL,NULL)); return 0; } ,,, * show the local before and after setting it to the default ----------------------------------------------------------- #include #include int main() { printf("Current locale is: %s\n", setlocale(LC_ALL,NULL)); setlocale (LC_ALL, ""); printf("Current locale is: %s\n", setlocale(LC_ALL,NULL)); return 0; } ,,, * set the locale for formatting numbers (but not money) to 'french'; ------------------------------------------------------------- #include int main() { setlocale(LC_NUMERIC, "fr"); } ,,, * set the locale for formatting time values to 'spanish' >> setlocale(LC_TIME, "es"); @@ http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_19.html#SEC322 == c locale categories .. LC_COLLATE, collation of strings (eg 'strcoll') .. LC_CTYPE, classification and conversion of characters (multibyte, wide) .. LC_MONETARY, formatting monetary value .. LC_NUMERIC, formatting numbers (not money) .. LC_TIME, formatting date and time values .. LC_ALL, all categories .. LANG, take local from the enviroment variable ..; * set the local to the local of the computer >> setlocale(LC_ALL, ""); ##(this must come before any wprintf statement) USING INTERNATIONAL CHARACTERS @@ http://triptico.com/docs/unicode.html how to convert @@ http://www.linux.com/archive/feature/51836 In this day and age using the 'char' character type is simply not good enough. The world has become globalised and text with foreign language characters needs to be handled. @@ http://www.gnu.org/software/libc/manual/html_node/Extended-Char-Intro.html#Extended-Char-Intro * loop through a (unicode) text file one character at a time ---------------------------------------------------------- /* ?? maybe have to convert the text file first */ // this is ISO C90 code wint_t c; while ((c = wgetc (fp)) != WEOF) { } ,,, == teminology .. multibyte character, a character in an encoding like utf8 (variable length) .. wide character, a character in ucs-2 or ucs-4 encoding (fixed length) .. == wide character conversion functions .. int wctob(wint_t c), converts a wide char to a single byte (if possible) .. mbrtowc, converts next multibyte char in string to a wide char .. * converting a multibyte string (utf8 for example) to a wide character string --------------------------------------------------------------------------- wchar_t * mbstouwcs(const char *s) { size_t len = strlen (s); wchar_t * result = malloc((len + 1) * sizeof(wchar_t)); wchar_t * wcp = result; wchar_t tmp[1]; mbstate_t state; size_t nbytes; memset (&state, '\0', sizeof (state)); while ((nbytes = mbrtowc (tmp, s, len, &state)) > 0) { if (nbytes >= (size_t) - 2) /* Invalid input string. */ return NULL; *wcp++ = towupper (tmp[0]); len -= nbytes; s += nbytes; } return result; } ,,, DEFINING CONSTANT VALUES * define a constant variable >> #define ELEMENTSIZE 10 INITIALIZING VARIABLES * declare an integer 'i' and an array of 100 integers 'ex' >> int i, ex[100]; * initialise a wide character string 'name' to be empty >> wchar_t name[200] = { L'\0' }; * initialise all fields of a 'struct tm' to 0 >> struct tm tm; memset(&tm, 0, sizeof(struct tm)); SWITCH STATEMENTS * a switch statement -------------------- switch(betty) { case 1: printf("betty=1\n"); break; case 2: printf("betty=2\n"); break; default: printf("Not sure.\n"); } ,,, LOOPS * exit a 'for' or 'while' loop without iterating. >> break; * execute the next iteration of a for or while loop >> ; INFINITE LOOPS An infinite loop has the potential to never terminate. * an infinite loop using for >> for (;;) { } * an infinite loop with while >> while (1) { } WHILE LOOPS .... FOR LOOPS * the body of a for loop does not need to have braces {} around it ----------------------------------------------------------------- for ( n = 1; n < index; ++n ) if ( var->next == NULL ) return NULL; else var = var->next; ,,, GETTING INPUT FROM THE USER * get a line of text from the user, a maximum of 200 wide characters -------------------------------------------------------------------- #include #include #include int main(void) { wchar_t buffer[201] = { L'\0' }; setlocale(LC_ALL, ""); wprintf(L"Enter something, telephone ☎:"); fgetws(buffer, 200, stdin); wprintf(L"You entered: %ls", buffer); } ,,, Note that fgetws (like fgetwc, fputwc, and fputws) performs an implicit conversion between multibyte and wide characters. How this actually works, I wouldnt know. DISPLAYING TEXT @@ http://www.cplusplus.com/reference/clibrary/cstdio/printf/ complete specification for printf * printf is the traditional way. puts * print a float specifying the output format >> printf("%6.3f", 2.8) ##(prints '2.800') * print a string left justified, field width 4 >> printf "%-4s", "foo"; ##(prints "foo ") >> int swprintf(wchar_t *wcs, size_t maxlen, const wchar_t *format, ...); * print a number padded on the left by zeros >> printf("%04d", i); * use an inspection set >> scanf("%[A-Z:]", stdin); >> wscanf(L"%l[A-Z:]", stdin); * print 'pi' to five decimal places ----------------------------------- #include #include fprintf(stdout, "pi = %.5f\n", 4 * atan(1.0)); ,,, STRINGS This section deals with wide character string 'wchar_t *' and with byte array strings 'char *'. Wide character strings should be able to handle characters outside of the standard 'ascii' (roman alphabet) characters, which is important. It is not possible to mix the use of 'printf' and 'wprintf' in the same program That is, any stream is either wide oriented or byte oriented. 'fwide()' can determine which it is. Whichever function is used first determines the nature of the streams (including 'stdin', 'stdout', 'stderr') INITIALISING STRINGS .... * initialise a char string using compiler concatenation >> char story[] = "once apon a time" "there was a small tree"; * define, initialize, print a wide character string ---------------------------------------- #include #include main () { wchar_t message[] = L"xx雨が降りそうxx\n"; setlocale(LC_ALL, ""); wprintf (L"message:%ls\n", message); } ,,, * define, initialize, print a wide character string ---------------------------------------- #include #include main () { wchar_t message[100]; setlocale(LC_ALL, ""); wcscpy (message, L"雨が降りそう hello\n"); wprintf (L"message:%ls\n", message); } ,,, * define and print a wide character ----------------------------------- #include #include main () { wchar_t kanji = L'雨'; setlocale(LC_ALL, ""); wprintf (L"kanji:%lc\n", kanji); wprintf (L"decimal:%i\n", kanji); wprintf (L"unicode code point:%x\n", kanji); } ,,, * define a kanji using \uxxxx notation (c99, c++ only) ----------------------------------------------------- #include #include main () { wchar_t k = L'\u96ea'; setlocale(LC_ALL, ""); wprintf (L"kanji:%lc, decimal:%i, unicode:%x\n", k,k,k); } ,,, COPYING .... * copy a byte string into another ---------------------------------------- #include #include int main () { char name[100] = "john"; char tag[100]; strcpy (name, L"雨が降りそう hello\n"); printf ("name= %s\n", ); } ,,, * copy a wide character string into another ---------------------------------------- #include #include int main () { wchar_t name[100] = L"john"; wchar_t tag[100]; setlocale (LC_ALL, ""); wcscpy(name, L"雨が降りそう hello\n"); wcscpy(tag, L"雨が降りそう hello\n"); wprintf(L"name:%ls\n", name); return(0); } ,,, SIZE .... * display the size of a wide string ----------------------------------- #include #include int main () { wchar_t name[100] = L"x雨が降りそx"; setlocale (LC_ALL, ""); wprintf(L"name:%ls\n", name); wprintf(L"size (bytes):%d\n", sizeof(name)); wprintf(L"size (chars):%d\n", sizeof(name)/sizeof(wchar_t)); wprintf(L"length (chars):%d\n", wcslen(name)); return(0); } ,,, Before appending something to a string in c, it is always necessary to make sure that there is enough room in the buffer. This can be done with 'sizeof' * display the size of a wide string pointer, this doesnt work ------------------------------------------------------------- #include #include int main () { wchar_t n[100] = L"x雨が降りそx"; wchar_t * p = n + 3; setlocale (LC_ALL, ""); wprintf(L"n:%ls\n", n); wprintf(L"p:%ls\n", p); wprintf(L"size n (bytes):%d\n", sizeof(n)); wprintf(L"size p (bytes):%d\n", sizeof(p)); wprintf(L"size (chars):%d\n", sizeof(n)/sizeof(wchar_t)); wprintf(L"length (chars):%d\n", wcslen(n)); return(0); } ,,, The code above shows that a string defined with 'char s[n]' knows how big it is, but a pointer defined with 'char * s' doesnt know how big the string is. READING .... * read a line of (maximum 64) wide characters from the keyboard --------------------------------------------------------------- #include #include int main () { wchar_t name[64] = L"X"; setlocale (LC_ALL, ""); wprintf(L"Enter name: "); int results = wscanf(L"%63l[^\n]", name); wprintf(L"Name:%ls\n", name); return(0); } ,,, * read two words from the user and store them in variables ---------------------------------------------------------- #include #include int main () { wchar_t fname[64] = {L'\0'}; wchar_t lname[64] = {L'\0'}; setlocale (LC_ALL, ""); wprintf(L"Enter first and last name: "); int results = wscanf(L"%63ls%63ls", fname, lname); wprintf(L"first:%ls last:%ls\n", fname, lname); return(0); } ,,, DISPLAYING STRINGS .... * query if output stream is wide oriented (>0) or not >> if (fwide(stdout, 0) == 0) ... print a byte string with wprintf ---------------------------------- #include int main() { char * s = "test"; wprintf(L"ascii string: %s\n", s); } ,,, * define and initialise to empty a wide character string >> wchar_t buffer[200] = { L'\0' }; >> wchar_t buffer[200]; buffer[0] = 0; ##(another way) * print a wide character string >> wprintf (L"value: %ls\n"); ANALYSING STRINGS .... * a simple 'startsWith' function, untested ----------- bool prefix(const char *prefix, const char *str) { return strncmp(pre, str, strlen(prefix)) == 0; } ,,, SEARCHING STRINGS .... search a string for a particular character ------------------------------------------ #include #include int main (void) { char * p; char c = 'x'; p = strchr("some text to be searched", c); if (p == NULL) { printf("character not found"); } printf(p); return(0); } ,,, ERRORS WITH STRINGS .... * "error: invalid initializer" >> wchar s[10] = "wrong"; ##(incorrect!!) >> wchar s[10] = L"wrong"; BOOLEANS The c language treats the value 0 as false and all non-zero values as true, but a boolean 'type' was not traditionally part of the c language. * define an enumerated type for booleans >> enum Bool { FALSE=0, TRUE }; * using booleans -------------- #include _Bool isHot; ,,, * define a boolean and display its value ---------------------------------------- #include #include main() { bool isHot = false; printf("isHot:%s", isHot?"true":"false"); } ,,, * define a boolean and display its value as a wide string --------------------------------------------------------- #include #include #include int main() { bool isHot = false; setlocale (LC_ALL, ""); wprintf(L"isHot:%ls", isHot?L"true":L"false"); return(0); } ,,, MULTIBYTE AND WIDE STRINGS A multibyte string is something like utf8. In these encodings a character may occupy 1, 2 or more bytes. This is called a variable length encoding. Wide character characters have fixed length (usually 4 bytes). IMPLICIT CONVERSION .... use fgetwc, fgetws, fputwc, fputws. EXPLICIT CONVERSION .... * convert some input text from multibyte to wide character >> fgets(s2, BUFSIZ, stdin); /* read EUC string from stdin into s2 */ >> mbstowcs(s1, s2, BUFSIZ); /* convert EUC string in s2 to process code string in s1 */ SCREEN WIDTH .... >> int wcswidth (const wchar_t *s, size_t n); INITIALISING STRING VARIABLES .... * define and initialise a wide character string >> wchar_t text[100] = L"This is unicode, rain 雨"; * initialise a wide string to be 'empty' >> wchar_t text[50] = L""; >> wchar_t text[50] = {L'\0'}; ##(the same) * define and initialise as empty a string with a capacity of 19 >> wchar_t s[20]; *s = L'\0'; >> wchar_t s[20]; *s = 0; ##(the same ?) COMPARING STRINGS .... * test if the string variable is "snow" >> if (wcscmp(word, L"snow") == 0) * compare two wide strings -------------------------- #include #include #include int main() { wchar_t * s = L"雨雨雨"; wchar_t * t = L"雨雨雨"; setlocale (LC_ALL, ""); if (!wcscmp(s, t)) wprintf(L"strings are equal\n"); else wprintf(L"strings are not equal\n"); return(0); } ,,, http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_5.html#SEC61 * duplicate a string >> strdup * add a character to a string >> sprintf(s, "%s%c", s, c); TIME AND DATE use clock() to time the amount of time it takes execute some section of code. use gmtime() etc to get calender dates. * get help for the time() function >> man 2 time * print the current date and time ----- #include #include int main() { time_t now = time(NULL); // or time_t now; time(&now); printf("the date is now: %s", ctime(&now)); } ,,, * determine if a date is today ----- #include #include int main() { struct tm someday = {1,1,1,28,2,114,-1,-1,-1}; time_t now; time(&now); struct tm today = *localtime(&now); printf("today is: %s", asctime(&today)); printf("someday is: %s", asctime(&someday)); if (today.tm_year == someday.tm_year && today.tm_mon == someday.tm_mon && today.tm_mday == someday.tm_mday) printf("someday is today!!!"); } ,,, * get the current year ----- #include #include int main() { time_t now; time(&now); struct tm date = *localtime(&now); printf("the current year: %d\n", date.tm_year + 1900); printf("the current year: %d\n", localtime(&now)->tm_year + 1900); } ,,, * print the time zone. ----- #include #include int main() { time_t now = time(NULL); printf("now the date is: %s", ctime(&now)); printf("the time zone is: %s", localtime(&now)->tm_zone); } ,,, GOTCHAS .... months tm.tm_mon are 1 based. years are 1900 based. days of months are 0 based negative and out of range integers within a 'struct tm' time structure will create havoc with functions such as 'mktime' and 'strftime' * cause a segmentation fault ----- struct tm someday = {-1,-1,-1,0,50,1000,0,0,0}; char output[200]; strftime(output, "%M, %Y", &tm); ,,, PARSING DATES AND TIMES .... The function 'strptime' carries out the job of parsing a date and or time from a character string. * get help for the strptime function >> man strptime * the prototype for strptime >> char *strptime(const char *s, const char *format, struct tm *tm); == some strptime format string example .. %d/%m%/Y - 31/2/2012 .. If strptime cant use the format it is given to parse a date then the return char * will be NULL. * parse a date string using strptime ----- #include #include int main() { char * remainder; char * input = "29/6/2015 tuesday"; struct tm someday = {-1,-1,-1,0,0,0,-1,-1,-1}; remainder = (char *)strptime(input, "%d/%m/%Y", &someday); printf("parsed date: %s", asctime(&someday)); printf("remainder: %s", remainder); } ,,, The strptime function below correctly fills in the 'day of the week' field in the struct tm time&date structure. Neither %z nor %Z seems to be working for 'EST' timezone * parse a date and time using strptime ----- #include #include int main() { char * remainder; char * input = "10/4/2014 11:30:00 EST"; struct tm someday = {-1,-1,-1,0,0,0,-1,-1,-1}; remainder = (char *)strptime(input, "%d/%m/%Y %H:%M:%S %Z", &someday); printf("parsed date: %s", asctime(&someday)); printf("remainder: %s", remainder); } ,,, * parse 2 dates using strptime ----- #include #include int main() { char * remainder; char * input = "10/4/2014 11:30:00 - 11/4/2014 12:00:00 "; struct tm someday = {-1,-1,-1,0,0,0,-1,-1,-1}; struct tm someday2 = {-1,-1,-1,0,0,0,-1,-1,-1}; input = (char *)strptime(input, "%d/%m/%Y %H:%M:%S", &someday); printf("1st parsed date: %s", asctime(&someday)); printf("remainder: %s\n", input); input = (char *)strptime(input, " - %d/%m/%Y %H:%M:%S", &someday2); printf("2nd parsed date: %s", asctime(&someday2)); printf("remainder: %s\n", input); } ,,, LIBRARY FUNCTIONS * view c library functions (on a unix-like operating system) >> man 3 func ARRAYS The name of an array is a pointer to that array, except in the case where the 'sizeof' operator is used. * declare and initialize an integer array., ----------------------------------------- #include int main () { int items[] = {32, 43, 29, 0}; printf ("The first item is %d\n", items[0]); printf ("The second item is %d\n", items[1]); return(0); } ,,, INITIALISING ARRAYS .... * all elements not initialised are set to '0' >> long name[100] = {1,3,5,7}; SIZE OF .... * display the size of an array ------------------------------ #include #include int main () { long name[100] = {1,3,5,7}; setlocale (LC_ALL, ""); wprintf(L"size (bytes):%d\n", sizeof(name)); wprintf(L"size (elements):%d\n", sizeof(name)/sizeof(long)); return(0); } ,,, * declare and initialize an array of structures ------------------------------ #include #include struct { int x; int y; } points[] = {0,1,2,3}; int main () { long name[100] = {1,3,5,7}; setlocale (LC_ALL, ""); wprintf(L"size (bytes):%d\n", sizeof(name)); wprintf(L"size (elements):%d\n", sizeof(name)/sizeof(long)); return(0); } ,,, * declare an array of structures >> struct { int x; int y; } points[] = {{0,1},{2,3}}; * make an array of float types ---------------------------- #include #define SIZE 3 int main (void) { float x[SIZE]; float *fp; int i; for (i = 0; i < SIZE; i++) { x[i] = 0.5 * (float) i; } for (i = 0; i < SIZE; i++) { printf(" %d %f \n", i, x[i]); } fp = x; for (i = 0; i < SIZE; i++) printf(" %d %f \n", i, *(fp + i)); } ,,, INPUT AND OUTPUT PRINTF .... == format specifiers for printf .. %s - any space delimited string .. %127s - a string, maximum of 127 characters .. etc .. * using compiler string concatenation ------ printf( "name: %s\n" "age: %d\n", name, age); ,,, SCANF AND FRIENDS ... Scanf is a method of reading formatted textual input into c variables. In a basic sense, it 'parses' text input. == format specifiers for scanf, sscanf, fscanf .. %s - any space delimited string .. %127s - a string, maximum of 127 characters .. %*127s - a 127 char string, discard result .. %[^\n] - an entire line .. %[abc] - a string containing only chars a,b or c .. scanf, sscanf, wscanf etc - all variables to scanf must be pointers. - whitespace is ignored, except by %c * read text and a number into variables ---- #include int main() { int age = 0; char name[128]; printf("enter name and age:\n"); scanf("%s%d", name, &age); printf("name:%s, age:%d \n", name, age); } ,,, field widths are useful for limited the number of characters read into a character array. * only read 31 characters into 'city' variable ---------- char city[32]; printf("city: "); if (scanf("%31s", city) < 1) fprintf(stderr, "error"\n); ,,, * read and discard the next 5 characters rom the input >> scanf("%*5c); %s only read one 'whitespace' delimited word. use fgets() to read one whole line. * read a text file word by word ---- #include int main() { char word[128]; FILE * fp = stdin; while (fscanf(fp, "%127s", word) == 1) { printf("%s\n", word); } } ,,, * a simple 'interpreter' loop with scanf ---- #include int main() { char line[128]; while (1) { scanf("%127[^\n]%*c", line); printf("%s\n", line); if (strcmp(line, "quit") == 0) exit(1); } } ,,, * use a 'scanset' or 'inspection set' to read binary --- char number[32]; scanf("%31[01]", number); ,,, will read at most 31 zeros and ones stopping at the first character which is not a '0' or '1' * inverted scanset, reads anything up to 1st punctuation >> scanf("%[^.!?]", sentence); The above example also reads whitespace. * read and discard everything up to the newline >> scanf("%*[^\n]%*c"); the %*c reads and discards the \n newline in the above example. WSCANF .... wscanf is used to read 'wide' character strings from an input source. This means any character which cannot by accomodated by the extended ascii (1 byte) characters. * read a line of (maximum 64) wide characters from the keyboard --------------------------------------------------------------- #include #include int main () { wchar_t name[64] = L"X"; setlocale (LC_ALL, ""); wprintf(L"Enter name: "); int results = wscanf(L"%63l[^\n]", name); wprintf(L"Name:%ls\n", name); return(0); } ,,, READING AND WRITING FILES == legal modes for opening files .. r, Open text file for reading .. w, Create a text file for writing .. a, Append to text file .. rb, Open binary file for reading .. wb, Create binary file for writing .. ab, Append to a binary file .. r+, Open text file for read/write .. w+, Create text file for read/write .. a+, Open text file for read/write .. rb+ or r+b, Open binary file for read/write .. wb+ or w+b, Create binary file for read/write .. ab+ or a+b, Open binary file for read/write .. * read a text file character by character., ----------------------------------------- #include #include int main (int argc, char *argv[]) { FILE *fp; char ch; if ((fp = fopen (argv[1], "r")) == NULL) { printf ("Cannot open file.\n"); exit (1); } while ((ch = fgetc (fp)) != EOF) { printf ("%c", ch); } fclose (fp); return 0; } ,,, * open the text 'somefile' file for writing., ------------------------------------------- #include #include int main (int argc, char *argv[]) { FILE *fp; if ((fp = fopen ("somefile.txt", "w")) == NULL) { printf ("Cannot open file.\n"); exit (1); } fclose (fp); } ,,, * read the textfile line by line ------------------------------------------- #include #include int main(int argc, char *argv[]) { FILE *fp; char line[1000]; char * file = "/home/mjb/sf/htdocs/app/data.txt"; if ((fp = fopen (file, "r")) == NULL) { perror("couldnt open file:"); exit (1); } while (fgets(line, 999, fp) != NULL) printf("%s", line); fclose (fp); } ,,, QUIRKS .... puts seems to convert the \0 to a \n. FUNCTIONS * define a function before the main method ------------------------------------------ #include int sum (int i1, int i2, int i3) { return (i1 + i2 + i3); } int main() { printf ("Sum is %d\n", sum (1, 2, 3)); return (0); } ,,, * define a function with a prototype., ------------------------------------ //prototypes allow functions to be defined after they are used #include int f (void); int main (void) { int number; number = f(); printf ("%d", number); return 0; } int f (void) { return 10; } ,,, FUNTION POINTERS .... Function pointers are interesting and useful. They all functions to be passed as parameters to other functions, or to be contained as fields in structures or elements of arrays. * basic usage ------- int sum(int a, int b) { return a + b; } int (*fp)(int, int); fp = sum; ,,, above a function and pointer to that function are defined. The name of the function 'sum' with no parenthesis is resolved by the compiler as a pointer. >> &sum may also work??? * execute a a function pointed to by pointer 'array.fn' >> info.fn(&list, param); In the example above the function pointer is a member of a structure 'info' STRUCTURES Structures allow data within a program to be organized in a logical manner. Structures are essentially the precursor of 'objects' in modern object oriented languages. C was written to implement Unix in a more portable fashion. Possibly the most important features of the C language are its inclusion of structures and pointers which make it an effective language. Structures and dynamic memory allocation can be used to create standard data structures such as linked lists, binary trees and dynamic stacks. Since c is 'pass by value' structures passed to functions are copied. To avoid this (inefficient) process, use a pointer to the structure instead. Unlike arrays, the name of a structure is not a pointer to that structure (I think). * defining and using a normal structure ---------------------------------------- #include struct point { int x; int y; }; int main() { struct point p; p.x = 3; p.y = 4; printf("The point is (%d, %d)\n", p.x, p.y); return(0); } ,,, * define a structure and initialise an array of them ---------------------------------------------------- struct song { wchar_t title[100]; wchar_t singer[100]; } songlist[] = { {L"one too many mornings", L"dylan"}, {L"money for nothing", L"knoffler"} {L"somewhere", L"anon"} }; ,,,, * define and use a typedef structure., --------------------------- typedef struct point { int x; int y; }; point p, q; int main() { p.x = 3; p.y = 4; printf ("The point is (%d, %d)\n", p.x, p.y); return (0); } ,,, The technique below is >> p = (struct point){3, 4}; and it seems to rely on syntax introduced in C99. * initialize a struct after it is declared --------------------------- #include struct point { int x, y; }; int main() { struct point p; p = (struct point){ 3, 4 }; printf ("The point is (%d, %d)\n", p.x, p.y); return (0); } ,,, * define a structure type and variables in one go ----------------------------------------------- struct student { char name[30]; float number; } rob, sarah; ,,, * allocate memory for a structure ------------------------------- struct person * p; p = (struct person *) malloc(sizeof(struct person); ,,, UNIONS Below... a good example of using a union within a structure with a tag. the enum Type could be within the structure like this enum Type { INTS, FLOATS, DOUBLE }; struct S { Type s_type; // or enum Type { INTS, FLOATS, DOUBLE } s_type; union { int s_ints[2]; float s_floats[2]; double s_double; }; }; void do_something(struct S *s) { switch(s->s_type) { case INTS: // do something with s->s_ints break; case FLOATS: // do something with s->s_floats break; case DOUBLE: // do something with s->s_double break; } } DATA STRUCTURES LINKED LISTS .... * a structure which contains a pointer to itself -------- struct node { char *item; struct node *next; }; typedef struct node *NODEPTR; ,,, * a linked list implementation.. ------------------------------ struct person { wchar_t name[20]; int age; struct person *next; }; int main() { struct person * someone; struct person * someoneelse; } ,,, The above linked list doesnt work very well because it is difficult to dynamically create list items. * a better linked list implementation.. ------------------------------ struct person { wchar_t * name; int age; struct person *next; }; struct person * person(); int main() { struct person * someone; struct person * someoneelse; } ,,, OBJECT ORIENTED PROGRAMMING IN C * ?? ORGANISING C CODE @@ http://tldp.org/HOWTO/Program-Library-HOWTO/more-examples.html * c files can be organised in modules, with header files ------------------------------------------------------- /* file: test.c */ #include #include "header.h" char * AnotherString = "Hello Everyone"; main () { printf("running test.c...\n"); ffTest(TEXT); printf("Finished.\n"); } /* file: ffTest.c */ #include extern char *AnotherString; void ffTest(char * s) { printf("%s\n", s); printf("Global Variable = %s\n", AnotherString); } /* file header.h: */ #define TEXT "Hello World" void ffTest(); ,,, HEADER FILES .... use ifndef to not include header files twice -------------------------------------------- /* File foo.h */ #ifndef FOO_H_SEEN #define FILE_FOO_SEEN ... head file contents #endif ,,, * an example header file ------------------------ #ifndef MY_HEADER #define MY_HEADER void myfunc1(int a,int b); int blah(void); #endif ,,, * declarations can be without parameter names >> int isLeapYear(int); ONE LINERS * execute a shell or system command >> system(...); SOCKETS AND TCP BSD Sockets are the unix and c abstraction for the creation of network connections using various protocols- tcp, udp etc. * see some documentation for the socket() function >> man socket == type of sockets .. SOCK_STREAM - tcp/ip .. SOCK_DGRAM - udp .. RAW? - raw .. * a simple daytime client using bsd sockets ------- #include #include #include #include #include #include #define PORT 13 int main() { int con, in, index=0, limit=128; struct sockaddr_in servaddr; char output[200]; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(PORT); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); connect(con, (struct sockaddr *)&servaddr, sizeof(servaddr)); while ((in = read(con, &output[index], 128))>0) { index += in; limit -= in; } output[index] = 0; printf("%s\n", output); close(con); return(0); } ,,, 'htons' is used to set the server port address because of the internet is Big Endian and the computer may not be. * read a page from a www server -------- #include #include #include #include #include #include //#include void getPage(int sock) { char buffer[10000]; size_t charRead; sprintf(buffer, "GET /\n"); write(sock, buffer, strlen(buffer)); while (1) { charRead = read(sock, buffer, 10000); if (charRead==0) return; fwrite(buffer, sizeof(char), charRead, stdout); } } int main() { int sock; char hostname[100] = "www.c2.com"; struct sockaddr_in name; struct hostent * hostinfo; sock = socket(PF_INET, SOCK_STREAM, 0); name.sin_family = AF_INET; hostinfo = gethostbyname(hostname); if (hostinfo == NULL) { printf("couldnt resolve hostname '%s'", hostname); return(1); } name.sin_addr = *((struct in_addr *)hostinfo->h_addr); name.sin_port = htons(80); if (connect(sock, (const struct sockaddr *)&name, sizeof(struct sockaddr_in))==-1) { perror("couldnt connect"); return 1; } getPage(sock); return 0; } ,,,, SOUND AND AUDIO Audio files consist of a 'container' format, which is a file format containing mainly 'meta' information about the audio data present in the file, and a 'codec' which is usually a compression or encryption encoding of the audio data. PORTAUDIO .... Portaudio is used by the Audacity audio editor. * install the portaudio sound library >> sudo apt-get install libportaudio-dev libportaudio-doc * play a sound file with portaudio and sndfile ------------- #include #include #include #include #define FRAMES_PER_BUFFER (1024) #define PA_SAMPLE_TYPE paInt16 typedef short SAMPLE; #define BUFFER_LEN 128 #define MAX_CHANNELS 2 int sndFile_play (const char *infilename) { PaStreamParameters outputParameters; PaStream *stream; PaError err; static short data[BUFFER_LEN]; SNDFILE *infile; SF_INFO sfinfo; sf_count_t readcount; int channels; int srate; err = Pa_Initialize(); if ( !( infile = sf_open( infilename, SFM_READ, &sfinfo ) ) ) { printf ("Not able to open input file %s.\n", infilename); puts (sf_strerror (NULL)); return 1; } if ( sfinfo.channels > MAX_CHANNELS ) { printf ("Not able to process more than %d channels\n", MAX_CHANNELS); return 1; } /* FILE INFO */ channels = sfinfo.channels; // channels printf("number of channels %d\n", sfinfo.channels); srate = sfinfo.samplerate; printf("sample rate %d\n", sfinfo.samplerate); outputParameters.device = Pa_GetDefaultOutputDevice(); outputParameters.channelCount = sfinfo.channels; outputParameters.sampleFormat = PA_SAMPLE_TYPE; outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; outputParameters.hostApiSpecificStreamInfo = NULL; printf("Begin playback.....\n"); fflush(stdout); err = Pa_OpenStream( &stream, NULL, &outputParameters, sfinfo.samplerate, FRAMES_PER_BUFFER, paClipOff, NULL, NULL ); if( stream ) { err = Pa_StartStream( stream ); printf("Waiting for playback to finish....\n"); fflush(stdout); while ((readcount = sf_read_short( infile, data, BUFFER_LEN*sfinfo.channels ))) { err = Pa_WriteStream( stream, data, BUFFER_LEN ); } err = Pa_CloseStream( stream ); printf("Done.\n"); fflush(stdout); } sf_close( infile ); Pa_Terminate(); return 0; } ,,, GSTREAMER Gstreamer is a 'pipeline' based api for playing, editing and analysing media such as audio and video. It is written in c but contain bindings for other languages, such as Python. It may well be *the* programmatic api for dealing with media. Recently (2012) an important new series of gstreamer was release (1.x) but the main linux repositories appear to contain the 0.10 series. http://tordwessman.blogspot.com.au/2012/01/installing-gstreamer-under-linux.html how to compile and run a gstreamer application. See gstreamer.org? for a simple helloworld program for gstreamer. * compile a gstreamer c program >> gcc -Wall helloworld.c -o helloworld $(pkg-config --cflags --libs gstreamer-1.0) COLOR IN THE TERMINAL Another way to achieve colour in the terminal is with ansi escape sequences (?) (is this portable?) http://ascii-table.com/ansi-escape-sequences.php a detailed list of ansi escapes, including colours * a simpler way to print something in color ---------- #include #define KNRM "\x1B[0m" #define KRED "\x1B[31m" #define KGRN "\x1B[32m" #define KYEL "\x1B[33m" #define KBLU "\x1B[34m" #define KMAG "\x1B[35m" #define KCYN "\x1B[36m" #define KWHT "\x1B[37m" int main() { printf(KRED "red\n"); printf(KGRN "green\n"); printf(KYEL "yellow\n"); // below is worse printf("%sblue\n", KBLU); printf("%smagenta\n", KMAG); printf("%scyan\n", KCYN); printf("%swhite\n", KWHT); // KNRM return colours to the default printf("%snormal\n", KNRM); return 0; } ,,, * a macro to print something in red --------- #include #define RED "\x1B[31m" #define RESET "\x1B[0m" #define LOG_RED(X) printf(RED X RESET) main() { LOG_RED("This is in Red"); } ,,, NCURSES The 'ncurses' library allows the programmer to use available capabilities of the terminal such as positioning the cursor on the screen, printing in color, receiving input from the mouse. Ncurses can be seen as an intermediate step between terminal programming and windowed applications. * install the ncurses development library >> sudo apt-get libncurses5-dev * compile a program which uses the ncurses library >> gcc program.c -lncurses * print hello world ------------- #include int main() { initscr(); /* Start curses mode */ printw("Hello World !!!"); /* Print Hello World */ refresh(); /* Print it on to the real screen */ getch(); /* Wait for user input */ endwin(); /* End curses mode */ return 0; } ,,, * print with colors --------- #include #include int main(int argc, char *argv[]) { initscr(); if(has_colors() == FALSE) { endwin(); printf("Your terminal does not support color\n"); exit(1); } start_color(); init_pair(1, COLOR_RED, COLOR_BLACK); attron(COLOR_PAIR(1)); mvwprintw(stdscr, 0, 9, "%s", "violoa in color..."); refresh(); attroff(COLOR_PAIR(1)); getch(); endwin(); } ,,, GLIB Glib is a library of non graphical utility functions and objects for the c language which is usually used in conjunction with gtk * concatenate strings using glib >> str = g_strconcat ("fist name ", name, "?", NULL); GTK AND WINDOWS The gtk api is the preferred manner to create windowed programs using the c programming language. == gtk components .. glib - non graphical utility functions (strings etc) .. pango - text and font rendering (international) .. gdk - drawing .. gdkpixbuf - manipulate images .. atk - accessibility .. * install gtk+ development on a debian-style system >> sudo apt-get install gnome-devel * compile a gtk program >> gcc -Wall test.c -o test $(pkg-config --cflags gtk+-2.0) $(pkg-config --libs gtk+-2.0) * slightly simpler... compile a gtk program >> gcc -Wall test.c -o test $(pkg-config --cflags gtk+-2.0 --libs gtk+-2.0) ENTRY WIDGETS .... The entry widget is a one-line box which allows the user to enter text. * a password entry box -------------- #include static void destroy (GtkWidget *window, gpointer data) { gtk_main_quit (); } int main (int argc, char *argv[]) { GtkWidget *window, *hbox, *label, *pass; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Password?"); gtk_container_set_border_width (GTK_CONTAINER (window), 10); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL); label = gtk_label_new ("Password:"); // a password entry widget pass = gtk_entry_new (); gtk_entry_set_visibility (GTK_ENTRY (pass), FALSE); gtk_entry_set_invisible_char (GTK_ENTRY (pass), '*'); hbox = gtk_hbox_new (FALSE, 5); gtk_box_pack_start_defaults (GTK_BOX (hbox), label); gtk_box_pack_start_defaults (GTK_BOX (hbox), pass); gtk_container_add (GTK_CONTAINER (window), hbox); gtk_widget_show_all (window); gtk_main (); return 0; } ,,, COMBOBOXES .... * add a set of options to a combobox --------- GList *glist = NULL; glist = g_list_append (glist, "String 1"); glist = g_list_append (glist, "String 2"); glist = g_list_append (glist, "String 3"); glist = g_list_append (glist, "String 4"); gtk_combo_set_popdown_strings (GTK_COMBO (combo), glist); ,,, FILECHOOSER .... * a simple example of using a file chooser button -------- #include static void destroy (GtkWidget *window, gpointer data) { gtk_main_quit (); } // When a file is selected, display the full path in the GtkLabel static void file_changed ( GtkFileChooser *chooser, GtkLabel *label) { gchar *file = gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER (chooser)); gtk_label_set_text (label, file); } int main (int argc, char *argv[]) { GtkWidget *window, *chooser, *label, *vbox; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Simple File Chooser"); gtk_container_set_border_width (GTK_CONTAINER (window), 10); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL); label = gtk_label_new (""); chooser = gtk_file_chooser_button_new ( "Choose a File", GTK_FILE_CHOOSER_ACTION_OPEN); g_signal_connect (G_OBJECT (chooser), "selection_changed", G_CALLBACK (file_changed), (gpointer) label); // Set chooser to the user's home directory. gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser), g_get_home_dir()); vbox = gtk_vbox_new (FALSE, 5); gtk_box_pack_start_defaults (GTK_BOX (vbox), chooser); gtk_box_pack_start_defaults (GTK_BOX (vbox), label); gtk_container_add (GTK_CONTAINER (window), vbox); gtk_widget_show_all (window); gtk_main (); return 0; } ,,, * use a file chooser with a file filter -------- #include static void destroy (GtkWidget *window, gpointer data) { gtk_main_quit (); } // When a file is selected, display the full path in the GtkLabel static void file_changed ( GtkFileChooser *chooser, GtkLabel *label) { gchar *file = gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER (chooser)); gtk_label_set_text (label, file); } int main (int argc, char *argv[]) { GtkWidget *window, *chooser, *label, *vbox; GtkFileFilter *filter; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "File Chooser Button"); gtk_container_set_border_width (GTK_CONTAINER (window), 10); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL); label = gtk_label_new (""); chooser = gtk_file_chooser_button_new ( "Choose a File", GTK_FILE_CHOOSER_ACTION_OPEN); g_signal_connect (G_OBJECT (chooser), "selection_changed", G_CALLBACK (file_changed), (gpointer) label); // Set chooser to the user's home directory. gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser), g_get_home_dir()); /* a filter to show only 3 types of images. */ filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter1, "Image Files"); gtk_file_filter_add_pattern (filter1, "*.png"); gtk_file_filter_add_pattern (filter1, "*.jpg"); gtk_file_filter_add_pattern (filter1, "*.gif"); // Add both filters to file chooser button that selects files. gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter); vbox = gtk_vbox_new (FALSE, 5); gtk_box_pack_start_defaults (GTK_BOX (vbox), chooser); gtk_box_pack_start_defaults (GTK_BOX (vbox), label); gtk_container_add (GTK_CONTAINER (window), vbox); gtk_widget_show_all (window); gtk_main (); return 0; } ,,, * a folder chooser -------- #include static void folder_changed (GtkFileChooser*, GtkLabel*); static void destroy (GtkWidget *window, gpointer data) { gtk_main_quit (); } int main (int argc, char *argv[]) { GtkWidget *window, *chooser, *label, *vbox; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Folder Chooser"); gtk_container_set_border_width (GTK_CONTAINER (window), 10); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL); label = gtk_label_new (""); chooser = gtk_file_chooser_button_new ( "Chooser a Folder", GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); /* Monitor when the selected folder or file are changed. */ g_signal_connect (G_OBJECT (chooser), "selection_changed", G_CALLBACK (folder_changed), (gpointer) label); // Set chooser buttons to location of the user's home directory. gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser), g_get_home_dir()); vbox = gtk_vbox_new (FALSE, 5); gtk_box_pack_start_defaults (GTK_BOX (vbox), chooser); gtk_box_pack_start_defaults (GTK_BOX (vbox), label); gtk_container_add (GTK_CONTAINER (window), vbox); gtk_widget_show_all (window); gtk_main (); return 0; } /* display the full path in the GtkLabel widget. */ static void folder_changed ( GtkFileChooser *chooser, GtkLabel *label) { gchar *file = gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER (chooser)); gtk_label_set_text (label, file); } ,,, TEXTVIEW WIDGET .... A comprehensive text editor and renderer. * a simple textview widget in a scrolled window ---------------- #include int main (int argc, char *argv[]) { GtkWidget *window, *scrolled_win, *textview; GtkTextBuffer *buffer; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Text Views"); gtk_container_set_border_width (GTK_CONTAINER (window), 10); gtk_widget_set_size_request (window, 250, 150); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL); textview = gtk_text_view_new (); buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview)); gtk_text_buffer_set_text(buffer, "A 1st GtkTextView widget!", -1); scrolled_win = gtk_scrolled_window_new (NULL, NULL); gtk_container_add (GTK_CONTAINER (scrolled_win), textview); gtk_scrolled_window_set_policy ( GTK_SCROLLED_WINDOW (scrolled_win), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_container_add (GTK_CONTAINER (window), scrolled_win); gtk_widget_show_all (window); gtk_main(); return 0; } ,,, IMAGES .... https://developer.gnome.org/gtk3/stable/GtkImage.html The official api documentation for GtkImage * insert an image into a textview widget --------------- #include int main (int argc, char *argv[]) { GtkWidget *window, *scrolled_win, *textview; GdkPixbuf *img; GtkTextIter line; GtkTextBuffer *buffer; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Pixbuf Images"); gtk_container_set_border_width (GTK_CONTAINER (window), 10); gtk_widget_set_size_request (window, 200, 150); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL); textview = gtk_text_view_new (); buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview)); gtk_text_buffer_set_text (buffer, " Undo\n Redo", -1); // Create an image and insert into the text buffer. img = gdk_pixbuf_new_from_file (argv[1], NULL); gtk_text_buffer_get_iter_at_line (buffer, &line, 0); gtk_text_buffer_insert_pixbuf (buffer, &line, img); scrolled_win = gtk_scrolled_window_new (NULL, NULL); gtk_container_add (GTK_CONTAINER (scrolled_win), textview); gtk_container_add (GTK_CONTAINER (window), scrolled_win); gtk_widget_show_all (window); gtk_main(); return 0; } ,,, GDKPIXBUF .... The gdkpixbuf is the data/object type used to read, analyse, manipulate and save to file image data within the gtk api. It includes functions to crop, rotate, scale, and composite images https://developer.gnome.org/gdk-pixbuf/stable/ the official and good documentation for the gdkpixbuf * some standard supported gdkpixbuf formats are "jpeg", "png", "tiff", "ico" or "bmp" The code below does not print anything, just creates a list of writeable formats. * get a list of all writeable image formats ------------ // #include #include int main (int argc, char** argv) { void add_if_writable (GdkPixbufFormat *data, GSList **list) { if (gdk_pixbuf_format_is_writable (data)) *list = g_slist_prepend (*list, data); } GSList *formats = gdk_pixbuf_get_formats(); GSList *writable_formats = NULL; g_slist_foreach (formats, (GFunc)add_if_writable, &writable_formats); g_slist_free (formats); return 0; } ,,, GTKIMAGE WIDGETS .... The GtkImage widget is an easy way to add an image to a gtk container object. It is a 'higher' level interface than a GdkPixBuf object. * possibly the simplest gtk code for displaying an image --------------- #include void destroy(void) { gtk_main_quit(); } int main (int argc, char** argv) { GtkWidget* window; GtkWidget* image; gtk_init (&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); image = gtk_image_new_from_file(argv[1]); gtk_signal_connect(GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (destroy), NULL); gtk_container_add(GTK_CONTAINER (window), image); gtk_widget_show_all(window); gtk_main(); return 0; } ,,, * can be compiled with >> gcc -Wall img.c -o img `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0` * load an image from file >> GtkWidget * gtk_image_new_from_file(const gchar * filename); * creating a new stock image and adding it to a box ---- image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG); hbox = gtk_hbox_new(FALSE, 5); gtk_box_pack_start_defaults(GTK_BOX(hbox, image); ... ,,, * use an image as the background for a widget ---------- GdkPixbuf *image = NULL; GdkPixmap *background = NULL; GtkStyle *style = NULL; image = gdk_pixbuf_new_from_file ("background.jpg", NULL); gdk_pixbuf_render_pixmap_and_mask (image, &background, NULL, 0); style = gtk_style_new (); style->bg_pixmap [0] = background; gtk_widget_set_style (GTK_WIDGET(widget), GTK_STYLE (style)); ,,, COLORS WITH GTK .... * define a new colour >> GdkColor red = {0, 0xffff, 0x0000, 0x0000}; * set the background colour of a gtk widget ---------- GdkColor color; gdk_color_parse("#00FF7F", &color); gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &color); ,,, * a color chooser button --------------- #include static void color_changed (GtkColorButton*, GtkWidget*); static void destroy (GtkWidget *window, gpointer data) { gtk_main_quit (); } int main (int argc, char *argv[]) { GtkWidget *window, *button, *label, *hbox; GdkColor color; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Color Button"); gtk_container_set_border_width (GTK_CONTAINER (window), 10); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL); /* Set initial color as #003366 and set the dialog title. */ gdk_color_parse ("#003366", &color); button = gtk_color_button_new_with_color (&color); gtk_color_button_set_title (GTK_COLOR_BUTTON (button), "Select a Color"); label = gtk_label_new ("Look at my color!"); gtk_widget_modify_fg (label, GTK_STATE_NORMAL, &color); g_signal_connect (G_OBJECT (button), "color_set", G_CALLBACK (color_changed), (gpointer) label); hbox = gtk_hbox_new (FALSE, 5); gtk_box_pack_start_defaults (GTK_BOX (hbox), button); gtk_box_pack_start_defaults (GTK_BOX (hbox), label); gtk_container_add (GTK_CONTAINER (window), hbox); gtk_widget_show_all (window); gtk_main (); return 0; } /* set selected color as the GtkLabel's foreground color. */ static void color_changed (GtkColorButton *button, GtkWidget *label) { GdkColor color; gtk_color_button_get_color (button, &color); gtk_widget_modify_fg (label, GTK_STATE_NORMAL, &color); } ,,, LAYOUT .... * layout a vertical box -------- #include static void destroy (GtkWidget*, gpointer); #define NAMES 4 const gchar* names[] = { "Andrew", "Joe", "Samantha", "Jonathan" }; int main (int argc, char *argv[]) { gint i; GtkWidget *window, *vbox; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Boxes"); gtk_container_set_border_width (GTK_CONTAINER (window), 10); gtk_widget_set_size_request (window, 150, -1); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL); vbox = gtk_vbox_new (TRUE, 5); /* Add four buttons to the vertical box. */ for (i = 0; i < NAMES; i++) { GtkWidget *button = gtk_button_new_with_label (names[i]); gtk_box_pack_start_defaults (GTK_BOX (vbox), button); g_signal_connect_swapped (G_OBJECT (button), "clicked", G_CALLBACK (gtk_widget_destroy), (gpointer) button); } gtk_container_add (GTK_CONTAINER (window), vbox); gtk_widget_show_all (window); gtk_main (); return 0; } static void destroy (GtkWidget *window, gpointer data) { gtk_main_quit (); } ,,, GDKPIXBUF .... The 'gdkpixbuf' library allows the viewing and editing of images. It is usually used in conjunction with the gtk api. * load an image from a pixbuf -------- GError * error = NULL; GdkPixbuf * logo = gdk_pixbuf_new_from_file("/path/to/logo.png", &error); GtkWidget * gtk_image_new_from_pixbuf(logo); ,,, * scale a GdkPixbuf image >> GdkPixbuf * gdk_pixbuf_scale_simple(const GdkPixbuf * src, int width, int height, GdkInterpType interpolation); * eg >> newpixbuf = gdk_pixbuf_scale_simple(oldpixbuf, 500, 500, GDK_INTERP_BILINEAR); EVENTS .... Events are things which happen which are not generated by the normal flow of the program. This can include human generated events such as mouse-clicks, keyboard presses and releases and any other human controlled input device. Events can also be generated by other processes or threads performing tasks. For example,the termination of loading a large image file into memory may generate an event. In gtk events emit 'signals' Some widgets, (such as the GtkLabel) do not generate events and need to be placed into a GtkEventBox if events are required. * use an eventbox to capture click events on a GtkLabel --------------- #include static void destroy (GtkWidget *window, gpointer data) { gtk_main_quit (); } static gboolean button_pressed (GtkWidget*, GdkEventButton*, GtkLabel*); int main (int argc, char *argv[]) { GtkWidget *window, *eventbox, *label; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Event Box"); gtk_container_set_border_width (GTK_CONTAINER (window), 10); gtk_widget_set_size_request (window, 200, 50); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL); eventbox = gtk_event_box_new (); label = gtk_label_new ("Double-Click Me!"); // Set order for receiving notification of events. gtk_event_box_set_above_child (GTK_EVENT_BOX (eventbox), FALSE); g_signal_connect (G_OBJECT (eventbox), "button_press_event", G_CALLBACK (button_pressed), (gpointer) label); gtk_container_add (GTK_CONTAINER (eventbox), label); gtk_container_add (GTK_CONTAINER (window), eventbox); /* the event box catches button presses, set the * cursor to hand when the mouse is over the event box. */ gtk_widget_set_events (eventbox, GDK_BUTTON_PRESS_MASK); gtk_widget_realize(eventbox); gdk_window_set_cursor(eventbox->window, gdk_cursor_new (GDK_HAND1)); gtk_widget_show_all (window); gtk_main (); return 0; } // called every time a button-press occurs on the GtkEventBox. static gboolean button_pressed (GtkWidget *eventbox, GdkEventButton *event, GtkLabel *label) { if (event->type == GDK_2BUTTON_PRESS) { const gchar *text = gtk_label_get_text (label); if (text[0] == 'D') gtk_label_set_text (label, "I Was Double-Clicked!"); else gtk_label_set_text (label, "Double-Click Me Again!"); } return FALSE; } ,,, KEYPRESS EVENTS IN GTK .... Return FALSE from the "key_press" event handler to allow the widget to handle the event normally. * testing keypresses --------------- #include static gboolean keyPressed (GtkEntry * entry, GdkEventKey * event) { guint k = event->keyval; gint value = g_ascii_digit_value (event->string[0]); return FALSE; } static void destroy (GtkWidget *window, gpointer data) { gtk_main_quit (); } int main (int argc, char *argv[]) { GtkWidget *window, *entry, *label, *hbox; GdkColor color; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Key presses"); gtk_container_set_border_width (GTK_CONTAINER (window), 10); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL); label = gtk_label_new ("key press"); entry = gtk_entry_new (); g_signal_connect (G_OBJECT(entry), "key-press-event", G_CALLBACK (keyPressed), NULL); hbox = gtk_hbox_new (FALSE, 5); gtk_box_pack_start_defaults (GTK_BOX (hbox), label); gtk_box_pack_start_defaults (GTK_BOX (hbox), entry); gtk_container_add (GTK_CONTAINER (window), hbox); gtk_widget_show_all (window); gtk_main (); return 0; } ,,, THE GNU C COMPILER == header file search folders .. /usr/local/include - .. libdir/gcc/target/version/include - .. /usr/target/include - .. /usr/include - * add to the header include folders >> gcc -Idir * add folders for quoted included header file eg: #include "header.h" >> gcc -iquote folder * create object files f1.o and f2.o >> gcc -c f1.c f1.c * create an executable file from object file linking the math library >> gcc function.o test.o -o test -lm ##(this links 'lib/libm.a') * link a library 'libtest.a' in the current folder >> gcc prog.o -L. -ltest * create an executable called 'test' from test.c and the function 'func.c' >> gcc func.c test.c -o test * create an archive (library) >> ar cr .... USING MAKE TO COMPILE PROGRAMS .... The principle behind make is to only compile code if it, or one of its dependencies has been modified. This saves time with large projects. * a very simple makefile called 'Makefile' ----------------------------------------------- test: test.o ffunction.o gcc ffunction.o test.o -o test test.o: test.c gcc -c test.c ffunction.o: ffunction.c gcc -c ffunction.c clean: rm *.o ,,, ##(the command lines have to begin with a tab) * only execute compile 'test' if 'test.o' or 'f1.o' has changed --------------------------------------------------------------- test: test.o f1.o gcc f1.o test.o -o test ,,, * run only the rule 'clean' from a makefile >> make clean * compile a program with a make file >> make MAKING STATIC LIBRARIES .... "ar": chive c code files o- it is a convention that static library files are named with a '.a' extention - libraries make it easier to distribute code since only one file has to be installed * show the contents (files in) of the library 'somelibrary.a' >> ar t somelibrary.a >> ar tv somelibrary.a ##(the same but more verbose output) * create or update a library file 'somelibrary.a' with 3 files >> ar r somelibrary.a functionA.o functionB.o functionC.o * add a file to a library file >> ar q library.a functionA.o * extract files from a library archive >> ar x somelibrary.a * use a library to create an executable file called 'test' >> gcc test.c somelibrary.a -o test * a makefile to build a static library -------------------------------------- library.a: functionA.o functionB.o ar rv libsome.a functionA.o functionB.o rm functionA.o functionB.o ,,, * add a table of contents to an archive file >> ar s libsome.a ##(this can be run with 'make'. or 'make clean' to remove .o files) * use a make file which is called 'create' not 'Makefile' >> make -f create SHARED LIBRARIES .... Shared libraries have names like 'libc.so.6' and are loaded dynamically when a program is run, instead of being compiled into the executable binary of a program, as is the case of static libraries made with the 'ar' program. * check what shared libraries the program 'wc' needs to run >> ldd /usr/bin/wc GCC ERROR MESSAGES DECIFERED .... > 'segmentation fault' This means that you are trying to access memory which you shouldnt be accessing. An array out-of-bounds, past the end of a string etc etc. * an undefined type or variable in a header file function declaration >> error: expected ‘)’ before ‘*’ token error message: file.c:6: error: conflicting types for ‘aFunction’ header.h:49: error: previous declaration of ‘aFunction’ was here explanation: BOOKS @@ C in a nutshell (O'Reilly) An excellent and comprehensive book LINKS http://library.gnome.org/devel/gtk-tutorial/stable/ a gtk tutorial KNOWLEDGEABLE PEOPLE Chas Owens (stack overflow) about images VIM AND C The vim editor can be used to write c programs and program fragments. These programs and fragments can be compiled and run from within the vim editor- a kind of basic 'ide' or integrated development environment. The following vim commands and maps can be placed inside the 'vimrc' file, which is the configuration file for vim and is usually located at /etc/vim/vimrc or ~/.vimrc * compile the current file with gcc >> map ,gcc :!gcc % * compile the current c file with tcc minimalist c compiler >> map ,tcc :!tcc % * a vim map to compile and run a 'c' program between '---' and ',,,' >> map ,scc :?^ *---?+1,/^ *,,,/-1w! test.c \| !gcc test.c; ./a.out * a more complicated map which compiles with gtk if necessary >> map ,gtk :?^ *---?+1,/^ *,,,/-1w! fragment.c \| !n=$(grep -c gtk.h fragment.c); if [ $n -gt 0 ]; then gcc -Wall fragment.c $(pkg-config --cflags gtk+-2.0 --libs gtk+-2.0); else gcc -Wall fragment.c; fi * compile & run a c fragment add skeleton code !!bug '#' >> map ,fcc :?^ *---?+1,/,,,/-1w ! (echo -e '#include \n int main () \n{' ; sed 's/a/a/'; echo -e ' }\n}') > fragment.c; gcc fragment.c; ./a.out * compile & run a c program within --- and ,,, >> map ,fcc :?^ *---?+1,/,,,/-1w ! ( cat - ) > fragment.c; gcc fragment.c; ./a.out The astyle c formatting utility can be used in conjunction with the vim editor to format and indent an entire c file or ooly a part of the file. * install the 'astyle' formatting program >> sudo apt-get install astyle The vim 'maps' below can be placed in the vimrc file (often located at ~/.vimrc) so that they will always be available when vim is started. * indent a the whole c file with astyle >> map ,ii :%! astyle -s2 * indent text between --- and ,,, with astyle >> map ,ci :?^ *---?+1,/^ *,,,/-1! astyle -s2 sed 's/^/ /' The map above is invoked by typing ',ci' when the vim editor is in 'normal' mode (that is not insert mode etc). It is designed to format code which is embedded in a normal text document. This is mainly useful when writing about c programs. * indent a the whole c file with astyle breaking open braces >> map ,ii :%! astyle -bs2 DOCUMENT-NOTES: # what sort of document is this document-icon: document-image: document-type: book # in what kind of state (good or bad) is this document document-quality: almost useful # when was this document last updated last-revision: mar 2014 # work which has been carried out on this document document-history: @@ 2009 document begun in a very cursory fashion. The idea behind the booklet was to write a modern text about the c language, showing how to solve real problems using c. Such as multibyte strings, windowed applications, etc @@ feb 2010 revisiting the document. @@ mar 2014 some new information about time and dates Some gtk window programming and rudimentary ncurses info. # who wrote this authors: mjb ~ http://bumble.sf.net # a short description of the contents, possible used for doc lists short-description: trying to make c programming less hazardous # a programming language code-language: c # the script which will be used to produce html (a webpage) make-html: ./book-html.sh # the script which will produce 'LaTeX' output (for printing, pdf etc) make-latex: