To compile an executable (myexecutable) from a C source code (code.c:
$ gcc -o myexecutable code.c
Main options
-g
tells GCC to include debug information into the binary.
-Wall
Warning all : print every warning. This switch is used by the C compiler only.
-Idir dir
Look for included header files (like in #include <myheader.h>) in directory dir. This switch is used by the C preprocessor only.
-llib lib
Link to library lib; here libxml2, used by the linker.
make
To compile an executable from a C source code using the make command, create a makefile file as follows:
makefile
CFLAGS=-Wall-gclean:rm-fcode
Warning
Notice that TAB should be used to indent lines under the clean section, instead of SPACE.
Then compile using make as follows:
$ make code
cc -Wall -g code.c -o code
Notice that the above makefile template provides a clean method:
$ make clean
rm -f code
Windows
On Windows, I recommend MinGW. Most of the advanced IDEs (e.g. Microsoft Visual Studio) will also embed their own compilers.
Arguments
Source
Run
#include<stdio.h>intmain(intargc,char*argv[]){inti;printf("Name of executable: %s\n",argv[0]);if(argc<2){printf("No argument\n");}else{printf("%d argument(s)\n",argc-1);for(i=0;i<argc-1;i++){printf("- arg %d: %s\n",i+1,argv[i+1]);}}return0;}
$ ./code
Name of executable: ./code
No argument
$ ./code abc
Name of executable: ./code
1 argument(s)
- arg 1: abc
$ ./code abc 123
Name of executable: ./code
2 argument(s)
- arg 1: abc
- arg 2: 123
Note
Like in many other languages, argv[0] is the name of the executable itself. Hence, our loop begins at the 2nd argument, which is actually the 1st real argument our program is provided with.
C Data Types
Integer types
Type
Storage size*
Value range*
char
1 byte
-128 to 127 or 0 to 255
unsigned char
1 byte
0 to 255
signed char
1 byte
-128 to 127
int
2 or 4 bytes
-32,768 to 32,767 or -2,147,483,648 to 2,147,483,647
unsigned int
2 or 4 bytes
0 to 65,535 or 0 to 4,294,967,295
short
2 bytes
-32,768 to 32,767
unsigned short
2 bytes
0 to 65,535
long
4 bytes
-2,147,483,648 to 2,147,483,647
unsigned long
4 bytes
0 to 4,294,967,295
(*) May vary depending on the environment.
Floating-point types
Type
Storage size
Value range
Precision
float
4 byte
1.2E-38 to 3.4E+38
6 decimal places
double
8 byte
2.3E-308 to 1.7E+308
15 decimal places
long double
10 byte
3.4E-4932 to 1.1E+4932
19 decimal places
Working with strings
Initialization
Strings
Source
Run
#include<stdio.h>intmain(intargc,char*argv[]){// Common ways to declare/initialize stringscharwelcome[]="Hello world!";// automatic sizingcharyourname[21];// Size of 20 chars + trailing null charyourcolor[11];// Size of 10 chars + trailing nullchar*myname="Sebastien";// Make read-only string// Less common way to initialize stringcharmycolor[]={'b','l','u','e','\0'};printf("%s\n",welcome);printf("What is your name? ");scanf("%20s",yourname);printf("What is your favorite color? ");scanf("%10s",yourcolor);printf("Hello %s. Your favorite color is %s\n",yourname,yourcolor);printf("BTW, my name is %s and my favorite color is %s.\n",myname,mycolor);return0;}
$ ./code
Hello world!
What is your name? Alice
What is your favorite color? green
Hello Alice. Your favorite color is green
BTW, my name is Sebastien and my favorite color is blue.
Array of strings
Source
Run
#include<stdio.h>intmain(intargc,char*argv[]){char*colors[]={"red","blue","green","white","black","yellow"};inti;printf("Size of array: %ld\n",sizeof(colors));printf("Size of 1st item in array: %ld\n",sizeof(colors[0]));for(i=0;i<sizeof(colors)/sizeof(colors[0]);i++){printf("- %s\n",colors[i]);}return0;}
Size of array: 48
Size of 1st item in array: 8
- red
- blue
- green
- white
- black
- yellow
String pointer
Source
Output
#include<stdio.h>#include<string.h>intmain(intargc,char*argv[]){charstr[]="hello";// my stringchar*pStr=str;// pointer of my stringinti=0;for(i=0;i<strlen(str);i++){// show each character of my string, both with indexed value and with pointer valueprintf("%c %c\n",str[i],*(pStr+i));}return0;}
h h
e e
l l
l l
o o
Space
What happens in case we provide a string that contains a space?
$ ./code
What is your name? Albert Farnsworth
Hello Albert
BTW, my name is: Sebastien
A space is saved in memory as 0x00 which is interpreted as a NULL character to terminate the string. Hence, in memory, we have:
#include<stdio.h>intmain(intargc,char*argv[]){char*names[]={"Etch","Lenny","Squeeze","Wheezy","Jessie","Stretch"};printf("Testing version is now: %s\n",names[5]);return0;}
Testing version is now: Stretch
*ptr
the value of whatever ptr is pointed at
#include<stdio.h>intmain(){inta=15;int*b=NULL;b=&a;printf("Address of a: %p\n",b);printf("Value at address of a: %d\n",*b);return0;}
Address of a: 0xffe447c8
Value at address of a: 15
&thing
the address of thing
*(ptr + i)
the value of (whatever ptr is pointed at plus i)
#include<stdio.h>intmain(intargc,char*argv[]){intt[3]={8,12,15};printf("t is a pointer on the 1st item of my array. Address: %p\n",t);printf("The 2nd item of my array is: %d\n",*(t+1));return0;}
t is a pointer on the 1st item of my array. Address: 0xffcd8ed4
The 2nd item of my array is: 12
type *ptr = &thing
a pointer of type named ptr set to the address of thing
#include<stdio.h>intmain(intargc,char*argv[]){inttable[3]={8,12,15};int*pTable=table;printf("Pointing to 1st item. Address: %p\n",pTable);printf("Value of item pointed to by pTable: %d\n",*pTable);pTable++;printf("Now pointing to 2nd item. Address: %p\n",pTable);printf("Value of item pointed to by pTable: %d\n",*pTable);return0;}
Pointing to 1st item. Address: 0xffa25e50
Value of item pointed to by pTable: 8
Now pointing to 2nd item. Address: 0xffa25e54
Value of item pointed to by pTable: 12
int and char pointers
Source
Run
#include<stdio.h>intmain(intargc,char*argv[]){intversions[]={4,5,6,7,8,9};char*names[]={"Etch","Lenny","Squeeze","Wheezy","Jessie","Stretch"};int*current_version=versions;char**current_name=names;intcount=sizeof(versions)/sizeof(versions[0]);inti=0;for(i=0;i<count;i++){printf("Version %d has code name %s (index).\n",versions[i],names[i]);printf("Version %d has code name %s (pointer index).\n",current_version[i],current_name[i]);printf("Version %d has code name %s (pointer).\n",*(current_version+i),*(current_name+i));printf("-----\n");}return0;}
$ ./code
Version 4 has code name Etch (index).
Version 4 has code name Etch (pointer index).
Version 4 has code name Etch (pointer).
-----
Version 5 has code name Lenny (index).
Version 5 has code name Lenny (pointer index).
Version 5 has code name Lenny (pointer).
-----
Version 6 has code name Squeeze (index).
Version 6 has code name Squeeze (pointer index).
Version 6 has code name Squeeze (pointer).
-----
Version 7 has code name Wheezy (index).
Version 7 has code name Wheezy (pointer index).
Version 7 has code name Wheezy (pointer).
-----
Version 8 has code name Jessie (index).
Version 8 has code name Jessie (pointer index).
Version 8 has code name Jessie (pointer).
-----
Version 9 has code name Stretch (index).
Version 9 has code name Stretch (pointer index).
Version 9 has code name Stretch (pointer).
-----
For reference, below is the 32bit disassembled version:
.text:0804841B; int __cdecl main(int argc, const char **argv, const char **envp).text:0804841Bpublicmain.text:0804841Bmainprocnear.text:0804841B.text:0804841Bnames=byteptr-48h.text:0804841Bversions=byteptr-30h.text:0804841Bcount=dwordptr-18h.text:0804841Bcurrent_name=dwordptr-14h.text:0804841Bcurrent_version=dwordptr-10h.text:0804841Bi=dwordptr-0Ch.text:0804841Bvar_4=dwordptr-4.text:0804841Bargc=dwordptr0Ch.text:0804841Bargv=dwordptr10h.text:0804841Benvp=dwordptr14h.text:0804841B.text:0804841Bleaecx,[esp+4].text:0804841Fandesp,0FFFFFFF0h.text:08048422pushdwordptr[ecx-4].text:08048425pushebp.text:08048426movebp,esp.text:08048428pushecx.text:08048429subesp,44h.text:0804842Cmovdwordptr[ebp+versions],4.text:08048433movdwordptr[ebp+versions+4],5.text:0804843Amovdwordptr[ebp+versions+8],6.text:08048441movdwordptr[ebp+versions+0Ch],7.text:08048448movdwordptr[ebp+versions+10h],8.text:0804844Fmovdwordptr[ebp+versions+14h],9.text:08048456movdwordptr[ebp+names],offsetaEtch; "Etch".text:0804845Dmovdwordptr[ebp+names+4],offsetaLenny; "Lenny".text:08048464movdwordptr[ebp+names+8],offsetaSqueeze; "Squeeze".text:0804846Bmovdwordptr[ebp+names+0Ch],offsetaWheezy; "Wheezy".text:08048472movdwordptr[ebp+names+10h],offsetaJessie; "Jessie".text:08048479movdwordptr[ebp+names+14h],offsetaStretch; "Stretch".text:08048480leaeax,[ebp+versions].text:08048483mov[ebp+current_version],eax.text:08048486leaeax,[ebp+names].text:08048489mov[ebp+current_name],eax.text:0804848Cmov[ebp+count],6.text:08048493mov[ebp+i],0.text:0804849Amov[ebp+i],0.text:080484A1jmploc_8048542.text:080484A6; ---------------------------------------------------------------------------.text:080484A6.text:080484A6loc_80484A6:.text:080484A6moveax,[ebp+i].text:080484A9movedx,dwordptr[ebp+eax*4+names].text:080484ADmoveax,[ebp+i].text:080484B0moveax,dwordptr[ebp+eax*4+versions].text:080484B4subesp,4.text:080484B7pushedx.text:080484B8pusheax.text:080484B9pushoffsetformat; "Version %d has code name %s (index).\n".text:080484BEcall_printf.text:080484C3addesp,10h.text:080484C6moveax,[ebp+i].text:080484C9leaedx,ds:0[eax*4].text:080484D0moveax,[ebp+current_name].text:080484D3addeax,edx.text:080484D5movedx,[eax].text:080484D7moveax,[ebp+i].text:080484DAleaecx,ds:0[eax*4].text:080484E1moveax,[ebp+current_version].text:080484E4addeax,ecx.text:080484E6moveax,[eax].text:080484E8subesp,4.text:080484EBpushedx.text:080484ECpusheax.text:080484EDpushoffsetaVersionDHasC_0; "Version %d has code name %s (pointer in"....text:080484F2call_printf.text:080484F7addesp,10h.text:080484FAmoveax,[ebp+i].text:080484FDleaedx,ds:0[eax*4].text:08048504moveax,[ebp+current_name].text:08048507addeax,edx.text:08048509movedx,[eax].text:0804850Bmoveax,[ebp+i].text:0804850Eleaecx,ds:0[eax*4].text:08048515moveax,[ebp+current_version].text:08048518addeax,ecx.text:0804851Amoveax,[eax].text:0804851Csubesp,4.text:0804851Fpushedx.text:08048520pusheax.text:08048521pushoffsetaVersionDHasC_1; "Version %d has code name %s (pointer).\"....text:08048526call_printf.text:0804852Baddesp,10h.text:0804852Esubesp,0Ch.text:08048531pushoffsets; "-----".text:08048536call_puts.text:0804853Baddesp,10h.text:0804853Eadd[ebp+i],1.text:08048542.text:08048542loc_8048542:.text:08048542moveax,[ebp+i].text:08048545cmpeax,[ebp+count].text:08048548jlloc_80484A6.text:0804854Emoveax,0.text:08048553movecx,[ebp+var_4].text:08048556leave.text:08048557leaesp,[ecx-4].text:0804855Aretn.text:0804855Amainendp
Send pointer to function
Source
Run
#include<stdio.h>voidtriple(int*pNum);intmain(intargc,char*argv[]){intnum=5;printf("Num before function: %d\n",num);// Send address of num to functiontriple(&num);printf("Num after function: %d\n",num);return0;}voidtriple(int*pNum){// Multiply by 3 value pointed by pointer*pNum*=3;}
$ ./code
Num before function: 5
Num after function: 15
Below is the disassembled code:
.text:080483EB; int __cdecl main(int argc, const char **argv, const char **envp).text:080483EBpublicmain.text:080483EBmainprocnear.text:080483EB.text:080483EBnum=dwordptr-0Ch.text:080483EBvar_4=dwordptr-4.text:080483EBargc=dwordptr0Ch.text:080483EBargv=dwordptr10h.text:080483EBenvp=dwordptr14h.text:080483EB.text:080483EBleaecx,[esp+4].text:080483EFandesp,0FFFFFFF0h.text:080483F2pushdwordptr[ecx-4].text:080483F5pushebp.text:080483F6movebp,esp.text:080483F8pushecx.text:080483F9subesp,14h.text:080483FCmov[ebp+num],5.text:08048403moveax,[ebp+num].text:08048406subesp,8.text:08048409pusheax; eax = 5 (initial value).text:0804840Apushoffsetformat; "Num before function: %d\n".text:0804840Fcall_printf; print 5 (initial value).text:08048414addesp,10h.text:08048417subesp,0Ch.text:0804841Aleaeax,[ebp+num]; Address of num sent to function.text:0804841Dpusheax.text:0804841Ecalltriple.text:08048423addesp,10h.text:08048426moveax,[ebp+num]; eax = Initial value multiplied by 3 by function.text:08048429subesp,8.text:0804842Cpusheax; eax = 5*3 = 15.text:0804842DpushoffsetaNumAfterFuncti; "Num after function: %d\n".text:08048432call_printf.text:08048437addesp,10h.text:0804843Amoveax,0.text:0804843Fmovecx,[ebp+var_4].text:08048442leave.text:08048443leaesp,[ecx-4].text:08048446retn.text:08048446mainendp.text:08048447; ==========================================================================================.text:08048447publictriple.text:08048447tripleprocnear.text:08048447.text:08048447pNum=dwordptr8.text:08048447.text:08048447pushebp.text:08048448movebp,esp.text:0804844Amoveax,[ebp+pNum].text:0804844Dmovedx,[eax]; edx = Value at address provided as arg to function.text:0804844Fmoveax,edx.text:08048451addeax,eax; \.text:08048453addedx,eax; / edx = Value multiplied by 3.text:08048455moveax,[ebp+pNum].text:08048458mov[eax],edx; Value multiplied by 3 put at address of pointer.text:0804845Anop.text:0804845Bpopebp.text:0804845Cretn.text:0804845Ctripleendp
=== PLAYER 1 ===
First name? Alice
Last name? Shaw
=== PLAYER 2 ===
First name? Foo
Last name? Bar
=== PLAYERS ===
Player 1: Alice Shaw
Player 2: Foo Bar
#include<stdio.h>#include<string.h>#include"main.h"intmain(intargc,char*argv[]){Playerplayer;initPlayer(&player);printf("Player: %s %s, %d years old\n",player.firstname,player.lastname,player.age);return0;}voidinitPlayer(Player*player){// Use strcpy when dealing with char// First possibility: '->' shortcutstrcpy(player->firstname,"Alice");// Second possibility pointerstrcpy((*player).lastname,"Shaw");// When dealing with int, you can just do as followsplayer->age=32;}
Player: Alice Shaw, 32 years old
Memory allocation
Dynamic vs manual memory allocation
The following example shows 2 ways of processing information in memory. The 1st one (Paul's age) uses an automatic/dynamic memory allocation whereas the 2nd one (Alice's age) is manual.
Source
Run
#include<stdio.h>#include<stdlib.h>intmain(intargc,char*argv[]){// Dynamic mem allocationintagePaul=0;// Manual mem allocationint*ageAlice=NULL;ageAlice=malloc(sizeof(int));if(ageAlice==NULL)exit(1);printf("How old is Paul? ");scanf("%d",&agePaul);printf("How old is Alice? ");scanf("%d",ageAlice);printf("Paul is %d years old and Alice is %d years old.\n",agePaul,*ageAlice);free(ageAlice);return0;}
$ ./code
How old is Paul? 33
How old is Alice? 35
Paul is 33 years old and Alice is 35 years old.
Manual allocation of array
Soiurce
Run
#include<stdio.h>#include<stdlib.h>intmain(intargc,char*argv[]){intnumKids=0;int*ageKids=NULL;inti=0;printf("How many kids do you have? ");scanf("%d",&numKids);ageKids=malloc(numKids*sizeof(int));if(ageKids==NULL)exit(1);for(i=0;i<numKids;i++){printf("How old is your kid %d? ",i+1);scanf("%d",&ageKids[i]);}printf("\nYour kids are ");for(i=0;i<numKids;i++){printf("%d ",ageKids[i]);}printf("years old.\n");free(ageKids);return0;}
$ ./code
How many kids do you have? 3
How old is your kid 1? 5
How old is your kid 2? 7
How old is your kid 3? 10
Your kids are 5 7 10 years old.