Steven-Jaro
☰ Menu

Chapter 1: Introduction to C tutorial

First basic exercises

Continuing with the C manual, it shows how to do basic arithmetic with a program that converts Fahrenheit values to Celsius. I decided to read the code carefully and write the implementation from scratch on my own without copying the book's directly:

openjazz$ vim main.c
    
#include <stdio.h>

int ftoc(int f)
{
        int c = (f - 32) / 1.8;
        return c;
}


int main()
{
        printf("De Fahrenhet a Celcius\n");

        int fahrenheit = 0;
        int paso = 10;
        int upper = 300;
        int lower = -300;
        int celcius = 0;


        for(fahrenheit=lower; fahrenheit <= upper; fahrenheit = fahrenheit + paso)
        {
                celcius = ftoc(fahrenheit);
                printf("Fahrenheit: %d  Celcius: %d\n", fahrenheit, celcius);
        }

        return 0;
}
    
openjazz$ clang main.c
openjazz$ ./
a.out   main.c
openjazz$ ./a.out
De Fahrenhet a Celcius
Fahrenheit: -300  Celcius: -184
Fahrenheit: -290  Celcius: -178
Fahrenheit: -280  Celcius: -173
Fahrenheit: -270  Celcius: -167
Fahrenheit: -260  Celcius: -162
Fahrenheit: -250  Celcius: -156
Fahrenheit: -240  Celcius: -151
Fahrenheit: -230  Celcius: -145
Fahrenheit: -220  Celcius: -140
Fahrenheit: -210  Celcius: -134
Fahrenheit: -200  Celcius: -128
Fahrenheit: -190  Celcius: -123
Fahrenheit: -180  Celcius: -117
Fahrenheit: -170  Celcius: -112
Fahrenheit: -160  Celcius: -106
Fahrenheit: -150  Celcius: -101
Fahrenheit: -140  Celcius: -95
Fahrenheit: -130  Celcius: -90
Fahrenheit: -120  Celcius: -84
Fahrenheit: -110  Celcius: -78
Fahrenheit: -100  Celcius: -73
Fahrenheit: -90  Celcius: -67
Fahrenheit: -80  Celcius: -62
Fahrenheit: -70  Celcius: -56
Fahrenheit: -60  Celcius: -51
Fahrenheit: -50  Celcius: -45
Fahrenheit: -40  Celcius: -40
Fahrenheit: -30  Celcius: -34
Fahrenheit: -20  Celcius: -28
Fahrenheit: -10  Celcius: -23
Fahrenheit: 0  Celcius: -17
Fahrenheit: 10  Celcius: -12
Fahrenheit: 20  Celcius: -6
Fahrenheit: 30  Celcius: -1
Fahrenheit: 40  Celcius: 4
Fahrenheit: 50  Celcius: 10
Fahrenheit: 60  Celcius: 15
Fahrenheit: 70  Celcius: 21
Fahrenheit: 80  Celcius: 26
Fahrenheit: 90  Celcius: 32
Fahrenheit: 100  Celcius: 37
Fahrenheit: 110  Celcius: 43
Fahrenheit: 120  Celcius: 48
Fahrenheit: 130  Celcius: 54
Fahrenheit: 140  Celcius: 60
Fahrenheit: 150  Celcius: 65
Fahrenheit: 160  Celcius: 71
Fahrenheit: 170  Celcius: 76
Fahrenheit: 180  Celcius: 82
Fahrenheit: 190  Celcius: 87
Fahrenheit: 200  Celcius: 93
Fahrenheit: 210  Celcius: 98
Fahrenheit: 220  Celcius: 104
Fahrenheit: 230  Celcius: 110
Fahrenheit: 240  Celcius: 115
Fahrenheit: 250  Celcius: 121
Fahrenheit: 260  Celcius: 126
Fahrenheit: 270  Celcius: 132
Fahrenheit: 280  Celcius: 137
Fahrenheit: 290  Celcius: 143
Fahrenheit: 300  Celcius: 148
    

The most interesting thing I saw, coming from Java, is the way strings and variables are concatenated. The book shows us the following concatenation example: printf("%3.0f %6.1f\n", fahr, celsius); and also gives us this table, which will obviously be a reference for the future since I plan to print text constantly:

%d      print as decimal integer
%6d     print as decimal integer, at least 6 characters wide
%f      print as floating point
%6f     print as floating point, at least 6 characters wide
%.2f    print as floating point, 2 characters after decimal point
%6.2f   print as floating point, at least 6 wide and 2 after decimal point
    

If you are following the manual, you will notice I jumped ahead on some steps, such as using functions and for, because some things are almost the same in Java, so I decided to implement them right away. I will mainly highlight the knowledge that is very new to me.

Symbolic constants

This is a new concept for me. Apparently in C you can declare a kind of constant outside any function, which makes me assume these variables are accessible from any function. To practice them, I decided to replace the variables in my implementation with symbolic constants. I added the variable n just to keep count of the for loop.

#include <stdio.h>

#define PASO 10
#define UPPER 300
#define LOWER -300

int ftoc(int f)
{
        int c = (f - 32) / 1.8;
        return c;
}


int main()
{
        printf("De Fahrenhet a Celcius\n");

        int fahrenheit = 0;
/*
        int paso = 10;
        int upper = 300;
        int lower = -300;
*/
        int celcius = 0;
	int n = 0;

        for(fahrenheit=LOWER; fahrenheit <= UPPER; fahrenheit = fahrenheit + PASO)
        {
                celcius = ftoc(fahrenheit);
                printf("N: %d Fahrenheit: %d  Celcius: %d\n", n, fahrenheit, celcius);
		n = n+1;
        }

        return 0;
}
    
openjazz$ clang main.c  
openjazz$ ./a.out       
De Fahrenhet a Celcius
N: 0 Fahrenheit: -300  Celcius: -184
N: 1 Fahrenheit: -290  Celcius: -178
N: 2 Fahrenheit: -280  Celcius: -173
N: 3 Fahrenheit: -270  Celcius: -167
N: 4 Fahrenheit: -260  Celcius: -162
N: 5 Fahrenheit: -250  Celcius: -156
N: 6 Fahrenheit: -240  Celcius: -151
N: 7 Fahrenheit: -230  Celcius: -145
N: 8 Fahrenheit: -220  Celcius: -140
N: 9 Fahrenheit: -210  Celcius: -134
N: 10 Fahrenheit: -200  Celcius: -128
N: 11 Fahrenheit: -190  Celcius: -123
N: 12 Fahrenheit: -180  Celcius: -117
N: 13 Fahrenheit: -170  Celcius: -112
N: 14 Fahrenheit: -160  Celcius: -106
N: 15 Fahrenheit: -150  Celcius: -101
N: 16 Fahrenheit: -140  Celcius: -95
N: 17 Fahrenheit: -130  Celcius: -90
N: 18 Fahrenheit: -120  Celcius: -84
N: 19 Fahrenheit: -110  Celcius: -78
N: 20 Fahrenheit: -100  Celcius: -73
N: 21 Fahrenheit: -90  Celcius: -67
N: 22 Fahrenheit: -80  Celcius: -62
N: 23 Fahrenheit: -70  Celcius: -56
N: 24 Fahrenheit: -60  Celcius: -51
N: 25 Fahrenheit: -50  Celcius: -45
N: 26 Fahrenheit: -40  Celcius: -40
N: 27 Fahrenheit: -30  Celcius: -34
N: 28 Fahrenheit: -20  Celcius: -28
N: 29 Fahrenheit: -10  Celcius: -23
N: 30 Fahrenheit: 0  Celcius: -17
N: 31 Fahrenheit: 10  Celcius: -12
N: 32 Fahrenheit: 20  Celcius: -6
N: 33 Fahrenheit: 30  Celcius: -1
N: 34 Fahrenheit: 40  Celcius: 4
N: 35 Fahrenheit: 50  Celcius: 10
N: 36 Fahrenheit: 60  Celcius: 15
N: 37 Fahrenheit: 70  Celcius: 21
N: 38 Fahrenheit: 80  Celcius: 26
N: 39 Fahrenheit: 90  Celcius: 32
N: 40 Fahrenheit: 100  Celcius: 37
N: 41 Fahrenheit: 110  Celcius: 43
N: 42 Fahrenheit: 120  Celcius: 48
N: 43 Fahrenheit: 130  Celcius: 54
N: 44 Fahrenheit: 140  Celcius: 60
N: 45 Fahrenheit: 150  Celcius: 65
N: 46 Fahrenheit: 160  Celcius: 71
N: 47 Fahrenheit: 170  Celcius: 76
N: 48 Fahrenheit: 180  Celcius: 82
N: 49 Fahrenheit: 190  Celcius: 87
N: 50 Fahrenheit: 200  Celcius: 93
N: 51 Fahrenheit: 210  Celcius: 98
N: 52 Fahrenheit: 220  Celcius: 104
N: 53 Fahrenheit: 230  Celcius: 110
N: 54 Fahrenheit: 240  Celcius: 115
N: 55 Fahrenheit: 250  Celcius: 121
N: 56 Fahrenheit: 260  Celcius: 126
N: 57 Fahrenheit: 270  Celcius: 132
N: 58 Fahrenheit: 280  Celcius: 137
N: 59 Fahrenheit: 290  Celcius: 143
N: 60 Fahrenheit: 300  Celcius: 148
    

Input and output

This section explains how to interact with the user. From what I have researched, this is mainly where C starts becoming less safe, since correct handling of input and output is entirely in our hands, including errors related to incorrect memory writes. For now, since I am still learning this language, I will keep everything as simple and understandable as possible for me, following what the manual says, and later I will work more on restructuring what I learn according to the reference we chose, which is OpenBSD.
I am going to create a new file so I can keep the other one at hand. The new one will be called interaccion.c.
Page 18 of the C manual explains 2 new functions, getchar() and putchar(). It then gives an example using both functions. I will implement it by hand and see what we get.

openjazz$ vim interaccion.c 
    
#include <stdio.h>

int main(void)
{
        int c;

        c = getchar();

        while(c != EOF)
        {
                putchar(c);
                c = getchar();
        }
}
    
openjazz$ clang interaccion.c  
openjazz$ ./a.out              
0
0
1
1
a
a
2
2
aa
aa
test
test
$
$
^C
openjazz$ 
    

This program seems to simply accept an input, receive it and then print it. It seems both functions, getchar() and putchar(), only accept a single char but process the input character by character until they reach something called EOF, which seems to be a special marker that tells the program it has reached the last character of the string.
The manual tells us we can simplify the code by putting getchar() inside the while expression like this: while ((c = getchar()) != EOF), since getchar() returns the next value in the string when called.
On page 20 they show how to use getchar() to count the number of input characters. The manual shows an implementation, but I will try to write it by hand on my own to practice.

openjazz$ vim contar-char.c 
    
#include <stdio.h>

int main(void)
{
        int count = 0;
        while(getchar() != EOF)
        {
                count = count + 1;
                printf("Counting... %d\n", count);
        }
        printf("Char total count: %d\n", count);
}
    
openjazz$ clang contar-char.c  
openjazz$ ./a.out              
saigbsidfhybgudshfbg
Counting... 1
Counting... 2
Counting... 3
Counting... 4
Counting... 5
Counting... 6
Counting... 7
Counting... 8
Counting... 9
Counting... 10
Counting... 11
Counting... 12
Counting... 13
Counting... 14
Counting... 15
Counting... 16
Counting... 17
Counting... 18
Counting... 19
Counting... 20
Counting... 21
Char total count: 21
    

The next exercise in the book is counting lines. Again, I will try to write my own implementation, only using the book's example as a reference if some part gets difficult.

openjazz$ vim contar-lines.c
    
#include <stdio.h>

int main(void)
{
        int count = 0;
        char c = '0';

        while(c != EOF)
        {
                c = getchar();
                if(c == '\n')
                {
                        count = count + 1;
                        printf("Counting... %d\n", count);
                }
        }

        printf("Total count: %d\n", count);
}
    
openjazz$ clang contar-lines.c  
openjazz$ ./a.out               
12312312
Counting... 1
Total count: 1
openjazz$ ./a.out               
aesfsdf^[[27;2;13~
Counting... 1
asdsdf
Counting... 2
Total count: 2
    

Next, the manual shows a more complex example. I will try to write my own version that details everything that comes in.

openjazz$ vim contar-todo.c
    
#include <stdio.h>

int main(void)
{
        int charcount = 0;
        int linecount = 0;
        int wordcount = 0;

        char c = '0';
        char p = '0';

        while(c != EOF)
        {
                c = getchar();
                if((c == ' ' || c == '\n') && p != ' ')
                {
                        wordcount = wordcount + 1;
                }
                if(c == '\n')
                {
                        linecount = linecount + 1;
                }
                charcount = charcount + 1;
                p = c;
        }

        printf("Char Count: %d\nLine Count: %d\nWord Count: %d\n", charcount, linecount, wordcount);
}
    
openjazz$ clang contar-todo.c  
openjazz$ ./a.out              
Hola, esta es una
prueba para saber
si mi programa
funciona correctamente
Char Count: 75
Line Count: 4
Word Count: 13
    

I have to admit the book's solution is much more impressive, but I tried to make mine as understandable and short as possible so as not to overcomplicate things. I think it is worth showing the book's version:

 #include <stdio.h>
 #define IN 1 /* inside a word */
 #define OUT 0 /* outside a word */
 /* count lines, words, and characters in input */
 main()
 {
    int c, nl, nw, nc, state;
    state = OUT;
    nl = nw = nc = 0;
    while ((c = getchar()) != EOF) {
        ++nc;
        if (c == '\n')
            ++nl;
        if (c == ' ' || c == '\n' || c = '\t')
        state = OUT;
        else if (state == OUT) {
            state = IN;
            ++nw;
        }
    }
    printf("%d %d %d\n", nl, nw, nc);
 } 
    

Arrays

In this part the book gets a bit more demanding, since it introduces a program that uses arrays directly without explaining the basics of an array. This tells me the book is not meant for programming beginners. Honestly, that makes sense considering C's purpose as a language, the people it is aimed at and, above all, the fact that this is a book about C and not about basic programming in general.
Next, the manual has us create a program that uses an array to keep counts based on the input.
In my case, I will write my own implementation that counts how many times each digit appears, as well as whitespace, line breaks, tabs and other characters.

openjazz$ vim array1.c
    
#include <stdio.h>

int main (void)
{
	int count[14] = {0};
	char c = '0';

	while((c = getchar()) != EOF)
	{
		switch(c)
		{
		case '0':
			++count[0];
			break;
		case '1':
			++count[1];
			break;
		case '2':
			++count[2];
			break;
		case '3':
			++count[3];
			break;
		case '4':
			++count[4];
			break;
		case '5':
			++count[5];
			break;
		case '6':
			++count[6];
			break;
		case '7':
			++count[7];
			break;
		case '8':
			++count[8];
			break;
		case '9':
			++count[9];
			break;
		case ' ':
			++count[10];
			break;
		case '\t':
			++count[11];
			break;
		case '\n':
			++count[12];
			break;
		default:
			++count[13];
		}
	}

	printf("Veces que aparece cada tipo de caracter\n");
	printf("Numero 0: %d\n", count[0]);
	printf("Numero 1: %d\n", count[1]);
	printf("Numero 2: %d\n", count[2]);
	printf("Numero 3: %d\n", count[3]);
	printf("Numero 4: %d\n", count[4]);
	printf("Numero 5: %d\n", count[5]);
	printf("Numero 6: %d\n", count[6]);
	printf("Numero 7: %d\n", count[7]);
	printf("Numero 8: %d\n", count[8]);
	printf("Numero 9: %d\n", count[9]);
	printf("Espacios: %d\n", count[10]);
	printf("Tabulado: %d\n", count[11]);
	printf("Saltos linea: %d\n", count[12]);
	printf("Otros: %d\n", count[13]);
	return 0;
}
    
openjazz$ clang array1.c
openjazz$ ./a
a.out     array1.c
openjazz$ ./a.out
est0 es una 77777 prueba
	tabulacion88888
cierre 333333 000    4^D
Veces que aparece cada tipo de caracter
Numero 0: 4
Numero 1: 1
Numero 2: 1
Numero 3: 7
Numero 4: 2
Numero 5: 0
Numero 6: 0
Numero 7: 5
Numero 8: 5
Numero 9: 0
Espacios: 13
Tabulado: 1
Saltos linea: 4
Otros: 43
    

I must admit that in this part I jumped ahead with the switch statement, and what I did was very different from what the book had.

Functions

I had already jumped ahead on functions, but I still do not want to skip this topic. The manual shows a function that raises a number to an exponent. I will write the implementation from scratch.

openjazz$ vim func-expo.c
    
#include <stdio.h>

int potencia(int numa, int numb)
{
	int result = 0;
	if(numa==0 && numb==0)
	{
		return -1;
	}
	if(numb==0)
	{
		return 1;
	}
	if(numa==0)
	{
		return 0;
	}
	result = numa;
	for(int i=1; i<numb; i++)
	{
		result = result * numa;
	}
	return result;
}

int main(void)
{
	int numa = 0;
	int numb = 0;
	int result = 0;

	printf("Ingrese el numero A:\n");
	scanf("%d", &numa);

	printf("Ingrese el numero B:\n");
	scanf("%d", &numb);

	result = potencia(numa, numb);

	printf("Resultado: %d\n", result);

	return 0;
}

    
openjazz$ clang func-expo.c  
openjazz$ ./a.out
Ingrese el numero A:
2
Ingrese el numero B:
6
Resultado: 64
    

In this one I added some slightly dirty if statements because of the mathematical definitions. Something I did not test is negative numbers, but I think this is more than enough.

Arguments - Call by Value

The next section of the book is quite short. In short, it explains that the arguments passed to a function are created locally inside the function, unlike Fortran, where the parameters passed to a function are a direct reference to the original input variable, so values can be altered globally from inside the function. It is a fairly easy concept to understand because this is also how Java behaves. In fact, honestly, I did not know and had never considered that other languages did it differently.

Char Arrays

Apparently the way C implements strings is very different from Java. In Java, strings are objects, but since C does not have objects as such like C++, the closest thing is arrays of char variables. This section of the book has several exercises. In my case, I will write an implementation from scratch that receives an input, stores it in a char array and prints only the words longer than 5 characters.

openjazz$ vim array-char.c
    
#include <stdio.h>

void printString(char string[2048], int limit)
{
	for(int i = 0; i < limit; i++)
	{
		printf("%c", string[i]);

		if(string[i] == '\n')
		{
			printf("\n");
		}
	}

	return;
}

int main(void)
{
	char string[2048];
	char c = '0';
	int i = 0;
	while((c = getchar()) != EOF)
	{
		string[i] = c;
		i++;
	}

	printf("Full input:\n----------------\n");
	printString(string, i);

	printf("\n----------------\nSolo palabras de + de 5 caracteres:\n");
	int size = i;
	i = 0;
	int length = 0;
	char word[2048];
	for(int l = 0; l <= size; l++)
	{
		if(string[l] != ' ')
		{
			word[length] = string[l];
			length++;
		} else if (string[l] == ' ')
		{
			if(length > 5)
                        {
                                printString(word, length);
                                printf("\n");
                        }
			length = 0;
		}
	}
	return 0;
}
    
openjazz$ clang array-char.c  
openjazz$ ./a.out             
hola esta es una prueba 
de mi programa que 
maneja cadenas de texto 
Full input:
----------------
hola esta es una prueba 

de mi programa que 

maneja cadenas de texto 


----------------
Solo palabras de + de 5 caracteres:
prueba
programa


maneja
cadenas
    

Honestly, this program is anything but perfect, but I consider it a useful exercise.