(This post is part of the learning c series.)
Learning C (Part 1): The basics
This post kicks off a series of articles designed to teach myself C. As I have decent programming fundamentals, these articles will not cover important, introductory concepts such as good variable names, the purpose of control statements, how conditionals work, etc. If you consider yourself at least a somewhat competent programmer and would like to learn C without the fluff, I invite you to follow along my journey!
Why learn C?
C powers many extremely important projects. A tiny sample of these projects yields some very recognizable names:
- Linux
- NASA's Curiosity Rover.
- Python
- Ruby
- Nginx
- Redis
If you want to contribute to projects such as these, which are truly changing the world, learning C would be a good first step!
Additionally, C is the goto language for Embedded Systems Programming.
A very, very brief overview of the language
This article in the series will quickly glance over many concepts of C, including iteration, strings, arrays, and more.
Getting started: Compiling and executing a program
Installing a compiler
I will be using gcc as my compiler on an Ubuntu linux VM. You are free to use other compilers while following along with the examples. I will do my best to note when compiler-specific behavior is being discussed.
If you are on Ubuntu and would like to see if gcc is available on your machine, execute
$ gcc -v
You should see results similar to
Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.7/lto-wrapper Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.7.2-2ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix gcc version 4.7.2 (Ubuntu/Linaro 4.7.2-2ubuntu1)
If you instead get the error
gcc: command not found
Install gcc on the machine
sudo apt-get install gcc
Run gcc -v
afterwards to ensure the installation procedure was successful.
Hello, world!
And now, we pay tribute to the classic "Hello, World!". To ensure our
environment is working correctly, we will create a trivial program that simply
prints "Hello, world!"
.
Create a file called "hello_world.c".
1 2 3 4 5 | #include <stdio.h> int main(){ printf("Hello, world!\n"); return 0; } |
We will now compile the file.
$ gcc hello_world.c -o hello_world.o
(The above hello_world.c
file has been verified to not have syntax errors, so
if you encounter a compiler error after executing the command, ensure you have
input the file correctly.)
The above gcc command will create a hello_world.o
output file, which we can
directly execute. To do so, we run
$ ./hello_world.o
And we observe the following output in our shell:
Hello world!
So this very basic usage of gcc can be generalized as follows:
$ gcc some_c_file.c -o some_output_executable.o
If some_c_file.c
compiles successfully, we will be able to execute the program
via
$ ./some_output_executable.o
The specifics of how the hello_world.c
works will be discussed later, for now
you should celebrate that you can now compile C files on your machine!
Article content
Structure of a C program
- The entry point of a program is the
main()
function.- The
main()
function should be of typeint
and return 0 upon success.
- The
Variables and expressions
Variables must be declared, with their type preceding, before they are used. Consider the following example, which will fail to compile.
1 2 3 4 5 6 | #include <stdio.h> int main(){ x = 10; // the type was omitted printf("Hello!\n"); return 0; } |
The compiler output the following error:
ex1.c: In function 'main': ex1.c:3:5: error: 'x' undeclared (first use in this function)
Declaring the x
as int
would compile successfully.
1 2 3 4 5 6 | #include <stdio.h> int main(){ int x = 10; printf("Hello!\n"); return 0; } |
Here is an example of the formatters for printf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #include <stdio.h> int main(){ int x = 10; float y = 10.0; // float for decimals char *mystr = "Hahah"; printf("x: %d\n", x); printf("y: %f\n", y); printf("mystr: %s\n", mystr); // padding printf("x: %5d\n", x); // Limit the number of decimal points printf("y: %.2f\n", y); // Padding AND limit decimal points printf("y: %10.2f\n", y); return 0; } |
x: 10 y: 10.000000 mystr: Hahah x: 10 y: 10.00 y: 10.00
Data types
char
- a character, a single byteshort
- short integerlong
- long integerdouble
- double-precision floating pointfloat
- floating point, may be smaller than double
using #define
#define identifier replacementtext
will replace instances of identifier
in
your program with replacementtext
(as long identifier
is not between double
quotes).
1 2 3 4 5 6 7 8 | #include <stdio.h> #define MYNAME "Joseph" #define YOURNAME "Dork" int main(){ printf("Hello YOURNAME, My name is MYNAME\n"); printf("Hello %s, My name is %s\n", YOURNAME, MYNAME); return 0; } |
Hello YOURNAME, My name is MYNAME Hello Dork, My name is Joseph
Using getchar
getchar()
reads text from the input stream. It returns the character read.
However, the EOF
(end of file) character can be outside the range of the
char
data type, so you should use int
to store the return value of
getchar()
.
1 2 3 4 5 6 7 8 9 | #include <stdio.h> int main(){ int c; printf("Type something! Press enter to echo, CTRL-D to exit\n"); while ((c = getchar()) != EOF){ putchar(c); } return 0; } |
(CTRL-D is the default EOF
character for Unix like systems)
I'm getting bored, so here's stuff I find interesting.
Reading a line into a char array.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #include <stdio.h> #define BUF_SIZE 100 void readline(char buf[], int bufsize); int main(){ char str[BUF_SIZE]; readline(str, BUF_SIZE); printf("%s\n", str); return 0; } void readline(char buf[], int bufsize){ int i,c; for(i=0; i<bufsize-1 && (c = getchar()) != EOF && c != '\n'; i++){ buf[i] = c; } if(c == '\n') buf[i++] = c; buf[i] = '\0'; } |
Copying one char array to another.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #include <stdio.h> void copy(char *fromstr, char *tostr); int main(){ char buf[10]; char str[] = "hello"; copy(str, buf); // prints "hello" printf("%s\n", buf); return 0; } void copy(char *fromstr, char *tostr){ // This works because A) the null char returns 0, which causes the condition // to terminate through B) the fact that assignments return the assign // value. while(*tostr++ = *fromstr++); } |
External variables
External variables can be accessed by any name in any functions. External variables must be defined once and only once, while they must also be declared wherever they will be used. They retain their values after functions have returned, in contrast to the standard automatic variables.
External variables cannot be defined and declared at the same time.
1 2 3 4 5 6 | #include <stdio.h> int main(){ // This will cause a compiler error extern int somevalue = 10; return 0; } |
ex8.c: In function ‘main’: ex8.c:3:16: error: ‘somevalue’ has both ‘extern’ and initializer
An example of extern usage:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #include <stdio.h> void alter_somevalue(); void alter_somevalue2(); int somevalue = 10; int main(){ printf("%d\n", somevalue); alter_somevalue(); printf("%d\n", somevalue); alter_somevalue2(); printf("%d\n", somevalue); return 0; } void alter_somevalue(){ extern int somevalue; somevalue = 15; } void alter_somevalue2(){ // extern is actually redundant in this case! somevalue = 25; } |
10 15 25
So when is extern useful? Mainly when dealing with multiple files. We'll get to that later!
Joseph, this "tutorial" was useless!
Sorry! I already knew about most of these concepts. Perhaps the upcoming tutorials will be more interesting!