Table of Contents

last revision
22 February 2015, 10:13pm
book quality
almost useful
& The C Programming Language :

www: http://c-faq.com/
this is essential reading
www: http://www.cs.cf.ac.uk/Dave/C/
a badly formatted introduction to c
www: nntp://comp.lang.c
to be read regularly
www: 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
www: http://ee.hawaii.edu/~tep/EE160/Book/
an online book about c
www: http://www.acm.uiuc.edu/webmonkeys/book/c_guide/
not a bad guide to c but pretty old
www: http://www.java2s.com/Code/C/CatalogC.htm
lots of example c programs
www: http://www.lysator.liu.se/c/pikestyle.html
rob pikes notes on c
possibly the simplest possible c program
    #include <stdio.h>
    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 ‹↑›

www: http://www.cppreference.com/wiki/
a complete looking api reference oriented to c++
search for a character within a string
    #include <wchar.h>
    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 <locale.h>
    #include <stdio.h>
    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 <locale.h>
    #include <stdio.h>
    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 <locale.h>
    int main()
    {
      setlocale(LC_NUMERIC, "fr");
    }

set the locale for formatting time values to 'spanish'

 setlocale(LC_TIME, "es");

www: http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_19.html#SEC322

set the local to the local of the computer

 setlocale(LC_ALL, ""); this must come before any wprintf statement

Using International Characters ‹↑›

www: http://triptico.com/docs/unicode.html
how to convert
www: 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.

www: 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)
   {
   }

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
;

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)

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 <stdio.h>
    #include <wchar.h>
    #include <locale.h>
    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 ‹↑›

www: 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 <math.h>
    #include <stdio.h>
    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 <locale.h>
   #include <wchar.h>
   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 <locale.h>
   #include <wchar.h>
   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 <locale.h>
   #include <wchar.h>
   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 <locale.h>
   #include <wchar.h>
   main () {
     wchar_t k = L'\u96ea';
     setlocale(LC_ALL, "");   
     wprintf (L"kanji:%lc, decimal:%i, unicode:%x\n", k,k,k);
   }

Manipulating Strings ‹↑›

remove the last character from the string 'line'

 *(line+strlen(line)-1) = '\0';

Copying ‹↑›

copy a byte string into another

   #include <stdio.h>
   #include <string.h>
   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 <wchar.h>
   #include <locale.h>
   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 <wchar.h>
   #include <locale.h>
   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 <wchar.h>
   #include <locale.h>
   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 <wchar.h>
   #include <locale.h>
   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 <wchar.h>
   #include <locale.h>
   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

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

print a byte string with wprintf

     #include <locale.h> 
     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 <stdio.h>
    #include <string.h>
    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 <stdbool.h> 
    _Bool isHot;

define a boolean and display its value

    #include <stdio.h>
    #include <stdbool.h>
    main()
    {
      bool isHot = false;
      printf("isHot:%s", isHot?"true":"false");
    }

define a boolean and display its value as a wide string

    #include <stdio.h>
    #include <stdbool.h>
    #include <locale.h>
    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 (fwide(stdout, 0) == 0) ...

compare two wide strings

    #include <stdio.h>
    #include <locale.h>
    #include <wchar.h>
    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 <stdio.h> #include <time.h> 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 <stdio.h> #include <time.h> 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 (wcscmp(word, L"snow") == 0)
if (today.tm_year == someday.tm_year &&
today.tm_mon == someday.tm_mon &&
printf("someday is today!!!"); } ,,,

get the current year ----- #include <stdio.h> #include <time.h> 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 <stdio.h> #include <time.h> 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); } ,,,

Strftime ‹↑›

print a nicely formatted date with strftime ----- #include <stdio.h> #include <time.h> int main() { time_t now = time(NULL); char display[200]; strftime(display, 199, "%d/%m/%Y %H:%M", localtime(&now)); printf("now the date is: %s", display); 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);

today.tm_mday == someday.tm_mday)

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 <stdio.h> #include <time.h> 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 <stdio.h> #include <time.h> 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 <stdio.h> #include <time.h> 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 <stdio.h>
    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 <wchar.h>
   #include <locale.h>
   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 <wchar.h>
   #include <locale.h>
   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 <stdio.h>
    #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 ‹↑›

some strptime format string example
%d/%m%/Y - 31/2/2012

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 printf
%s - any space delimited string
%127s - a string maximum of 127 characters
etc

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 <stdio.h> 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 <stdio.h> int main() { char word[128]; FILE * fp = stdin;

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 ab or c
printf("%s\n", word); } } ,,,

a simple 'interpreter' loop with scanf ---- #include <stdio.h> int main() { char line[128]; while (1) { scanf("%127[^\n]%*c", line); printf("%s\n", line);

while (fscanf(fp, "%127s", word) == 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 <wchar.h>
   #include <locale.h>
   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 ‹↑›

if (strcmp(line, "quit") == 0) exit(1);

read a text file character by character.,


    #include <stdio.h>
    #include <stdlib.h>

    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 <stdio.h>
    #include <stdlib.h>
    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 <stdio.h>
    #include <stdlib.h>
    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 <stdio.h>
    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 <stdio.h>
    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 <stdio.h>
    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 <stdio.h>
    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 ‹↑›

www: http://tldp.org/HOWTO/Program-Library-HOWTO/more-examples.html
c files can be organised in modules, with header files

    /* file: test.c */
    #include <stdio.h>
    #include "header.h"
    char * AnotherString = "Hello Everyone";

    main ()
    {
      printf("running test.c...\n");
      ffTest(TEXT);
      printf("Finished.\n");
    }

    /* file: ffTest.c */
    #include <stdio.h>
    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

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

a simple daytime client using bsd sockets ------- #include <sys/socket.h> #include <arpa/inet.h> #include <stdio.h> #include <unistd.h> #include <time.h> #include <string.h> #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 <sys/socket.h> #include <stdio.h> #include <unistd.h> #include <netinet/in.h> #include <netdb.h> #include <string.h> //#include <arpa/inet.h> 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);

type of sockets
SOCK_STREAM - tcp/ip
SOCK_DGRAM - udp
RAW? - raw
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 (charRead==0) return;
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,

if (hostinfo == NULL) {
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 <stdio.h>
   #include <stdlib.h>
   #include <portaudio.h>
   #include <sndfile.h>
   
   #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 <stdio.h>

   #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 <stdio.h> #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 <ncurses.h>
   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 <ncurses.h> #include <stdlib.h>

int main(int argc, char *argv[]) { initscr();

sizeof(struct sockaddr_in))==-1) {
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.

if(has_colors() == FALSE) {

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 <gtk/gtk.h>

     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 <gtk/gtk.h>

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 <gtk/gtk.h>

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 <gtk/gtk.h>

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 <gtk/gtk.h>

    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 <gtk/gtk.h>

    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 <gdk-pixbuf/gdk-pixbuf.h>
   #include <gtk/gtk.h>

   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 <gtk/gtk.h>
   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 <gtk/gtk.h>

    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 <gtk/gtk.h>

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 <gtk/gtk.h>
   
   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 <gtk/gtk.h>

    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 ‹↑›

gtk components
glib - non graphical utility functions (strings etc)
pango - text and font rendering (international)
gdk - drawing
gdkpixbuf - manipulate images
atk - accessibility

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": <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 ‹↑›

www: 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 %<cr>

compile the current c file with tcc minimalist c compiler

 map ,tcc :!tcc %<cr>

a vim map to compile and run a 'c' program between '---' and ',,,'

 map ,scc :?^ *---?+1,/^ *,,,/-1w! test.c \| !gcc test.c; ./a.out<cr>

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 <stdio.h> \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 <cr>

indent text between --- and ,,, with astyle

 map ,ci :?^ *---?+1,/^ *,,,/-1! astyle -s2 <bar> sed 's/^/   /'<cr>

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 <cr>

DOCUMENT-NOTES:

header file search folders
/usr/local/include -
libdir/gcc/target/version/include -
/usr/target/include -
/usr/include -