C programming. Exercises

There are many good C/C++ tutorials online. You can find one in this link.

Next, there are several examples that we will use during the lectures to talk about different aspects of C language.

You can download a ZIP with the examples here

Compilation (headers, macros...)

#include <stdio.h>

/******** QUESTIONS/TASKS *****
* 1. Compile and execute the code
* 2. Later, apply only the preprocessor  (-E flag) and redirect the output
* to a file called hello.i
* 3. What happened to the call min()?
* 4. What did the directive  #include <stdio.h> produced?
*****************/
#define N 5

#define min(x,y) ( (x<y)?x:y )
int a = 7;
int b = 9;
int main() {

 char* cad = "Hello world";
 int i;

 for (i=0;i<N;i++) {
   printf("%s \t a= %d b= %d\n",cad,a,b);
   a++;
   a = min(a,b);            
 }
 return 0;
}

Data types. Sizes

#include <stdio.h>
/**** QUESTIONS/TASKS ********
 * Compile and execute the code. 
 * 1. Why the first "printf" prints different values for the same variable 'a'?
 * 2. How large is a 'char' variable?
 * 3. Why the value of 'a' changes that much when adding 1?  
 * 4. If "long" and "double" have the same size, what's the difference?
 *****/
char a = 127;
int b = 41;
int main() {

    printf("a = %d a = %c \n", a,a);
    a++;
    printf("a = %d a = %c b=%d  b=%c\n", a,a,b,b);
    printf("Size of int: %lu\n",sizeof(int ) );
    printf("Size of char: %lu\n",sizeof( char) );
    printf("Size of float: %lu\n",sizeof(float ) );
    printf("Size of double: %lu\n",sizeof( double) );
    printf("Size of long: %lu\n",sizeof(long ) );
    printf("Size of short: %lu\n",sizeof( short) );
    printf("Size of void*: %lu\n",sizeof( void*) );

}
#include <stdio.h>


/**** QUESTIONS/TASKS ********
 * Compile and execute the code. 
 * 1. Is there a compilation problem or a execution problem?
 * 2. Why is it complaining? Fix it and compila again.
 * 3. a,b,c, y x are declared one after the other. Are their addresses consecutive in memory?
 * 4. What does the modifier "%lu" means in printf()? 
 * 5. Which address is "pc" pointed to? Is the address of any other variable? Are those two the same size?
 * 6. Does the size of "array1" matches the number of elements? Why?
 * 7. Do "cadena1" and "cadena2 "point to the same address? 
 * 8. Why sizes (according to sizeof()) of cadena1 and cadena2 are different?
 *************/

#define ARRAY_SIZE  10

int a = 7;
unsigned long b = 8;
short c;
char x;
char* pc;

int array1[ARRAY_SIZE];
int array2[a]; 

char* cadena1 = "CADENA DE CARACTERES"; 
char cadena2[] = "CADENA DE CARACTERES";
int main() {
    pc =&x;
    a = 16;
    printf("Adress of a: %p Tam: %lu \n",&a,sizeof(a));
    printf("Adress of b: %p Tam: %lu \n",&b,sizeof(b));
    printf("Adress of c: %p Tam: %lu \n",&c,sizeof(c));
    printf("Adress of x: %p Tam: %lu \n",&x,sizeof(x));
    printf("Adress of pc: %p Adress pointed by pc: %p Tam: %lu \n",&pc,pc,sizeof(pc));
    printf("Adress of array: %p Adress of elem 0: %p Tam de array: %lu \n",array1, &array1[0], sizeof(array1));
    printf("Adress of cadena1: %p Adress pointed by: %p Tam: %lu \n",&cadena1,cadena1,sizeof(cadena1));
    printf("Adress of cadena2: %p DAdress pointed by: %p Tam: %lu \n",&cadena2,cadena2,sizeof(cadena2));    
return 0;
}

Using Arrays.

#include <stdio.h>

/**** QUESTIONS/TASKS ********
 * Compile and execute the code. 
 * 1. Should we use "&list" to get the address of the array?
 * 2. What is actually stored in the address of "list"?
 * 3. Why are we including the lentgh of the array as parameter to "init_array"?
 * 4. Why the sizeof() output is different for the array in "init_array" and the one in main()?
 * 5. Why aren't we including a second parameter in init_array2?
 * 6. Do sizeof() outuput now match with the array in init_array2()?
 ***************/

#define N 5

void init_array(int array[], int size) ;
void init_array2(int array[N]);

int main(void) {
    int i,list[N];
    printf("Dir de list %p Dir de list[0]: %p  Dir de list[1]: %p. Sizeof list %lu \n",list,&list[0],&list[1],sizeof(list));

    init_array(list, N);
    for (i = 0; i < N; i++)
        printf("next: %d ", list[i]);
    printf("\n-------------------------\n");

    init_array2(list);
    for (i = 0; i < N; i++)
        printf("next: %d ", list[i]);
    printf("\n-------------------------\n");
}

void init_array(int array[], int size) { 
    int i;
    printf("Direccion de array: %p Sizeof array %lu \n", array, sizeof(array));
    for (i = 0; i < size; i++)
        array[i] = i;
    printf("Array initialized\n\n");
}

void init_array2(int array[N]) { 
    int i;
    printf("Direccion de array: %p Sizeof array %lu \n", array, sizeof(array));
    for (i = 0; i < N; i++)
        array[i] = i*2;
    printf("Array initialized\n\n");
}
#include <stdio.h>

/**** QUESTIONS/TASKS ********
 * Compile and execute the code. 
 *  1. Does the copy of the array works? Why? 
 *  2. Fix it.
 *  3. Uncommnet the call to function "tom". Compile again and execute.
 *  4. The problem that arises, is it in compilation or execution time? Why?
 *  5. Find a value for MAXVALID (greater than 4) when the problem does not happen. Why does it work?
*******************/

#define N 10
#define MAXELEM 5000
#define MAXVALID 100

void printArray(int v[],int size) {
    int i;
    printf("-------------------\n");
    for (i=0;i<size;i++)
        printf("%d ",v[i]);
    printf("\n\n");

}

void copyArray(int src[],int dst[],int size) {
    dst = src;
}

void tmo() {
    int x = -1; 
    int a[4] = {0,1,2,3};    
    int b = 10000;
    int c = -1;
    int i;

    for  (i=4;i<MAXVALID;i++)
        a[i]=i;

    printf("x %d b %d c %d\n", x,b,c);


}

int main() {
    int A[N] = {4,3,8,5,6,9,0,1,7,2};
    int B[N];

    //tmo();
    copyArray(A,B,N);
    printArray(B,N);

}

Pointers


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

/**** QUESTIONS/TASKS ********
 * Compile and execute the code. 
 * 1. Which operand should we use to declae a variable as a ponter?
 * 2. How do we obtain the address of a variable?
 * 3. How do we read/write into the address pointed by a pointer? 
 * 4. There ¡s a bug in the code. Is it a compile-time or executiontime errror? Why does it happen?
  ***********/
int c = 7;
int main(void) {

    int *ptr;
    printf("Address of ptr %p. ptr apunta a %p. Address of c: %p Valor of c %d\n",&ptr,ptr,&c,c);   

    ptr = &c;
    printf("Address of ptr %p,. ptr apunta a %p. Address of c: %p Value of c %d\n",&ptr,ptr,&c,c);  

    *ptr=4;
    printf("ptr apunta a %p. Content of address of ptr: %d Address of c: %p Value of c %d\n",ptr,*ptr,&c,c);    

    ptr =  (int*) 0x600a48;
    printf("Address of ptr %p. Value of c %d\n",ptr,c); 

    *ptr =13;
    printf("Address of ptr %p. Value of c %d\n",ptr,c); 

return 0;

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

/**** QUESTIONS/TASKS ********
 * Compile and execute the code. 
 *  1. How many bytes are allocated in memory with the malloc() call?
 *  2. Which are the addresses of the first and last bytes of the allocated area?
 *  3. Why the content of the address pointed by "ptr" is 7 and not 5 in the first printf()?
 *  4. Why the content of ptrg[1] is modified after the sentence *ptr2=15 ?
 *  5. Suggest two different ways of writting the value 13 in the address of ptr[100] 
 *  6. There is a bug in the code. Even if nothing goes wrong,the bug is there. Where?
 *  ***********/
int nelem;

int main(void) {
    int *ptr;
    int * ptr2; 

    nelem = 127;
    ptr = (int*) malloc(nelem*sizeof(int));
    *ptr = 5;
    ptr[0] = 7;
    ptr2 = ptr;

    printf("Address pointed by ptr %p. Content of that address: %d \n",ptr,*ptr);   

    ptr[1] = 10;    
    printf("Address pointed by ptr[1] %p. Content of that address: %d \n",&ptr[1],ptr[1]);  

    ptr2++;
    *ptr2 = 15;
    printf("Address pointed by ptr[1] %p. Content of that address: %d \n",&ptr[1],ptr[1]);  


    free(ptr);  
    *ptr = 3;
    printf("Address pointed by ptr %p. Content of that address: %d \n",ptr,*ptr);   
}
#include <stdio.h>
#include <stdlib.h>
/**** QUESTIONS/TASKS ********
 * Compile and execute the code. 
 *  1. Why the value of ptr[13] is changed after the sentence ptr = &c;
 *  2. This code has (at least) one bug. Compile or run-timer error? Why?
 *  3. What happens with the memory allocated by malloc()  after the assignment ptr=&c? 
 *     How can we reach that memory again? How can we free it?
 *  ***********/
int nelem;
int c;
int main(void) {
    int *ptr;
    int i;
    c = 37; 
    nelem = 127;
    ptr = (int*) malloc(nelem*sizeof(int));
    for (i=0; i<nelem; i++)
        ptr[i] = i;

    printf("ptr[0]= %d ptr[13]=%d \n",ptr[0],ptr[13]);  

    ptr = &c;
    printf("ptr[0]= %d ptr[13]=%d \n",ptr[0],ptr[13]);  

    free(ptr);
}
#include <stdio.h>
#include <stdlib.h>
/**** QUESTIONS/TASKS ********
 * Compile and execute the code. 
 *  1. Why the second printf() prints a different value for 'd'?
 *  2. What is 'f'? A variable? A function?
 *  3. Use the function 'opera()' to perform the first addition. Then, use it again to perform a substraction.
 *  4. Using typedef, build a type called ptrToFunc with the same prototype thatn 'f'
 *  5. Creat a function 'choose()' that will return, alternatively, a pointer to "add()" and "sub()" 
 *     every time it is called
 *  ***********/

int add (int x, int y);
int sub(int x, int y);

int (*f)(int a, int b);

int add(int x, int y) {
    return x+y;
}

int sub(int x, int y) {
    return x-y;
}

int opera(int x, int y, int (*g)(int, int)) {
    return g(x,y);
}

int main(void) {

    int a = 12;
    int b =  8;
    int c,d;

    f = add;
    c = add(a,b);
    d = f(a,b);
    printf("c = %d d= %d \n",c,d);  
    f = sub;
    d = f(a,b);
    printf("c = %d d= %d \n",c,d);
}

Arguments

#include <stdio.h>
/**** QUESTIONS/TASKS ********
 * Compile and execute the code. 
 * 1. Why the value of 'xc' is not changed after the call to sumC()? 
 *     Where do the write operations happen?
 * 2. Comment  the two forwarded declarations of sum() and sumC(). Compile again. What happens?
 *******************/
/* Struct type */
struct _complex_ {
    float re;
    float im;
};

/* Forward declarations */
int sum(int a, int b);
struct _complex_  sumC( struct _complex_ a,  struct _complex_ b);


int main(void){
    int x = 4,y = 5;
    struct _complex_  xc = {.re = 1.0, .im = 2.0};
    struct _complex_  yc = {.re = 3.0, .im = 1.0};
    struct _complex_  zc; 

    zc = sumC(xc,yc);

    int total = sum(x,y); 

    printf("Suma de complejos. (%f,%f i) + (%f,%f i) =(%f,%f i)\n",xc.re,xc.im,yc.re,yc.im,zc.re,zc.im);
    printf("Suma de enteros:  x +y = %d + %d = %d \n",x,y, total);
    return 0;
}

int sum(int x, int y) {  
    int c;
    c = x +y;
    x = 7;
    y =3;  
    return c;         
}


struct _complex_  sumC( struct _complex_ a,  struct _complex_ b) {
        struct _complex_ r;
        r.re = a.re + b.re;
        r.im = a.im + b.im;
        // Try to change the first parameter
        a.re = 12.5;
        a.im = 13.4;
        return r;
}
#include <stdio.h>
/**** QUESTIONS/TASKS ********
 * Compile and execute the code. 
 * 1. Why does the value of 'y' changes after the call to sum()?
 * 2. Why sometimes we use operator '.' and other times '->'?
 * 3. Why the vauue of 'zc' gets wrong without further using it in the code?
 * 4. Fix the code to avoid the bug in 'zc' shown in previous point
 *******************/
struct _complex_ {
    float re;
    float im;
};

int sum(int *pa, int *pb);
struct _complex_ * sumC( struct _complex_ *a,  struct _complex_ *b);


int main(void){
    int x = 4,y = 5;
    int* ptr = &y;
    struct _complex_  xc = {.re = 1.0, .im = 2.0};
    struct _complex_  yc = {.re = 3.0, .im = 1.0};
    struct _complex_  *zc; 


    printf("Complex addition (%f,%f i) + (%f,%f i) = ",     xc.re,xc.im,yc.re,yc.im);
    zc = sumC(&xc,&yc);
    printf("(%f,%f i)\n",zc->re,zc->im);
    int total = sum(&x,ptr); 

    printf("Complex addition:  x +y = %d + %d = %d \n",x,y, total);
    printf("xc = (%f,%f i)  yc = (%f,%f i) zc = (%f,%f i)\n",xc.re,xc.im,yc.re,yc.im,zc->re,zc->im);
    return 0;
}

int sum(int *pa, int *pb) {  
   /* args passed by reference */
  int c = *pa + *pb;
  int buf[256] = {0};
  *pa = 7;
  *pb = 8;  
   return c;      /* return by value */
}


struct _complex_ * sumC( struct _complex_* a,  struct _complex_* b) {
        struct _complex_ r;
        r.re = a->re + b->re;
        r.im = a->im + b->im;
        a->re = 12.5;
        a->im = 13.4;
        return &r;
}

Strings

#include <stdio.h>
#include <string.h>

/**** QUESTIONS/TASKS ********
 * Compile and execute the code. 
 * 1. The code has a bug. Compile or run-time? Why?
 * Fix the bug commenting the line(s) that produce it. Compile and execute again. 
 * 2. Which is the address of letter 'B' in the chain "Bonjour"? And letter 'j'?
 * 3. After the assignment p=msg2; how can we get back the address of "Bonjour"?
 * 4. Why the length of strings 'p' and 'msg2' are 2 after the third assignment?
 *    3 bytes are assigned to 'p', but then the length is only 2 !!
 * 5. Why strlen() returns a different value than sizeof()?
 * 6. Why the string stored in 'msg' in line 36 is bad-printed in the last printf()?
 ************** */
int main() {

char msg[10]; /* array of 10 chars */
char *p;          /* pointer to a char */

char msg2[28]="Hello";  /* msg2 = 'H' 'e' 'l' 'l' 'o' '\0' */

    p   = "Bonjour"; 
    printf("msg: %s, p: %s, msg2: %s\n",msg,p,msg2);
    printf("dir de msg: %p, dir de p: %p, dir de msg2: %p\n",msg,p,msg2);

    p = msg2;
    printf("msg: %s, p: %s, msg2: %s\n",msg,p,msg2);
    printf("dir de msg: %p, dir de p: %p, dir de msg2: %p\n",msg,p,msg2);

    p[0] = 'H', p[1] = 'i',p[2]='\0';
    printf("msg: %s, p: %s, msg2: %s\n",msg,p,msg2);
    printf("msg len: %lu p len %lu msg2 len %lu\n", strlen(msg),strlen(p),strlen(msg2));
    printf("msg size: %lu p size %lu msg2 size %lu\n", sizeof(msg),sizeof(p),sizeof(msg2));

    msg[0] = 'B', msg[1] = 'y';
    printf("msg: %s, p: %s, msg2: %s\n",msg,p,msg2);

    msg = "Goodbye";
    printf("msg: %s, p: %s, msg2: %s\n",msg,p,msg2);
}
#include <stdio.h>
#include <string.h>

/**** QUESTIONS/TASKS ********
 * Compile and execute the code. 
 * 1. The code of fcuntion 'copy' does not work. Why?
 * 2. Use now 'copy2()'. Does the copy actually work?
 * 3. Suggest a valid implementation for a copy
 * 4. What does function "mod" do? 
 * 5. Uncomment last line of code (call to mod()). Compile and execute. Why is there an error now?
 ************** */

void copy2(char* org, char** dst) {
    *dst = org;
}

void copy(char* org, char* dst) {
    dst = org;
}

void mod(char* org, char* dst) {
    int i;

    for (i=0;i<strlen(org);i++)
        dst[i] = org[i] - 32;

}

int main() {

    char* cad1 = "original";          
    char* cad2 = "other";
    char cad3[32];

    copy(cad1,cad2);
    //copy2(cad1,&cad2);
    printf("cad1 %s cad2 %s\n", cad1,cad2);

    mod(cad1,cad3);
    printf("cad1 %s cad3 %s\n", cad1,cad3);

    //mod(cad1,cad1);
}

Bitwaise operations

#include <stdio.h>

/**** QUESTIONS/TASKS ********
 * Compile and execute the code. 
 * Study the syntax of the different bit-level operators
 * and make sure you understand  the result of every operation
 ************** */

int a,b,c;

int main() {

    a = 7;
    b = 9;
    c = a & b;
    printf("%x AND %x = %x\n",a,b,c);

    c= a | b;
    printf("%x OR %x = %x\n",a,b,c);

    c = a ^ b;
    printf("%x XOR %x = %x\n",a,b,c);

    c = ~a;
    printf("NOT %x = %x\n",a,c);

    c = a << 2;
    printf(" %x << 2 = %x\n",a,c);

    c = a >> 1;
    printf(" %x >> 1 = %x\n",a,c);

    c = a & 0xFB;
    printf(" %x bit 2 to 0 -> %x\n",a,c);

    c = a | 0x40;
    printf(" %x bit 6 to 1 -> %x\n",a,c);

    c = (a & 0x1C) >> 2;
    printf("bits 4-3-2 of %x: %x\n",a,c);   
}
#include <stdio.h>

/**** QUESTIONS/TASKS ********
 * Compile and execute the code. 
 * 1. Why the assignment using pointer 'p' does not overwrite completely 'a'?
 * 2. How is modified the address pointed by 'p' after the assignment p=p+1
 * 3. How would it be different if 'p' is declared as 'short *'
 *
 ************** */
int a = 3;
int b;
char * p;
int c;
int main() {

    printf("a = %x Address of a: %p \n",a,&a);
    p = (char*) &a;
    p=p+1;
    *p= 0x1f;
    printf("a = %x. Address pointed by p:%p \n",a,p);

    a = 3;
    b = 0x00001f00;
    a= a | b;

    printf("a = %x. Address pointed by p:%p \n",a,p);
}