Sie sind auf Seite 1von 37

HOW-TO

Written by Elie De Brauwer


PROGRAM IN C - PART 1
basics of the language are explained, known is probably the Linux
we will introduce new concepts, kernel itself. The main objections
N/A techniques, and more intermediate- against learning C are that it is
to-advanced principles -- by not a modern language; for
example. I hereby promise I will do example, it lacks a rich
my best not to make too-large leaps, framework, and it is not object-
and to introduce new concepts as we oriented, which makes C a rather
encounter them. If any reader simple language to learn. On the
experiences problems, or fails to other hand, a valid objection is
Dev
properly understand certain things, that, since C is a language
Graphics Internet Multimedia System
please do not hesitate to get in touch closely related to the hardware,
with me. it can allow users to do things
that were not supposed to be
done. If you really want to shoot
CD/DVD HardDrive USB Drive Laptop Wireless
Today, there are numerous yourself in the foot, C will not

T
programming languages out there, prevent you from doing so.
his article is the first in a and the question of why to use 'A'
series which will focus on and not 'B' has led to never-ending
having fun with the C discussions. A first argument is that Now, the scary part -- it's time
programming language. In the C is still a very popular language. A to get our hands dirty. If you visit
first articles, we will introduce the second argument is the link between a programming-related forum or
C language and some basic UNIX and C -- C was initially newsgroup, you will encounter,
computer programming concepts developed at AT&T Bell Labs at regular intervals, somebody
to the novice user. This way, between 1969 and 1973 by Dennis who wants to start programming
inexperienced users should be Ritchie, and the UNIX kernel was the and fails to compile/execute the
able to follow the series, and get first major project to be implemented first example they found on a
to a level where they should be in the language. Nowadays, the website (or in a magazine).
able to write and understand number of (open) software projects Especially for those beginning
simple C applications. Once the written in C is still huge -- the best programmers, Debian/Ubuntu

8
has foreseen this, and provided a use of a terminal
01. #include <stdio.h>
special metapackage called 'build- emulator to type in
02.
essential`. Running: some commands.
03. /***********************************
Once you master
sudo apt-get install build- 04. * Main function gets called when *
these steps, and
essential 05. * the application is launched *
know what's going on
06. ***********************************/
will equip your system with under the hood, you
07. int main()
everything required to compile a can still switch to an
08. {
simple C application (amongst IDE, or not. I write all
09. // Say something to the audience
others the GNU GCC compiler and my code using Emacs
10. printf("Hello world\n");
make). In this series, we won't and some x-terminals.
11. return 0;
teach you how to use an IDE 12. }
(
— a graphical suite Enough talk. The
that performs embedded simplest application
debugging, editing, building, and (which actually does something), and echo $?
includes, preferably, some the de facto first example for every 0
content help for the user as well). programming language, is the so-
There are some excellent IDEs called 'hello world' application. This The first line will invoke the
available, such as is an application which starts up, GNU C compiler to compile the
, and displays the string 'Hello world', and file called and
in conjunction with the terminates. This code can be seen in output (-o) it to an executable
CDT. You are, of course, free to Listing 1. To compile and execute this called . The options
use any of those, but I suggest application, put it in a text file with -Wall -W and -Werror instruct the
you learn programming using the extension .c, open a terminal, go compiler to check for warnings
your favorite text editor such as to the directory where you saved the (a warning is a non-critical error,
Emacs, Vi, Vim, Kate, and file, and execute: meaning the compilation will still
numerous others. Simply pick an succeed but it might not do what
gcc -Wall -W -Werror hello- the user expected in all
editor that supports syntax
world.c -o hello-world situations), and abort when a
highlighting for C (most editors
should have this feature). And, ./hello-world warning is encountered. We
next to your favorite editor, make execute the binary by prefixing it
Hello world with './' -- this is because the

9
directory where you placed the • defines the main entry point with a string as an argument.
binary will typically not be in your of our application. When the The only odd thing here is the
$PATH. And we used the funny application is executed, it will start '\n'; this is a so-called escape
echo command to inform us of the executing the function sequence, and it
exit status of the last command called main(); the int in means nothing
Let's take a close
executed. It is not a coincidence front of it means that more than a
that this value is the same as the the main function look at the source... newline. Try
value after the 'return' statement. should return an removing it, and
integer. The '()' means that main() is you will see that when you
Now, let's take a close look at
a function, and it takes no arguments execute the application, your
the source file:
(it can take arguments, but we will prompt will be printed on the
• instructs the discuss this later). same line as the application.
preprocessor. This is a piece of Note that every instruction ends
• opens a block -- which is with a semicolon. You will forget
logic executed prior to the actual
closed at line 12. These blocks group to place these semicolons on
compilation, and it focuses on
instructions which belong together; numerous occasions! This way,
manipulating the C language,
in this case they group the main() you can put multiple instructions
such as inserting other files or
function instructions. on one line, or can have them
replacing macros with C code. It
includes a header file called • is a single-line comment. span multiple lines.
stdio.h. This file should be located When '//' is encountered on a line, • exits from the main
in /usr/include/stdio.h, and what remains of that line is ignored function, and passes a certain
contains definitions for several by the compiler. It's impossible to value (in this case 0 -- which is of
functions; in our case, we need it end these comments, and they can type int) back to whatever called
to let the compiler know that not span multiple lines. this function. In this case, the
something called printf() exists.
• , we finally find shell called the main function.
• consist of a block something useful; here we call And that's why gave us
comment that will be ignored by another function called printf(), and, our zero. This is an instruction,
the compiler -- everything between the parenthesis, we pass and thus also terminated with a
between '/*' and '*/' will be the function an argument, which, in semicolon.
ignored. It is clear that this our case, is a string literal. C strings One final note is that, if you
comment can span multiple lines. are placed between double-quotes. modify your source file, you
Thus, we call the printf() function

10
should run gcc again. C is unlike • Remove the
Perl, Bash, Python, PHP, and parameter at the command line.
others -- it's not an interpreted What is the default name given to
language; the gcc command calls the binary? Answer is shown below.
a compiler (which transforms a
• Try removing all comments from
higher level language into
the source file, verify that this has no
assembler), an assembler
effect.
translates assembler into object
files (machine instructions), and a • If you rename the
linker, which combines several function to , what will the
object files into an executable. compiler (actually the linker) tell
These will transform the C code you?
into machine code that your CPU
is able to understand and execute.

• Compile the example


yourself, see that you can
reproduce the result.
the default name is
• Make the application display
.
• Replace return 0; by return 1;,
and confirm that the exit status
is a Belgian
has changed. Linux fanatic, currently
employed as an embedded
• Delete the return 1; software engineer with one of the
statement, and check what the world's leading satellite
compiler says. Is it a warning or communications companies. Apart
an error? from spending time with his family, he https://launchpad.net/
enjoys playing with technology, and
• Run gcc without the spends his days waiting for Blizzard to
parameter; does it create a binary finally release Diablo III.
now or not?
11
HOW-TO
Written by Elie De Brauwer
PROGRAM IN C - PART 2
it's impossible to be complete in function_name, which returns a
these short articles - the main goal of result of type return_type, and
FCM#17 - Program In C - Part 1 takes two parameters. If you
which is to create some base, and
give people a starting point to don't have a return type, you
continue their journey. would replace return_type by
void. A more concrete example
would look like:
C is a so-called procedural
int add(int a, int b){
language, which means that, when
return a+b; }
Dev Graphics Internet Multimedia System
programming in C, you are working
in a procedure-oriented way (the This adds two integers ('int a'
most popular alternative is object- says the the first variable is of
oriented programming where people type integer and that it is given
manipulate objects). This means that the name 'a'), and returns their
CD/DVD HardDrive USB Drive Laptop Wireless
when you need to solve a problem, sum as an int. You could call it

I
you will start by breaking it up into by putting 'add(1,1);' in your
n the first article in this series, smaller and reusable pieces. code. Note that the function
we learned to configure our Suppose you were writing an office needs to be defined before it is
system and compile and suite. You would have a print used. And this is where the use
execute an application that didn't function to print your work on paper, of header files pops in; a header
do anything useful at all, but we and this function could be reused by file will typically contain
had to start somewhere. This all your suite components. In C most 'function prototypes'; this is the
article is of major importance for prototypes will look like: function header as displayed
novice programmers since here above, but terminated with a ';',
return_type
we'll introduce some thinking in and not followed by the function
function_name(parameter_type1
code. This article will introduce body. This is enough to let the C
param1, parameter_type2 param2)
functions, loops, and decision compiler know that a function,
making, from a C perspective. Here you define a function called with a given signature, will be
However, it should be clear that defined in the future, and let's

8
01. #include <stdio.h>
just hope that the linker will find section, 'statements1;' means 02. #define VERSION "1.0"
that function. In the example any sequence of application 03.
code, there are three functions logic. The first and most common 04. /*
defined. One is the main function, structure can be seen from line 05. * Runs a prime check on a given
but there is also the function 13 to 28 and line 49 to 56, and integer, return
isPrime() defined on line 8 - which has the following structure: 06. * 1 when the integer is a prime
takes one integer as a parameter, number, 0 otherwise
if(condition1)
and will return 0 when the integer 07. */
{
is a prime. Then we have also 08. int isPrime(int prime)
statements1;
printVersion() on line 34, which 09. {
}
only prints some information, and 10. int count=2;
else if(condition2)
doesn't return anything at all. 11.
{
printVersion() makes use of the 12. // Catch two special cases
statements2;
symbols __DATE__ and __TIME__, 13. if(prime==1)
}
which are replaced at compile 14. {
else
time by the compilation 15. return 0;
{
timestamp. Other symbols such 16. }
statements3;
as __LINE__ and __FILE__ also 17. else if(prime==2)
}
exist - which can help during 18. {
debugging. This function also If condition1 is true, 19. return 1;
uses the VERSION symbol which statements1 will be executed, 20. }
is defined on line 2. When the otherwise condition2 will be 21. else
preprocessor is run (before the checked; if this is true, 22. {
compiler), it does some plain statements2 will be executed, 23. while(prime%count!=0 &&
string replaces; in this case and, if all else fails, statements3 count*count<=prime)
VERSION will be replaced by '1.0'. will be executed. Both the 'else 24. {
if' and 'else' parts are optional, 25. count++;
and you can also add more 'else 26. }
The example code (Listing 1) if' parts. A condition is 27. return
has been written so that the most considered true when it differs (prime%count==0)?0:1;
common loop/decisions from zero - which explains line 28. }
constructs are used. In this 49. 29. }
30.

9
31. /*
A special form of the if...else to 57; this is a for loop and 32. * Print version information
structure is on line 27. This form has the following syntax: 33. */
isn't that common, and is typically 34. void printVersion()
for(init_variable;conditio
used for very compact things. 35. {
n;update_variable)
Here, it is a compact way of 36. printf("Primality checker
{
saying that the function should version %s\n", VERSION);
statements;
return 0 if count is a divisor or 37. printf("Compiled on %s
}
prime, or 1 otherwise. %s\n", __DATE__, __TIME__);
Here, there are three parts: 38. }
A first loop is a while loop, for
first a loop variable is 39.
example lines 23 to 26. Here, the
initialized to a value (typically 40. int main()
body of the loop will be executed
0 but in our example to 1), 41. {
provided and as long as the
next there is a condition which 42. int i=1;
condition is true, which means it
is checked on every iteration 43. const int max_prime=2500;
is potentially not executed. In this
and the for loop will continue 44.
example, we say a number is a
as long as this condition is 45. printVersion();
prime by trying all numbers
true, and finally the variable is 46.
smaller than the square root of
updated -- this is typically a 47. for(i=1;i<max_prime;i++)
the number (but we use
'i++' (i++ is shorthand for 48. {
count*count <= prime instead of
i=i+1). It is good style to use 49. if(isPrime(i))
count <= sqrt(prime) because
while loops when you don't 50. {
multiplying is more CPU friendly
know the number of iterations 51. printf("%d is
than calculating a square root.
up front, and a for loop when prime\n",i);
The % operator is used to take the
you do know, and thus do not 52. }
modulo. Meaning that 7%2=1
need to modify the loop 53. else
because the remainder of the
variable in the loop body. 54. {
division of 7 by 2 is 1 (7-2*3=1). 55. printf("%d is not
Within the main loop, you make The language has two other prime\n",i);
some changes which impact the constructs which are not 56. }
loop condition. Failing to do this present in the example. First 57. }
will result in an eternal loop. there is the: 58. return 0;
A second loop is seen on line 47 59. }

10
do variable on which the decision will be • Rewrite the if...else in the
{ based, and this is followed by a list of main() function to make use of
statements; case keywords succeeded by all the ternary operator
}while(condition); cases which need handling (here,
• Replace the isPrime() function
one will typically use enum with a
Here, the statements will be by an isOdd() function which
limited range). Statements can be
executed as long as condition is returns 1 when a given integer is
terminated with break, otherwise
true, which is almost the same as odd.
execution would fall through (which
the while loop. The difference is
also has its uses) and continue the • Design and write a small
that the body will be executed at
statements of the next case (if application which prints out the
least once. While loops are,
variable equals 4, statements2 will n Fibonacci sequence, where n
however, more common than
be executed). And finally there is a should be easily modifiable.
do...while.
default which stands for 'all other
A more popular format which cases'.
has been omitted here is the
One final note: it is possible to
switch...case construct:
jump out of if..else, while, for,
switch(variable) do..while and switch...case blocks by
{ using the 'break;' statement. And it is
case 1: possible to proceed with the next
statements1; iteration (of a loop) by using the
break; 'continue;' statement.
case 4:
is a
case 2:
Belgian Linux fanatic,
statements2; • Rewrite the for loop in the main() currently employed as an
break; function so it becomes a while loop embedded software engineer
default: with one of the world's leading
statements3; • Rewrite the if...else if..else satellite communications
} structure in the isPrime() function to companies. Apart from spending
a switch...case structure time with his family, he enjoys
This is a very compact form of playing with technology, and
writing if..else if...else if...else • Rewrite the ternary spends his days waiting for
(condition)?value1:value2 to an Blizzard to finally release Diablo
statements. A switch is passed a III.
if..else structure

11
HOW-TO
Written by Elie De Brauwer
PROGRAM IN C - PART 3
assembly language, and in assembly When handling pointers, you
languages you spend most of your will encounter two 'extra'
FCM#17 - Program In C - Part 1 time moving data around, but in operators. These are * and &. It
FCM#18 - Program in C - Part 2
order to do that you need to know helps, when you look at code,
where the data is located, hence its that you read * as 'the value
address in memory. And this is just stored at this address', and & as
what a pointer is. A pointer is an 'the address of this variable'.
address in your computer's memory,
int anInt=5;
nothing more, nothing less. But when
Dev
you're working with C, you'll end up int * anIntPointer=&anInt;
Graphics Internet Multimedia System
with the conclusion that pointers are
everywhere. So, after conquering printf("Address: %p Value:
functions and pointers, we should be %d \n",&anInt, anInt);
able to handle almost anything. printf("Address of pointer:
CD/DVD HardDrive USB Drive Laptop Wireless
In this article, I will not present a %p Address: %p Value: %d
'fully functional program'. I will \n",&anIntPointer,

S
present small snippets between the anIntPointer,
o far so good. This is already
text, but you are encouraged to fire *anIntPointer);
the third part in this series,
up your editor and start
and we have already made printf("Size of pointer: %d
experimenting. You will also see that
a lot of progress. The past articles size of int: %d\n",
I introduce some 'extras' which are
explained how to think in code - sizeof(anIntPointer),
not mentioned in the main title. I
by introducing functions. This sizeof(anInt));
will, for example, also introduce
article will probably be one of the Thus, we declare an integer
structures, arrays, strings, ... ,
most difficult in this series; here and assign this integer the value
because I want to see this series
we'll touch something which is 5, we declare a pointer (mind
evolve into a practical tutorial, and
almost C-specific: the notion of the extra *), and we let it point
not into a C textbook.
pointers. C is a programming to the address of the previously
language which lives close to the

8
declared integer. Next, we print other. In printf, we use p to print a anIntArray[i],
the address of the integer, and pointer (in hexadecimal), s to print a *(anIntArray+i));
the value of the integer. Then we string (for more information see man }
print the address of the pointer, 3 printf). The sizeof() operator used
This code produces the
the value of the pointer (which is in the printf statement returns the
following output:
an address, the address of anInt), size of an element (in bytes).
and the value the pointer points Address of array: 0xbf8b55d4
to. And to end, we print the size Size of array: 20
of the pointers and the size of the What is an array? An array is Index:0 Address:0xbf8b55d4
integer. This produces the simply a list of variables of the same Value:10 Value: 10
following output: type. In this example, we declare an Index:1 Address:0xbf8b55d8
array of integers where we can store Value:20 Value: 20
Address: 0xbfc819d8 Value: 5
5 integers. At this point, we also Index:2 Address:0xbf8b55dc
Address of pointer: declare how many integers we want Value:30 Value: 30
0xbfc819d4 Address: to put in there (in this case five). Index:3 Address:0xbf8b55e0
0xbfc819d8 Value: 5 Here we initialize the array at Value:40 Value: 40
declaration, but we could do it Index:4 Address:0xbf8b55e4
Size of pointer: 4 size of
elsewhere in the program as well. Value:50 Value: 50
int: 4
int Now, what does this show us?
Here we can see that both The size of the array equals the
anIntArray[5]={10,20,30,40,50};
pointers and integers are 4 bytes number of elements times the
large (which makes sense, since printf("Address of array: size of each element (there is
I'm on a 32-bit computer; if you %p\n", &anIntArray); nothing extra stored). All
run this on a 64-bit or a 16-bit elements are placed next to
printf("Size of array:
computer, these values may each other in memory (look at
%d\n",sizeof(anIntArray));
vary). The address will be the memory addresses: they
different on your system, but the for(i=0;i<sizeof(anIntArray)/si each differ by 4. By adding [i]
fact that the address of the zeof(int);i++) after the array name, we can
pointer and the address of the { address an element of the array
integer are only 4 bytes apart is printf("Index:%x at index i. But, and here's some
not a coincidence; they are simply Address:%p Value:%d Value: magic called 'pointer arithmetic',
physically stored next to each %d\n", i, &anIntArray[i], if we add 1 to an int pointer, the

9
pointer is increased by 4 (the size printf("Value: %s\n", aString); There is actually nothing new
of the integer) - not by one. So, here. We handle it the same way
for(i=0;i<=strlen(aString);i++)
we can address the array by using as adding integers, except we
{
the subscript method ([i]), but now use 'strlen()', a function
printf("Index:%x
also with some pointer arithmetic, defined in string.h (see man 3
Address:%p Value:%c\n", i,
and, in essence, the array we strlen for details) to get the
&aString[i], aString[i]);
declared is just a pointer to length of the string; a char is
}
memory - where several values of only one byte large, and we use
the same type are stored. Here, we create a char, and a char %s to print it. There is only one
array (which is, in essence, a magical thing here and that is
pointer; this is equal to writing 'char how will we know that the string
We have touched on integers aString[6]=”Hello”;', and do mind is finished? Well, the array is not
and arrays of integers, and we'll the difference between the char 'c' {'H','e','l','l','o'}, it is
extend this principle. A single and the string “c”). This generates {'H','e','l','l',o',0}. The ASCII null
character ('c') can be stored in a the following output: character is added after the
'char' type, and, if we take string, so how does strlen()
multiples of these chars, and put
Address: 0xbf8b560f Value: c work? It is just a while loop
them after each other, a string is
Size: 1 which continues increasing the
thus nothing more than an array
Address of string: 0xbf8b5600 index until the value becomes 0.
Size of string: 5
of chars.
Value: Hello
char aChar='c'; Index:0 Address:0x8048780 This defines a
char * aString="Hello";
Value:H structure...
Index:1 Address:0x8048781
printf("Address: %p Value: Value:e
%c Size: %d\n",&aChar, Index:2 Address:0x8048782
Value:l
aChar, sizeof(aChar)); Everything's going well. Let's
Index:3 Address:0x8048783
printf("Address of string: add another thing on the pile -
Value:l
%p\n", &aString); structures. We know arrays?
Index:4 Address:0x8048784
Arrays are a collection of items
Value:o
printf("Size of string: of the same type; structures are
Index:5 Address:0x8048785
%d\n",strlen(aString)); a collection of things with
Value:
different types.

10
struct aStruct &aStruct.charMember, Member of struct: 6
{ &aStruct.stringPointer); Member of struct: 5
int intMember; Member of struct: 6
aStruct.intMember=6;
int * intPointer; Member of struct: 5
char charMember; aStruct.intPointer=&anInt; Member of struct: Hello
char ** stringPointer;
}; aStruct.charMember='k'; And what does this teach us?
Well, we can declare structures,
aStruct.stringPointer=&aString; we can have pointers to
structures (it goes further, we
This defines a structure called aStructPointer=&aStruct;
can have arrays of structures,
'aStruct', which combines an printf("Member of struct: and structures can contain
integer, a pointer to an integer, a %d\n", arrays, structures can also
char, and a 'double' pointer (a (*aStructPointer).intMember); contain structures and structures
pointer to a string or a pointer to
can even contain pointers to
a pointer to a char). Put this printf("Member of struct:
structures of the same type --
declaration outside your %d\n",
this is called a linked list). By
functions. Typically, these are *(*aStructPointer).intPointer);
using the '.' operator we can
placed in header files. Next we
printf("Member of struct: access the members of a struct,
can use this struct; we use the
%d\n", aStructPointer- and when we have a pointer to a
previously defined variables to
>intMember); struct, we do not need to
populate this struct:
dereference it first as in
printf("Member of struct:
struct aStruct aStruct; (*aStructPointer).intMember,
%d\n", *aStructPointer-
since this is so common we can
>intPointer);
struct aStruct * use the '->' operator as in
aStructPointer;
printf("Member of struct: aStructPointer->intMember. Also,
printf("Address: %p Size: %s\n", *aStructPointer- using the double pointer is
%d\n",&aStruct, >stringPointer); peanuts. There is, however, one
sizeof(struct aStruct)); odd thing in the output: here it
And the output: says the size of this struct is 16,
printf("%p %p %p
Address: 0xbf8b55e8 Size: 16 while we added one int (4 byte),
%p\n",&aStruct.intMember,
0xbf8b55e8 0xbf8b55ec one int pointer (4 byte), one char
&aStruct.intPointer,
0xbf8b55f0 0xbf8b55f4 (1 byte) and one char pointer (4

11
byte). Who stole those three up in strange situations. I lost a day while loop.
bytes of memory? Well that is this week, because I incremented a
• Take a look at some manpages -
called alignment. During the pointer (which was zeroed
those of memcpy strcpy strcat
compilation process all memory afterwards) instead of incrementing
memzero, and see that all these
addresses were aligned to 4-byte the value the pointer pointed to. C
functions operate on pointers.
multiples since it is will not prevent you
much more efficient from doing these • A C application typically has
for the processor to You just need a things, but these will 'int main(int argc, char **argv)'
fetch an address little practice... result in your as it's main prototype, here argc
which starts at an application being contains the number of strings
address which is a multiple of terminated. It's the same with passed to the application, and
four. But if you would really want arrays: if you write int array[5]; int b; argc is an array of argc strings.
to change this, you can. array[6]=0;, you will set the value of Write a small application which
b to zero. This leads to memory prints all arguments given to the
corruption, and, in extremis, to stack application. What is stored in
For all the brave who managed corruption. So, pointers are very argv[0] ?
to bear with me this far, my powerful, but you need to use them
congratulations. I know that the right.
first time people talk about
pointers it results in a lot of
frowning and thinking 'why would
somebody want to use this', but,
don't panic - you just need a little is a
practice to get full speed with • Collect all the code snippets on this Belgian Linux fanatic,
pointers, and you'll soon see the currently employed as an
page and turn them into a working
embedded software engineer
advantage they bring. But one program. with one of the world's leading
word of caution is in place: satellite communications
pointers point to 'a' memory • Try to run this program on a 32bit companies. Apart from spending
location. They can point to any and a 64bit system (use a livecd for time with his family, he enjoys
memory location. If you forget to example), and compare the playing with technology, and
initialize them, or forget to differences. spends his days waiting for
Blizzard to finally release Diablo
dereference them, you can end • Implement strlen yourself using a III.

12
HOW-TO
Written by Elie De Brauwer
PROGRAM IN C - PART 4
But, since it's also the holiday Then, we will need to include
season, the demo application will be the ncurses header in our source
FCM#17-19 - Program In C - Parts 1-3
an application which creates ASCII file - by adding #include
snow. In order to create this effect I <ncurses.h> at the top of our
will use a small subset of a library source file. But, what is really
called 'ncurses'. For more new is that ncurses is provided
information regarding this library, as a dynamic library, which
you are strongly advised to read means two things: first, we will
http://tldp.org/HOWTO/NCURSES- instruct the linker to link our
Dev Graphics Internet Multimedia System
Programming-HOWTO, since I will source against the ncurses
touch only the functions used in the library which can be done calling
demo. gcc this way:
gcc -Wall -lncurses snow.c -o
snow
CD/DVD HardDrive USB Drive Laptop Wireless
In order to use ncurses, you will The -l flags instructs the linker

I
first need to install the ncurses to link with the ncurses shared
n this fourth article in the package and the ncurses developers library. And as a result of this we
series, I'll introduce an package: see the output below:
important topic that every C apt-get install libncurses5
programmer should master, libncurses5-dev
because it can cause a whole lot
of problems: dynamic memory
allocation. Failing to use and edb@lapedb:~/fullcircle/c-4$ ldd snow
understand dynamic memory linux-gate.so.1 => (0xb805c000)
allocation (and pointers) correctly libncurses.so.5 => /lib/libncurses.so.5 (0xb7ff7000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7e99000)
will result in memory leaks and
libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7e94000)
application failures (think of the /lib/ld-linux.so.2 (0xb8042000)
well known Segmentation Fault as
an example).

8
When we use ldd (ldd prints the • getmaxyx() to get the
shared libraries required to terminal dimensions
execute a binary), we see that the 1.int main()
• clear() to clear the 2.{
applications require
screen 3. char * field=NULL;
libncurses.so.5 to be available on 4. int row=0;
our system. This also means that • mvaddch() to display 5. int col=0;
running our binary on a system a character at a given 6. initscr(); //nc
with this library not installed will location 7. atexit(exitfun);
not work. 8.
• refresh() to force 9. /* Eternal snow ! */
Now what does ncurses do? output on the terminal 10. while(1)
Well, a text terminal is in fact an 11. {
odd thing - with printf(), we can • endwin() to properly 12. updateFlakes(&field,&row,&col);
write text, but the text always reset the terminal at 13. if(field==NULL)
appears at the end of the line - application exit 14. {
we can't scroll back; we can't • initscr() to initialize
15. break;
16. }
print colors; we can't print bold the ncurses library 17. drawScreen(field,row,col);
characters; etc. There are things 18. sleep(1);
called 'escape sequences' which 19. }
manipulate the cursor behavior
The main() (see Listing 20. return 0;
and the way text is printed on 21.}
1) doesn't do much. It
such a terminal (this all dates Listing 1: main()
initializes the screen (line
from the roots of the history of
6), and every second it
computing), but these escape
updates and array of snowflakes (line
sequences are non-human
12). If that succeeds, it draws them
friendly. Well, ncurses is a form of 1. /* At termination, properly
to the screen (line 17). There is only
wrapper library which eases the close the terminal */
one special thing here and that is the
use of these escape sequences. In 2. void exitfun()
atexit() function. This function is 3. {
my example code, I've added //nc
used to instruct the application that, 4. endwin(); //nc
after a function call when this
prior to termination, this function 5.}
function call belongs to ncurses.
should be called. The contents of this Listing 2: exitfun()
The functions I've used are:
function are shown in Listing 2. All it
does is call endwin(). Note, that the

9
trick used here is called a at compile time, so we need 1./* Update the structure */
'function pointer'. Just as we can to learn this and ask for the 2.void updateFlakes(char ** fieldIn,
have pointers to data, we can amount of memory we need. int *rowIn, int *colIn)
3.{
have pointers to functions too The same happens at the
4. int numnew=0; int row=0; int
(and this is simply the function point of a resize of the col=0; int i=0;
name, without the parentheses). window; then we need to 5. char *field=*fieldIn;
update the amount of 6. getmaxyx(stdscr,row,col); //nc
required memory. This is 7.
In the main(), we have storage done using a combination of 8. /* Create new field */
for the number of rows, the the functions malloc() (line 9. if(field==NULL || *rowIn!=row
number of columns, and the array 15) and free() (line 13). With || *colIn!=col)
10. {
of flakes; we pass these three malloc() (which stands for
11. if(field!=NULL)
parameters to the updateFlakes() memory allocate), you pass it 12. {
function (see Listing 3). This the number of bytes you wish 13. free(field);
function will allocate memory if a to allocate, and it will return a 14. }
change of the terminal dimension pointer to this amount of 15. *fieldIn=malloc(row*col);
is detected. Every time this bytes (or NULL when the 16. field=*fieldIn;
function is called it reads the system is out of memory). 17. memset(field,0,row*col);
dimension of the terminal. If these With a call to free(), you tell 18. *rowIn=row; *colIn=col;
don't match those stored in the the system you no longer 19. }
20.
main function, we allocate a new need the memory. Not
21. /* Apply gravity ! */
array and start from scratch. From combining a malloc() with a 22.
lines 6 to 19, we read the free() properly will result in a memmove(&field[col],&field[0],(row-
dimensions, and reallocate the memory leak and an eventual 1)*col);
memory (and free old memory if it crash of your application. 23. memset(field,0,col);
existed). And this is where Well, that's all there is to it - 24. numnew=random()%(col/2);
dynamic allocation kicks in. easy isn't it? Now, see how 25. for(i=0;i<numnew;i++)
many times you will shoot 26. {
Sometimes you don't know at 27. field[random()%col]=1;
compile time how much memory yourself in the foot using
28. }
you will need. Here, we need one dynamic memory allocation. 29.}
byte for each position on the
The real difficult part in this
screen, but the window isn't fixed Listing 3: updateFlakes
function is the memory

10
juggling. First, we use a one 1 rows and shift these by
dimensional array (char * field) to col bytes. See also Figure 1;
represent two dimensional data the move is illustrated with 1./* Let it snow */
(the 2D screen contents). This the dotted arrow. When that 2.void drawScreen(char * field, int row,
means simply that field[0] is at is done, we zero the new int col)
row 0, col 0, field[1] is at row 0, 'first' row, and place some 3.{
col 1, field[row] is at row 1, col 0 random cells to 1 (implying 4. clear(); //nc
5. int x=0;
and field[row+1] is at row 1, col 1. it will snow there).
6. int y=0;
This is because it's easier to work 7. for(y=0;y<row;y++)
with one large array than with an 8. {
array of arrays. In Figure 1, this is And finally, all we need is 9. for(x=0;x<col;x++)
illustrated for a screen consisting to iterate over the array, 10. {
out of five rows and three and put some snow on the 11. if(field[y*col+x]==1)
columns. We make use of screen. How this is done is 12. {
memset() (line 17 ) to initialize shown in Listing 4. Which is
13. mvaddch(y,x,'*'); //nc
14. }
the allocated array to zero (which nothing more than two for 15. }
is always a good idea, since loops, one to iterate the 16. }
allocated memory usually columns and one to iterate 17. refresh(); //nc
contains junk). the rows - combined with 18.}
the decision whether or not Listing 4: drawScreen()
The real magic however occurs
to print a snowflake.
on line 22, here we use
memmove() to move the first row-

Although only four articles have


been presented, already a lot of
'heavy stuff' has been covered. It can
be clearly seen that, with this article, this path and to focus more and
we're already drifting a bit away from more on Linux specific goodies in
the generic-c-programming, and application development, and
we're making a move towards more from this I wish all you
Linux/Ubuntu specific applications. enthusiasts out there an exciting
The goal in this series is to continue New Year filled with discoveries!
Figure 2 - memmove() in action

11
free the memory in the exit function.
• Get the application up and • Write a while(1) {malloc(1);} A PENNY FOR YOUR
running on your application, and THOUGHTS
own system (you'll confirm that in the
Get the application
need to figure out end your system will
the required up and running on run out of memory.
We want to know what you
headers yourself, your own system... like, or dislike, to help us
• Check the random improve Full Circle to make
hint consult the
and srand manpages to learn how to 2009 even better than 2008.
manpages of the calls which give
seed the random number generator.
implicit declaration errors). We'd really appreciate it if
you could take a few
• Instead of passing exitfun() to
minutes to fill in this short
atexit(), we could as well have
survey:
passed endwin() directly; verify
that this works. Read the atexit http://url.fullcirclemagazine.
manpage to figure out which org/e78bdf
function prototypes it accepts.
Why is it useless to pass a We'll keep the survey up
function which returns a value? until 24th Jan. and publish
the results in the January
• Remove the functionality to issue of FCM.
reallocate the field after a window
size, try resizing the window now, From everyone at Full
is a Circle, we want to wish you
what are the pro and contras? Belgian Linux fanatic,
all the best for 2009, and
currently employed as an
• Note that the currently used thank you for melting our
embedded software engineer
field array isn't free()'ed at with one of the world's leading admins server each month
application exit, this is not a satellite communications with over 20,000 downloads.
problem since this won't cause a companies. Apart from spending
memory leak and the kernel will time with his family, he enjoys
free the memory; nevertheless, playing with technology, and
spends his days waiting for
try making field a global variable Blizzard to finally release Diablo
(place it outside the main() ) and III.

12
HOW-TO
Written by Elie De Brauwer
PROGRAM IN C - PART 5
we will focus more on how we can
make use of C to get things done, 01.int divide(int a, int b)
FCM#17-20 - Program In C - Parts 1-4 how issues with C applications can 02.{
03. return a/b;
be diagnosed, and how 04.}
troubleshooting can be done. 05.
06.typedef int
(*mathFun)(int, int);
We already explained that if int a is 07.
an integer then int * b=&a declares a 08.struct operator

Dev Graphics Internet Multimedia System


pointer b and initializes it to point to 09.{
10. char c;
a. Now, take a look at Listing 1; here 11. mathFun f;
we have a function called divide 12.};
(lines 1-4), and, on line 6, we have a
typedef where we define a new Listing 1
CD/DVD HardDrive USB Drive Laptop Wireless
datatype called “mathFun” - which is

A
a function pointer to a function
fter four articles, most of returning an integer, and taking two function which needs to be
the basic and generic C- integers as an argument. Lines 8-12 called when the user performs
related topics have already define a structure which links a an action. If you have the
been covered. I hope that after character with a function. This manpages-dev package
these articles you can confirm two principle is called a 'callback' (or installed, and type “man qsort”,
things: the first being that C isn't handler), and is used a lot (in fact you will get the definition of a
a terrible large and complex this is how object oriented
function which implements the
language, and the second being programming can be simulated in C;
quicksort algorithm (see also
that it is also a very powerful you define a structure with some
Listing 2), and you can see that
language which allows you to do data and some function pointers and
this function is used for sorting
lots of low-level things. This will this is almost a class). But, it's very
some data, and you should pass
be the last article to cover the common to use this, for example, in
it a function pointer to a function
“basics”; in the coming articles, GUI programming - you register a

8
man scanf for details).
NAME These functions are
qsort - sorts an array
the opposite of printf()
SYNOPSIS
#include <stdlib.h> (and sprintf(), fprintf()
...). Where printf()
void qsort(void *base, size_t nmemb, size_t size, takes a format
int(*compar)(const void *, const void *)); definition to format
DESCRIPTION some variables
The qsort() function sorts an array with nmemb elements of size size. accordingly, and put
The base argument points to the start of the array. this to a destination,
scanf() will read a
Listing 2: man 3 qsort extract
string, dissect the
string according to the
format, and store the result in
capable of doing the comparison we allocate storage for four some variables. Take line 13 for
(this can be useful when you are structures which are filled in with the example; here, it will read a
sorting an array of points, and you operator and the function pointers on “%d” (an integer), and store the
wish to sort them on distance to lines 4-7. Next, there is the user result in the location passed as
the origin). input handling on lines 12 to 18. an argument (note that here we
When the user has entered some pass pointers, with printf()
input, lines 20-32 show a search variables are passed). But
Now, to illustrate how we can through the command array to find there's nothing more to it than
use callbacks, which are typically the entry matching the operator and, that. The format strings are
used to handle events, we will if found, we issue the callback with completely alike. The only
develop a small application which the read data, and print the result. confusing thing might be line 17;
prompts the user for two digits And that's all there is to it. we need a second scanf()
and an operator and, if the because the first one will read
operator is known, it calls the the newline of the previous read.
function with the two digits as Although printf() was already used As with printf(), it is possible to
parameters and prints the result. in the past, this is the first time we have more complex format
Listing 3 shows a basic encounter a scanf()-alike function strings where multiple variables
implementation of this; on line 3 (alike because there are some are read at once; in this case you
variants like sscanf(), fscanf(), ... see will be interested in the return

9
01.int main()
02.{
value of scanf() which is the based on their distance to 03. struct operator functs[4];
number of elements properly the origin, and use the 04. functs[0].c='-'; functs[0].f=&minus;
qsort() function for this.
decoded. I strongly suggest to 05. functs[1].c='+'; functs[1].f=&add;
play a little with scanf(), printf(), • Extend the calculator with 06. functs[2].c='*'; functs[2].f=&multiply;
and various formats, since these the possibility for the user to 07. functs[3].c='/'; functs[3].f=&divide;
enter 'q' to quit.
format strings can be found
08. while(1)
09. {
almost everywhere, and it's very • Modify the application that,
10. int a,b,i;
useful to understand how they instead of entering
characters, the user is able 11. char c;
behave. One important thing to to enter “5 plus 6” or “6 12. printf("Enter a:\n");
keep in mind, when handling minus 5”. In order to do this, 13. scanf("%d",&a);
strings, is to keep track of the you will need to adapt the 14. printf("Enter b:\n");
amount of data you read. structure to hold a string as 15. scanf("%d",&b);
Something as simple as “char the operator, and, instead of 16. printf("Enter the operator:\n");
reading a character, you will
s[10]; scanf(“%s\n”,s);” is the de 17. scanf("%c",&c); // Get the newline
need to read a string. Extra 18. scanf("%c",&c);
facto example of a buffer credit if you manage to do 19. i=0;
overflow, waiting to be exploited; this without buffer overrun 20. while(i<4)
for things like these one should issues (see man getline) and 21. {
limit the amount of bytes read in memory leaks. 22. if(functs[i].c==c)
the format, or use more advanced 23. {
solutions like getline() (man 24. printf("Result:
getline) which dynamically %d\n",functs[i].f(a,b));
allocates more memory if it is 25. break;
26. }
needed.
27. i++;
is a
28. }
Belgian Linux
29. if(i==4)
fanatic, and apart from
spending time with his 30. {
family, he enjoys 31. printf("Unknown operator:
• Write the missing callbacks, and get
the application working. playing with %c\n",c);
technology, and 32. }
• Modify the application to operate on spends his days 33. }
floating point numbers instead of waiting for Blizzard to 34. return 0;
integers. finally release Diablo 35. }
• Write an application which sorts points III.
Listing 3: calc.c main loop

10
HOW-TO
Written by Elie De Brauwer
PROGRAM IN C - PART 6
code, compiling code, testing code, processes. A system call is a
etc.), and there are many tools out function call which transfers
FCM#17-21 - Program In C - Parts 1-5
there. There are even some IDEs control to the kernel for some
(integrated development functions that can be done in
environments) which combine some user space. For example,
of these tools in a nice graphical incrementing a variable is
front-end (e.g. the CDT in the Eclipse translated to a simple assembler
project, kdevelop, Code::blocks, command, but when you do
anjuta, and more), but it is my something which deals with
Dev Graphics Internet Multimedia System
humble opinion that a beginning resources, this always goes past
programmer should first get an idea your kernel. If you read 'man 2
about how things work under the syscalls', you can get a list of all
hood, before he starts using system calls the kernel supports.
shortcuts. Although there are many Now, why is this a good thing to
CD/DVD HardDrive USB Drive Laptop Wireless tools out there which cover many monitor? Well, if you monitor

U
categories, in this article we will which system calls your
ntil now, I have been focus on troubleshooting application makes, you can
presenting to you some code/applications. follow the logical flow of your
code, and instructions on application, and the good thing
how to compile and execute that is that it is non-intrusive, which
code. So, until now, you've strace is one of my best friends. means you can run it on every
probably only needed an editor ltrace is also a nice tool, but I don't binary on your system. As an
(emacs, vi, ...) and a compiler make use of it that often. You can example, I will highlight the
suite (gcc). However, there are install both by typing output of wget, installable by
some other tools which make typing:
sudo apt-get install strace ltrace
developing code easy (bear in sudo apt-get install wget
mind that developing doesn't Now, what do they do? strace
mean only typing source code; it intercepts the system calls made by wget is an application which
covers the entire process - typing

8
fetches an URL from the Internet execve("/usr/bin/wget", ["wget", "-q", "http://www.google.com"], [/*
38 vars */]) = 0
and writes it to disk.
...
If we take a look at the output of stat64("/etc/wgetrc", {st_mode=S_IFREG|0644, st_size=4221, ...}) = 0
open("/etc/wgetrc", O_RDONLY|O_LARGEFILE) = 3
strace wget -q fstat64(3, {st_mode=S_IFREG|0644, st_size=4221, ...}) = 0
http://www.google.com mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
0) = 0xb7ad2000
shown in Fig. 1 (right) we can read(3, "###\n### Sample Wget initializati"..., 4096) = 4096
clearly see some interesting parts read(3, "on:\n#backup_converted = off\n\n# T"..., 4096) = 125
in the execution. read(3, "", 4096) = 0
close(3) = 0
We can see that it starts with a ...
call to 'execve()' (you can use stat64("/home/edb/.wgetrc", 0xbfe57a48) = -1 ENOENT (No such file or
man execve; this goes for each directory)
systemcall - the first word on a ...
Fig. 1
line echoed by strace), which
loads the binary. A bit later, the
application checks if an init file
called '/etc/wgetrc/' exists; it does, stat64("/etc/resolv.conf", {st_mode=S_IFREG|0644, st_size=88, ...}) = 0
and it is read. Next, we see that it socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 4
connect(4, {sa_family=AF_INET, sin_port=htons(53),
tries to open a '.wgetrc' in my
sin_addr=inet_addr("195.130.131.5")}, 28) = 0
home directory, but this file does fcntl64(4, F_GETFL) = 0x2 (flags O_RDWR)
not exist, so this file is not opened. fcntl64(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0
gettimeofday({1234091526, 549043}, NULL) = 0
The next example (Fig. 2, below
poll([{fd=4, events=POLLOUT, revents=POLLOUT}], 1, 0) = 1
right) shows that '/etc/resolv.conf' send(4, "\372\312\1\0\0\1\0\0\0\0\0\0\3www\6google\2be\0\0\1\0\1"...,
is being opened, and that a socket 31, MSG_NOSIGNAL) = 31
is opened to a DNS server, in poll([{fd=4, events=POLLIN, revents=POLLIN}], 1, 5000) = 1
order to resolve the address I ioctl(4, FIONREAD, [367]) = 0
asked for. recvfrom(4,
"\372\312\201\200\0\1\0\6\0\7\0\7\3www\6google\2be\0\0\1"..., 1024, 0,
{sa_family=AF_INET, sin_port=htons(53),
sin_addr=inet_addr("195.130.131.5")}, [16]) = 367
close(4)
Fig. 2

9
edb@lapedb:~$ whereis wget
wget: /usr/bin/wget /usr/share/man/man1/wget.1.gz
Now, isn't this nice? We edb@lapedb:~$ ldd /usr/bin/wget
examined the internals of an linux-gate.so.1 => (0xb7f12000)
application, without taking a libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7ed8000)
look at a single line of code; we librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0xb7ecf000)
libssl.so.0.9.8 => /usr/lib/i686/cmov/libssl.so.0.9.8 (0xb7e88000)
immediately learned where it
libcrypto.so.0.9.8 => /usr/lib/i686/cmov/libcrypto.so.0.9.8 (0xb7d3c000)
stored some config files, which libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7bde000)
ones didn't exist, and how it /lib/ld-linux.so.2 (0xb7ef8000)
translated the DNS entry to an libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0xb7bc5000)
ip address. ltrace works in a libz.so.1 => /usr/lib/libz.so.1 (0xb7baf000)
Fig. 3
similar fashion, but instead of
tracing system calls, ltrace
gives you an idea of which
ltrace wget -q internals without any extra
functions are called and which are
http://www.google.com effort. The only difference is that
located in a dynamically linked they will run a bit slower than
we can find this snippet (some normal, and this allows you to
library, see Fig. 3 (right). spaces omitted): learn what the application is
ldd tells us that wget makes use strlen("www.google.com") = 14 doing, and where something
of libssl (secure connections), dcgettext(0, 0x8075c8a, 5, goes wrong.
libpthread (for creating threads), 0x804e66d, 0xbf8e1761) = 0x8075c8a
libz (compression), and libc getaddrinfo("www.google.com",
NULL, 0xbf8e1780, 0xbf8e17b4) = 0
amongst others. Libc is, in Valgrind can be installed by
calloc(1, 20) = 0x909c1e0
essence, the base of your system. malloc(96) = 0x909c1f8 typing:
It implements generic C functions freeaddrinfo(0x909c100) = <void>
like printf(), malloc(), and free(), sudo apt-get install valgrind
and it implements this logic, often This is the ltrace counterpart of the
It is a collection of tools that do
mapping them on system calls DNS resolution we examined in the
some advanced checking of
(e.g., a printf() maps to a write()). strace output. All the network
applications. See
Now ltrace will tell us where our communication is hidden by a simple
http://www.valgrind.org for more
application makes use of call to 'getaddrinfo()'.
information on the available
functions provided by such a
I hope that you now can appreciate tools. In this article, I will focus
library. So, if we examine the
the value of strace and ltrace. Both only on the most-used tool,
output of
allow you to examine a binary's called 'memcheck'. This tool will
override libc calls that deal with

10
handling memory. And it will do allocates some memory in the main timescale. Some applications,
some bookkeeping – is all function, and then goes into an which leak only a couple of bytes
memory (that is dynamically eternal loop. The first thing I want an hour, might run perfectly for
allocated) given back to the you to do is to run this code, replace years - before all hell breaks
system, and is all the allocated the for loop with a while(1) loop, and loose. This is why valgrind is
memory still reachable? replace the malloc(10) with such a useful tool. This is the
malloc(1000). Start the application, output of Listing 1 on my system
Take a look at Listing 1 (below). and see what happens with your after compiling it with
This is some bad code. It calls a system. Your physical memory will
function leak() (lines 3 to 7) 10 be filled, then your swapspace will
gcc -Wall -g leak.c -o memleak
times, which allocates 10 bytes be filled, and eventually the
and does not free it. Then it displays Fig.4 (following page).
oom_killer (out of memory killer) will
kill the fat When I terminate the while(1)
01. #include <stdio.h> process. Things loop by pressing Ctrl+C, it tells
02. #include <stdlib.h> like this are me how many calls to malloc() I
03. void leak() devastating to a did, how much memory I
04. { system and its allocated, and how much I gave
05. char * ptr = malloc(10); performance. back. And then it concludes that
06. printf("malloc(10) points to: %p\n",ptr); You have just I have lost 100 bytes of memory
07. } observed the in 10 blocks. This means that I
08. int main()
effect of a asked for some memory that I
09. {
10. int i=0; memory leak. can't reach anymore because I
11. for(i=0;i<10;i++) This is the don't have a pointer to it
12. { painful part of (“definitely lost” in the output),
13. leak(); dynamically and it says that I have also
14. } asking for allocated 15 bytes in 1 block,
15. char * ptr = malloc(15); memory - it which, at the moment of
16. printf("malloc(15) in main: %p\n",ptr); should all be termination, I could still free
17. while(1){} because I have a pointer to it.
given back! This
18. return 0;
is the example This is why I had to write the
19.}
of a memory while(1) loop. If I hadn't done
Listing 1: leak.c leak on an that, valgrind would have
extreme concluded that I lost 115 bytes

11
edb@lapedb:~/fullcircle/c-6$ valgrind --leak-check=full --show-
reachable=yes ./memleak
==7257== Memcheck, a memory error detector.
==7257== Copyright (C) 2002-2007, and GNU GPL'd, by Julian
in 11 blocks (verify this!), because valgrind accounts for
Seward et al. what really happens; it doesn't look forward to what
==7257== Using LibVEX rev 1854, a library for dynamic binary might happen in the system.
translation.
One special thing I should still mention here: I told you
==7257== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks
LLP.
==7257== Using valgrind-3.3.1-Debian, a dynamic binary earlier I compiled the code with the '-g' flag, which adds
instrumentation framework.
==7257== Copyright (C) 2000-2007, and GNU GPL'd, by Julian
debugging symbols to the binary. This is why valgrind is
Seward et al. able to tell us at which file and on which line number the
==7257== For more details, rerun with: -v
==7257==
error occurred. If I would compile the binary with
malloc(10) now points to: 0x41a2028
malloc(10) now points to: 0x41a2068
gcc -Wall leak.c -o memleak
malloc(10) now points to: 0x41a20a8
malloc(10) now points to: 0x41a20e8 the output would look like:
malloc(10) now points to: 0x41a2128
malloc(10) now points to: 0x41a2168 ==7339== 100 bytes in 10 blocks are definitely lost
malloc(10) now points to: 0x41a21a8
malloc(10) now points to: 0x41a21e8 in loss record 2 of 2
malloc(10) now points to: 0x41a2228 ==7339== at 0x4025D2E: malloc
malloc(10) now points to: 0x41a2268 (vg_replace_malloc.c:207)
malloc(15) in main: 0x41a22a8 ==7339== by 0x8048405: leak (in
^C==7257==
==7257== ERROR SUMMARY: 0 errors from 0 contexts (suppressed:
/home/edb/fullcircle/c-6/memleak)
11 from 1) ==7339== by 0x8048443: main (in
==7257== malloc/free: in use at exit: 115 bytes in 11 blocks. /home/edb/fullcircle/c-6/memleak)
==7257== malloc/free: 11 allocs, 0 frees, 115 bytes allocated.
==7257== For counts of detected errors, rerun with: -v
==7257== searching for pointers to 11 not-freed blocks. It still is able to tell us we lost some memory, but it can
==7257== checked 52,132 bytes. no longer tell us on which file or line things went wrong.
==7257==
==7257== 15 bytes in 1 blocks are still reachable in loss
record 1 of 2
So, the good news is valgrind telling us if we have a
==7257== at 0x4025D2E: malloc (vg_replace_malloc.c:207) memory leak or not. The bad news is that we need to
==7257==
==7257==
by 0x8048459: main (memleak.c:15)
have a binary with debugging symbols in it if we wish to
==7257== 100 bytes in 10 blocks are definitely lost in loss know the exact location of the leak. We can then
record 2 of 2 recompile the executable to do some troubleshooting - for
==7257== at 0x4025D2E: malloc (vg_replace_malloc.c:207)
==7257== by 0x8048405: leak (memleak.c:5) which we also need the sources!
==7257== by 0x8048443: main (memleak.c:13)
==7257==
==7257== LEAK SUMMARY:
==7257== definitely lost: 100 bytes in 10 blocks. In this article, I introduced some tools that allow you to
==7257== possibly lost: 0 bytes in 0 blocks.
==7257== still reachable: 15 bytes in 1 blocks. do some easy troubleshooting and analysis on binaries,
==7257== suppressed: 0 bytes in 0 blocks.
Fig. 4 12
without the need to have any example on wget but now with an with respect to memory
sources or knowledge of these invalid URL, on which output is it management.
binaries. Next time, we'll even easier to diagnose that the output
• Which others tools are part of
attempt to go a bit deeper, and was a faulty DNS entry.
the valgrind suite, and how
then we'll take a look at using a
• Read the strace manpage; will could these help you in writing
real debugger.
strace automatically follow child higher quality applications?
processes? What measures do you
have to take when tracing a
multithreaded application?
is a
• vmstat is a tool which reports
• Does valgrind automatically trace Belgian Linux fanatic, and
system usage statistics, use apart from spending time
child processes?
strace to figure out which /proc/ with his family, he enjoys playing
file(s) it uses to generate its • Try running valgrind on some of with technology, and spends his
output. your favorite command line tools. days waiting for Blizzard to finally
release Diablo III.
And check if they behave properly
• Repeat the ltrace/strace

13
HOW-TO
Written by Elie De Brauwer
PROGRAM IN C - PART 7
only what happens with memory
(de)allocation. The tool discussed
FCM#17-22 - Program In C - Parts 1-6 here is named gdb (The GNU
debugger), and to this tool there
are no real limits - if there is
something related to an application
which you want to examine, GDB is
the tool. On a regular Ubuntu
system, gdb can be installed by
Dev
entering:
Graphics Internet Multimedia System
sudo apt-get install gdb

All IDE's on a Linux system which


allow debugging will typically have
CD/DVD HardDrive USB Drive Laptop Wireless
the text-mode gdb as a backend.

I
Here, I will focus on using gdb from
n part 6 of this series, I showed the command line, but know that panels. At the top, you have the
you some non-intrusive ways when it comes to complex data panel where you can
of examining applications. In debugging, it can sometimes be display variables and browse
this article, I will present a tool useful to have a graphical view on through their contents. In the
which allows you to dig deeper, to things. One of the older graphical middle, you can see the source
do some post-mortem analysis, frontends on gdb is called (Data panel where the source code is
and to examine the inner working Display Debugger), you can install it shown - here you can place
of an application. Where by typing: breakpoints. And the bottom
strace/ltrace/valgrind are really panel allows you to see the gdb
sudo apt-get install ddd
nice tools, they will show only a interaction. You can either type
part of what really happens; Above right is a screenshot of ddd gdb commands in there, or you
strace shows, for example, only in action. It consists of three large can click the matching buttons.
system calls, while valgrind shows

8
The example in this article is
called . There is already an
ifstat application in Ubuntu, but 01. #include <stdio.h>
this application behaves the same 02. #include <stdlib.h>
but is simpler. The application is 03. #include <string.h>
presented in Listing 1 and Listing 04. #include <unistd.h>
2. The goal of the application is to 05. typedef unsigned long long ull
print, every 2 seconds, the 06. int parseDevFile(const char * iface, ull *bRx, ull *pRx,
07. ull *bTx, ull *pTx)
interface rate of a given network 08. {
interface. It is basically a while 09. FILE * fp = NULL;
loop (Lines 29-49) which reads 10. char * line = NULL;
/proc/dev/net and prints the 11. unsigned int len = 0;
incoming and outgoing interface 12. fp = fopen("/proc/net/dev", "r");
rate for a given network interface 13. if(fp==NULL)
in both kilobytes per second and 14. {
as packets per second. The main 15. return -1;
16. }
function itself is rather simple
17. while(getline(&line,&len,fp)!= -1)
(Lines 51-60). Here we check if 18. {
there is one parameter given from 19. if(strstr(line,iface)!=NULL)
the command line. This one 20. {
parameter will become the 21.
interface the user wants to sscanf(strstr(line,":")+1,"%llu%llu%*u%*u%*u%*u%*u%*u%llu%llu",
monitor. If no parameters, or too 22. bRx, pRx, bTx, pTx);
many parameters, are given, a 23. }
message is printed which
24. }
25. fclose(fp);
instructs the user how to use the 26. free(line);
application. Up until now, nothing 27. return 0;
really new has been shown, all 28. }
new things are in the
parseDevFile() function (Lines 5- Listing 1: ifstat.c (part 1)
28), so the new things are briefly
discussed here. This function will
open /proc/dev/net and parse its

9
29. void dumpInterfaceUsage(const char * iface)
contents, the counters we are 30. {
interested in will be stored in the 31. ull ifaceBRxOld=0, ifaceBTxOld=0, ifacePRxOld=0, ifacePTxOld=0;
bRx, pRx, bTx and pTx pointers 32. ull ifaceBRxNew=0, ifaceBTxNew=0, ifacePRxNew=0, ifacePTxNew=0;
33. const int SLEEP_TIME = 2;
which are passed when calling
34.
this function. By passing pointers, 35.
we are capable of changing the if(parseDevFile(iface,&ifaceBRxOld,&ifacePRxOld,&ifaceBTxOld,&ifacePTx
values of these variables from Old)==-1) return;
within the function. The function 36. sleep(SLEEP_TIME);
will return 0 on success, or -1 37. while(1)
when opening the file has failed. 38. {
39.
In this example, it is the first if(parseDevFile(iface,&ifaceBRxNew,&ifacePRxNew,&ifaceBTxNew,&ifac
time we open a file - on Line 9 ePTxNew)==-1) return;
there is a file pointer declared. 40. printf("%s In: %8.2f kbyte/s %5llu P/s Out: %8.2f kbyte/s
%5llu P/s\n", iface,
Line 12 contains a call to fopen()
41. (ifaceBRxNew-ifaceBRxOld)/(SLEEP_TIME * 1024.0),
(man fopen for details), the first 42. (ifacePRxNew-ifacePRxOld)/SLEEP_TIME,
argument is the file we want to 43. (ifaceBTxNew-ifaceBTxOld)/(SLEEP_TIME * 1024.0),
open, the second argument says 44. (ifacePTxNew-ifacePTxOld)/SLEEP_TIME);
how we want to open this file. In 45. ifaceBRxOld=ifaceBRxNew; ifaceBTxOld=ifaceBTxNew;
this case “r” means we want to 46. ifacePRxOld=ifacePRxNew; ifacePTxOld=ifacePTxNew;
open the file for reading. Once we 47. sleep(SLEEP_TIME);
are done with reading from the 48. }
file, we close it using fclose() on 49. }
50.
Line 25. 51. int main(int argc, char **argv)
52. {
53. if(argc != 2)
Let's discuss C-style I/O: 54. {
fopen(), fclose(), fread(), fwrite() 55. printf("Usage: %s interfacename\n", argv[0]);
calls are part of the C-standard, 56. exit(1);
and these should be available on 57. }
58. dumpInterfaceUsage(argv[1]);
each platform. open(), close(), 59. return 0;
read(), write(), however, are part 60. }
of the POSIX standard, and these
Listing 2: ifstat.c (part 2)
10
are the actual internal system Lines 19-24 do the actual parsing flags passed to the compiler, this
calls. One usually uses fread() of the line read from the file. Line 19 means that debugging symbols
when reading from a file. checks if the interface name is are embedded within my binary,
However, if you look at the somewhere within the line we read and this will allow the debugger
manual page, it would tell you (meaning we read enough lines). If to get more precise information.
that you need to specify a buffer - we are at the correct line, sscanf()
the size of an element and how will be used to convert the values on When I try to start the
many elements to read - and this the line to the unsigned long long application, and I pass by
is not really convenient in our variable we are using in the accident 'b' as the interface
case. This is why we make use of application. Notice that the '*' within name, the application behaves
getline(); this function takes a the formatstring means that we are as follows:
pointer to a pointer as first not interested in this value. edb@lapedb:~/fullcircle/c-7$
argument, and a pointer to an ./ifstat b
Now, compiling and running the
integer as a second argument. Segmentation fault
application gives the output below
Internally, this function will always
when I examine the activity of my Now, what happened here:
read a full line, and it will either
wireless link. apparently our application tried
copy the data to the buffer passed
if there is enough room, or it will to access some memory which
reallocate a new buffer if there is didn't belong to the application,
not enough room (see man Unfortunately, this article is about the kernel didn't like this, and
getline for details). All we should debugging, and although this sent us a signal SIGSEGV. As a
keep in mind is to free the pointer example seems to behave now, it is result, the application
getline() allocated for us (Line 26). far from perfect. Notice that I terminated. There are two
compiled the example with the -ggdb options we could adopt in this
situation; we could either restart
the application in our debugger
and do some live debugging
edb@lapedb:~/fullcircle/c-7$ gcc -ggdb -o ifstat ifstat.c
edb@lapedb:~/fullcircle/c-7$ ./ifstat wlan0
there. Or we could obtain a core
wlan0 In: 1.36 kbyte/s 16 P/s Out: 1.50 kbyte/s 16 P/s file and do some post mortem
wlan0 In: 103.25 kbyte/s 84 P/s Out: 4.61 kbyte/s 54 P/s debugging. When you encounter
wlan0 In: 1.29 kbyte/s 15 P/s Out: 1.50 kbyte/s 16 P/s a situation like this with any of
the packages your distribution
has to offer, and you file a bug

11
report, people will often ask you the application was terminated due and we see here that we are stuck
for a core file. It's useful to know to a segmentation violation. We at a line which contains a 'b'
how to create these core files, so entered where, and gdb responded (which we passed as interface),
that's what we'll do first. with a backtrace - a list of all but the strstr() which searches for
functions that were called - we see a ':' has returned NULL since there
edb@lapedb:~/fullcircle/c-7$
ulimit -c unlimited we started at main, then entered is not ':' in the header. So,
dumpInterfaceUsage, then entered sscanf() tried to read from
edb@lapedb:~/fullcircle/c-7$ parseDevFile, which called sscanf. memory address 1.
./ifstat b Thus, usually one hopes (and here
In order to have the same effect
one is usually correct) that the
on a live session, start gdb, and
Segmentation fault (core problem lies within the code you just
pass the binary as the first
dumped)
wrote, and not within the library you
argument. At the gdb prompt, you
called. So our guess here would be
edb@lapedb:~/fullcircle/c-7$ type run followed by the startup
that we did something wrong when
ls -hal core arguments. And the same will
calling sscanf(). So, to be sure, I
happen:
-rw------- 1 edb edb 280K 2009- asked gdb to print the line variable,
03-07 13:33 core

With ulimit, limits to certain edb@lapedb:~/fullcircle/c-7$ gdb ifstat core


resources can be set, the size of a GNU gdb 6.8-debian
corefile is one of these resources, Copyright (C) 2008 Free Software Foundation, Inc.
and nowadays this is by default License GPLv3+: GNU GPL version 3 or later
set to 0. When we set this to <http://gnu.org/licenses/gpl.html>
unlimited, an application can This is free software: you are free to change and redistribute it.
dump a core file (a core file is a There is NO WARRANTY, to the extent permitted by law. Type "show
copying"
dump of the working memory of and "show warranty" for details.
an application). Now let's take a This GDB was configured as "i486-linux-gnu"...
look at it using gdb (right).
warning: Can't read pathname for load map: Input/output error.
Now what have we done here? Reading symbols from /lib/tls/i686/cmov/libc.so.6...done.
We started gdb, and passed our Loaded symbols for /lib/tls/i686/cmov/libc.so.6
binary, and the core file, as Reading symbols from /lib/ld-linux.so.2...done.
startup arguments. gdb told us
NOTE: and several other libc.so.6 errors.

12
edb@lapedb:~/fullcircle/c-7$ get a gdb prompt when the showing an expression every
gdb ifstat breakpoint is encountered. We time) on the line pointer which
decide to step through this function contains our string (the output is
(gdb) run b
by issuing a number of steps a bit trimmed down for
Starting program: commands (this equals executing formatting reasons). But we see
/home/edb/fullcircle/c- one line of code). After the fopen() that we go through the while
7/ifstat b call, we investigate whether the file loop without executing the
Program received signal pointer is valid; it seems it is. So we sscanf. So we can only conclude
SIGSEGV, Segmentation fault. decide to put a display (this is that the interface “bla” does not
0xb7fd26c7 in rawmemchr ()
from
/lib/tls/i686/cmov/libc.so.6 edb@lapedb:~/fullcircle/c-7$ gdb ifstat
(gdb) break parseDevFile
But here we did not make use of Breakpoint 1 at 0x80485da: file ifstat.c, line 11.
the core file. The following (right) (gdb) run bla
Starting program: /home/edb/fullcircle/c-7/ifstat bla
is the output of a live session. Breakpoint 1, parseDevFile (iface=0xbf96175d "bla", bRx=0xbf961290,
When we started the pRx=0xbf961280, bTx=0xbf961288, pTx=0xbf961278) at ifstat.c:11
11 FILE * fp = NULL;
application with 'bla' as a
(gdb) step
parameter, we saw that all our 12 char * line = NULL;
rates remained zero. So we (gdb) step
decided to take a look. If 13 unsigned int len = 0;
something goes wrong, we (gdb) step
suspect it to be in parseDevFile, 15 fp = fopen("/proc/net/dev", "r");
so by calling break parseDevFile, (gdb) step
we tell gdb to place a breakpoint 16 if(fp==NULL)
when this function gets called. (gdb) print fp
$1 = (FILE *) 0x9e20008
This means the application will (gdb) step
start and work as normal, but it 21 while(getline(&line,&len,fp)!= -1)
will interrupt and present a gdb (gdb) display line
shell each time the breakpoint is 1: line = 0x0
met. After setting the breakpoint, (gdb) step
we start the application and we 23 if(strstr(line,iface)!=NULL)

13
NOTE: and several 'line = 0x9e20170' errors.
exist. When we issue cont to But I hope that this is sufficient to let application! Make sure it prints a
continue execution, we see the the reader understand that gdb warning when an interface
next time the program encounters allows you to examine how an cannot be found, and make the
the breakpoint we are dropped application is running; how it is interface matching more
back to the gdb shell. making use of the system. And I intelligent.
strongly advise everybody who
works with C applications to invest
In this article I introduced first some time in getting to learn to work is a
the concept of C style I/O, and the with gdb, since this will prove to be Belgian Linux fanatic, and
use of getline(), but I also gave a an extremely valuable tool when it apart from spending time
comes to troubleshooting with his family, he enjoys playing
bird's eye overview of gdb. Due to with technology, and spends his
limited space, I have been able to applications. When it comes to
days waiting for Blizzard to finally
only scratch the surface of gdb. exercises for this article, fix the release Diablo III.

' ' is
reviewed on page 23 of this issue.

14
HOW-TO Program in C - Part 8
sequence will look like:
0,1,1,2,3,5,8,13,21,... and it is
FCM#17-23 - Program In C - Parts 1-7
immediately clear that this is 01. #include <stdio.h>
an ideal job for a computer to 02.
generate. But there's a catch: 03. typedef unsigned long long fibo_type;
04. #define FIBO_FORMAT "%10llu"
these numbers get very large, 05.
very quickly. The Fibonacci 06. void printFibo(fibo_type num)
sequence has some other 07. {
interesting properties and 08. printf(FIBO_FORMAT,num);
09. }
various other, more efficient 10.
Dev Graphics Internet M/media System algorithms to generate a 11. int main()
certain number. 12. {
13. int num=0;

Finding limits
14. fibo_type a=0,b=1,c
15.
CD/DVD HDD USB Drive Laptop Wireless 16. printf("%4d: ",++num); printFibo(a);
In Listing 1, a small
printf("\n");

C
17.
application is shown where the 18. printf("%4d: ",++num); printFibo(b);
omputers and main loop (lines 11 to 29) printf("\n");
mathematics have defines three variables a, b and 19.
c, which will contain the
20. c=a+b;
always been best 21. while(c>=b)
friends. Perhaps this previous, current and next 22. {
is the reason why so many number of the Fibonacci 23. printf("%4d: ",++num); printFibo(c);
bugs exist. To illustrate, this sequence. In each iteration the printf("\n");
numbers are shifted, and a
24. a=b; b=c; c=a+b;
article will work around a 25. }
common problem known as new next value is calculated. 26. printf("Stopped after %d digits\n",num);
overflow. As an example, we There is, however, one odd 27. printFibo(c); printf("\n");
will work with the so called thing - the condition of the 28. return 0;
while loop on line 21. It reads
29. }
Fibonacci sequence, which
starts with zero and one, and 'c>=b', but c equals b+a so Listing 1: Fibonacci.c
the next value in the sequence from a mathematical viewpoint
is calculated by adding the two this expression is worthless
previous digits. This means the since it will always be true.

full circle magazine #24 10 contents ^


PROGRAM IN C - PART 8
However, this application which have access to a larger digit at a time, bring carry into can offer you.
isn't running in a mathematical range. But keep in mind that the calculation, etc. For
utopia, it is running inside a one looses precision. This can addition and subtraction, this Listing 2, which can be
computer, and this means that, be even more dangerous since can be done, but once working compiled with the command:
in the case of a 32 bit unsigned the number appears to be with multiplication, division,
integer, if you add one to correct but in fact isn't (if in and square roots, things are gcc -Wall -lgmp Fibonacci2.c
0xffffffff, the result will be 0x0. doubt ask the people who getting rather tricky, and it -o Fibonacci2
This means an overflow has wrote the Ariane 5 rocket gets very unlikely that they will
occurred, the new value cannot software). be implemented efficiently. shows an implementation of
be expressed using only 32 bits Adding two digits is as efficient the same algorithm, but now it
(0x100000000), and the result Conclusions so far: It's nice as adding two integers, so uses GMP. Lines 12-15 initialize
has been calculated modulo-32 that there are an infinite adding two four-digit numbers a container, and set the
bits number of integers. Wouldn't it the manual way is at least four container to a certain value.
(0x100000000&0xffffffff=0x0). be nice if we could be able to times slower than the integer Behind the scenes, GMP
In other words, a wrap has actually use all of them? version. allocates storage for you, and
occurred. The same happens performs all the needed
bookkeeping. Lines 18 to 25
when working with signed Breaking limits Now, luckily we live in an (at
show the main loop, which will
values, but here you will least for a part) open world,
overflow the sign bit first, and and we are not required to never terminate. Here the
Well, actually we can use mpz_add function is used to
you will end up with a large them all, but there will be a reinvent the wheel ourselves.
negative value. There is a library called GMP add two integers and store the
price in efficiency. Adding two result in an mpz_t. This
32-bit values is bleeding fast, (GNU Multiple Precision
On line 3 and 4 there is a Arithmetic Library, see replaces the c=a+b. And
in fact a simple assembly mpz_swap is used to get the
definition of a fibo_type and a instruction is able to do the http://gmplib.org), which offers
FIBO_FORMAT. These are used all this functionality and much, order right. We only use two
trick, but then again you're variables here and one swap,
to easily modify the application stuck with the 32-bit limit (this much more, and all we need to
to other datatypes. This way it do for it is type sudo apt-get instead of three variables and
may vary depending on cpu two swaps we used in Listing 1.
is possible to experiment type, but there will be some install libgmp3-dev. This library
where the boundary lies when offers us a lot of functionality, The second part of the while
limit). But there's a work- loop, lines 22-24, creates a
using a signed value or a short. around. Instead of using an but, in this article, we'll only
In the case of an unsigned long scratch the surface a little. I base-10 string representation
integer we could use an array of the mpz_t, prints it and frees
long, this application is able to and implement the addition strongly encourage the reader
calculate 94 Fibonacci numbers. to take a look at the API the storage (note: there is
ourselves, simply by doing it room for improvement here,
the same way we learned to do documentation at
One could also experiment http://gmplib.org/manual/ to see exercises). Lines 26-30 are
it in primary school: and one unreachable code, but they
using floating point numbers, see the possibilities this library
full circle magazine #24 11 contents ^
PROGRAM IN C - PART 8
illustrate how the internal point data types in Fibonacci.c.
structure should be cleared. Do you get more numbers? Are
This clearly states how powerful they correct? Where do things
01. #include <stdio.h> this library is. From a start going wrong?
02. #include <stdlib.h> programmer's perspective, all
03. #include <string.h> we need to do is replace our • Skim through the GMP api
04. #include <gmp.h> initialization of our variables, documentation and get familiar
05.
06. int main() and replace the addition by a with the possibilities of the
07. { library call. Behind our backs, library.
08. int num=0; the library took care of
09. mpz_t f_1; everything. But keep in mind • Read the GMP manual, and
10. mpz_t f_2;
11. that these 'simple' additions search for help on mpz_get_str.
12. mpz_init(f_1); are in fact rather heavy Now, rewrite Fibonacci2 so that
13. mpz_init(f_2); computations, and it would be memory is not allocated and
14. mpz_set_ui(f_1,0); a bad idea not to use an integer freed every time, but is
15. mpz_set_ui(f_1,1);
16. printf("%10d: 0\n",++num); for num. reallocated when more digits
17. are required.
18. while(1) Now this application will give
19. { us a truly eternal (well actually
20. mpz_add(f_1,f_2,f_1);
21. mpz_swap(f_1,f_2); num will overflow after 2^31
22. char * res = mpz_get_str(NULL,10,f_2); Fibonacci digits) feed of
23. printf("%10d: %s\n",++num, res); Fibonacci numbers in a style
24. free(res); what would only envy The
25. }
26. Matrix.
27. mpz_clear(f_1);
28.
29.
mpz_clear(f_2);
return 0; Exercises
30. }
• Try running the application for
Elie De Brauwer
Listing 2: Fibonacci2.c all different data types in
Fibonacci.c, signed and
unsigned versions of char,
short, long and long long, and
try to pinpoint their limits.

• Try the same using floating

full circle magazine #24 12 contents ^

Das könnte Ihnen auch gefallen