C language is one of the most well known and wildly used in Computer Science and it is one of the foundation of Informatic, i.e. even other languages like Python. Surely it guaranties a wide control over the machine but sometimes can be counterintuitive, even for simple tasks, but it also allows us to use some tricks and get the most out of it.
Swapping values between two variables
Let us start with a banal still quite important task like swapping values. C does not have an automatic memory management like Python, so we ought to use a temporary value.
int main(){
int num_1 = 5, num_2 = 7, temp;
temp = num_1;
num_1 = num_2;
num_2 = temp;
return 0;
}
Now, this technique is certainly correct and effective, but still it can be improved. For example, not using a third variable and thus saving memory and hardware resources, especially in old or limited hardware
int main(){
int num_1 = 5, num_2 = 7;
// swap
num_1 += num_2; // same as num_1 = num_1 + num_2 (12)
num_2 = num_1 - num_2; // (12 - 7 = 5)
num_1 = num_1 - num_2; // (12 - 5 = 7)
return 0;
}
Revers of a number
Another quite tricky tasks is obtaining the invers of an integer, but still it can be solved with some logical and mathematical thinking just like before (each variable is an integer):
while(number > 0){
result = (result * 10) + number % 10;
number = number / 10;
}
Dividing to numbers
When dividing two number be careful! C will handle the / operator in quite a peculiar way, indeed if you try to divide two integers, even storing the result in a float, it will return an integer. So be aware, if you are not sure to obtain an integer from the operation, always check that one of the value is a floating point.
int main(){
float result;
int divider = 5, divisor = 2;
result = divider / divisor;
printf("result = %f", result);// 2.000000
return 0;
}
int main(){
float result, divider = 5;
int divisor = 2;
result = divider / divisor;
printf("result = %f", result); // 2.500000
return 0;
}
As you see the %f will return a number with six decimal digits, so if you want to display more or less of them, you can specify the precision with the notation %.[number]f
printf("result = %.2f", result); // 2.50
Determine the length of a string
If, for example, you are not allowed to use string.h, and so the function strlen(), you can use a simple for to achieve the same result, but first of all let’s define what a string is in C. As you might now, there is no string datatype in C, just char, which represent a character. So we have to declare it as an array, or rather a vector of characters, which at the end has a fundamental symbol, which is \0, which is represented as a 0 on the ASCII table, which is used to codify the alphabetic symbols in a “computer friendly” way. Thanks to it we can determine the end of a string
char string[] = {'b','a','n','a','n','a','\0'}; // same as
char string[] = "banana";
char string[LEN]; // empty string with an arbitrary number of character (not necessary the exact length)
So, back to the main point, we can use for characteristics to find a fast and compact way to return the length of a given string. This function syntax is for(counter ; condition ; increment), but the first and the last are quite optional, so what we really need is the condition, that will keep the loop active if true, for instance a non-zero value, and here is were that special character comes handy, because since its value is 0, then it will stop the loop. In the end we can now write the function:
int strlen(char str[]){
int i = 0;
for(; str[i++];);
return i;
}
It allow us to iterate over the string, merging the condition and the iterator, place the counter outside the for loop so that we can access its value later and a semicolon to notify the compiler that we do not have any block to execute related to the for. So, in few words this function will pass each character in the string until it detects the \0, which has value 0 and consequently stops the loop.
From lower- to upper-case and vice versa
As we saw earlier, C handles character as a numeric code according to a specific format, generally known as ASCII (American Standard Code for Information Interchange). This allow us to sum or subtract actual integers to a character and obtain another different symbol. Since they are full-fledged numbers they can also be subject to operation among themselves. Knowing this and having the ASCII table at hand, we can finally write down our functions:
char toUpper(char character){
character = character - 'a' + 'A';
return character;
}
char toLower(char character){
character = character + 'a' - 'A';
return character;
}
We can also apply the swap function to them, quite handy isn’t it?
Vectors and pointers
Now, we cannot talk about C without saying a thing about pointers, one of the most helpful an intricate topic to learn about this programming language. For example, what if I told you there are three conceptually identical ways to access a value inside a vector? But first, let us define better a vector. A vector in C language is a mono-dimensional data-structure, which consist of a series of consecutive memory cells according to the dimensions declared, the type and amount of elements.
float vector[] = {0.5, 3.0, 7.2, 8.6};
int another_vector[10]; // a vector with a maximum number of 10 elements
The name we give them is also their pointer, or rather the pointer to the first element of the sequence (i.e. vector and another_vector), so if we would dereference vector *vector we would obtain 0.5, but how can we access the others? Now we know the pointer so the memory address of the first cell, so we need to add one to get to the next, thus vector+1 is the pointer of the second element, so to get it we dereference what we just attained *(vector + 1) Well, you might or might not be used to use the vector[1] syntax, or maybe the 1[vector] syntax, which corresponds to the exact same script as before:
int main(){
float vector[] = {0.5, 3.0, 7.2, 8.6};
printf("%.1f, %.1f, %.1f \n", vector[1], 1[vector], *(vector + 1));
printf("%.1f, %.1f, %.1f \n", vector[0], 0[vector], *(vector + 0));
return 0;
}
>>>
3.0, 3.0, 3.0
0.5, 0.5, 0.5
This is also the reason why we start from 0, because you do not need to add anything to access the first element *(vector + 0)
This gives you a lot of freedom when deciding which way apply and where.
For a matrix is conceptually the same but slightly different in the scripting, for example in a bidimensional array:
int main(){
int matrix[3][3] = { {0, 1, 2},
{3, 4, 5} };
printf("%d, %d \n", matrix[0][1], *(*(matrix + 0) + 1));
return 0;
}
>>>
1, 1
Comments