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.