
Our mascot for this level, the common raven, is a very sociable corvid and known for its problem-solving capacity. Ravens organize in teams and have been observed playing even as adults.
This level will acquaint you with the C programming language: that is, it will provide you with enough knowledge to write and use good C programs. “Good” here refers to a modern understanding of the language, avoiding most of the pitfalls of early dialects of C, and offering you some constructs that were not present before and that are portable across the vast majority of modern computer architectures, from your cell phone to a mainframe computer. Having worked through these chapters, you should be able to write short code for everyday needs: not extremely sophisticated, but useful and portable.
In many ways, C is a permissive language; programmers are allowed to shoot themselves in the foot or other body parts if they choose to, and C will make no effort to stop them. Therefore, just for the moment, we will introduce some restrictions. We’ll try to avoid handing out guns in this level, and place the key to the gun safe out of your reach for the moment, marking its location with big and visible exclamation marks.
The most dangerous constructs in C are the so-called castsC, so we’ll skip them at this level. However, there are many other pitfalls that are less easy to avoid. We will approach some of them in a way that might look unfamiliar to you, in particular if you learned your C basics in the last millennium or if you were introduced to C on a platform that wasn’t upgraded to current ISO C for years.
Some of “getting used to” our approach on this level may concern the emphasis and ordering in which we present the material:
You might also be surprised by some style considerations that we will discuss in the following points. On the next level, we will dedicate an entire chapter (chapter 9) to these questions, so please be patient and accept them for the moment as they are.
char* name;
where char* is the type and name is the identifier. We also apply the left-binding rule to qualifiers and write
char const* const path_name;
Here the first const qualifies the char to its left, the * makes it to a pointer, and the second const again qualifies what is to its left.
unsigned const*const a, b;Here, b has type unsigned const: that is, the first const goes to the type, and the second const only goes to the declaration of a. Such rules are highly confusing, and you have more important things to learn.
/* These emphasize that the arguments cannot be null. */ size_t strlen(char const string[static 1]); int main(int argc, char* argv[argc+1]); /* Compatible declarations for the same functions. */ size_t strlen(const char *string); int main(int argc, char **argv);The first stresses the fact that strlen must receive a valid (non-null) pointer and will access at least one element of string. The second summarizes the fact that main receives an array of pointers to char: the program name, argc-1 program arguments, and one null pointer that terminates the array. Note that the previous code is valid as it stands. The second set of declarations only adds additional equivalent declarations for features that are already known to the compiler.
/* This emphasizes that theHere, the first declaration of atexit emphasizes that, semantically, it receives a function named handler as an argument and that a null function pointer is not allowed. Technically, the function parameter handler is “rewritten” to a function pointer much as array parameters are rewritten to object pointers, but this is of minor interest for a description of the functionality. Note, again, that the previous code is valid as it stands and that the second declaration just adds an equivalent declaration for atexit.handler'' argument cannot be null. */ int atexit(void handler(void)); /* Compatible declaration for the same function. */ int atexit(void (*handler)(void));
int main(int argc, char* argv[argc+1]) { puts("Hello world!"); if (argc > 1) { while (true) { puts("some programs never stop"); } } else { do { puts("but this one does"); } while (false); } return EXIT_SUCCESS; }