Showing posts with label C. Show all posts
Showing posts with label C. Show all posts

12 October 2010

How to pass a two dimensional array in C

int a[rows][cols];
void f(int **a);

...

f(a);

...


Guess what? Compiler complains about this (a correctly implemented compiler, that is)! You cannot pass! Instead, you should declare the function prototype to be the following:

void f(int (*a)[cols]);

or

void f(int a[][cols]);


See 2.10 in http://www.lysator.liu.se/c/c-faq/c-2.html. This is a commonly made mistake!

The differences between write() and C library IO functions?

write() is a system call, the strings or characters it writes doesn't get buffered by a user-space buffer. C library IO functions like fputs() ,fprintf() or puts() is user space code; all the data they write is written to a user space buffer (you don't notice this if all you are writing is user space codes, if you are doing system programming with some user space codes you will find that the data actually gets buffered). To make such data out of buffer, use fflush(). Check the man page of fflush() yourself.

IPC using UNIX pipes

Pipe is the easiest form of UNIX interprocess communication, but there is a few tips to be remembered before using it.

Pipes inside a single process is basically useless; therefore we usually do piping with fork(). And here comes one important concept: pipes can only help RELATED processes communicate, meaning only processes that forked or created by the same ancestor can communicate using pipes. Non-related processes can communicate with each other by other forms of channel like shared memory or sockets.

If you want n processes to communicate through pipes, you'll need at least n-1 different pipes. This is because one pipe can only connect two processes.

So how do with use pipes with forks? First you need to create all the pipes (using pipe()) you need in the 'oldest' parent before any forking occurs. This way all the pipes created get inherited by all the descendants. A bit of caution here: 'pipes get inherited' meaning that all the file descriptors have their distinct copies for each child process; however, each copy actually refers to the SAME file (an end/terminal of a pipe/channel in the kernel); in other words, the channel inside the kernel does not have copies, the channel is the channel, both ends of the channel are referenced/referred by several copies of file descriptors having identical names.

So now you can do forks. But how? different ways of forking creates different architecture/processes tree. If you want to create a pipeline among a series of processes, it is better you use a 'chain' of processes architecture. For reference (a nice one), check this out: http://tinyurl.com/2fonwzn.

After the necessary setup mentioned in the previous paragraphs, you need to do some necessary 'closing' (close()) and 'duping' (dup2()) in each child process to actually make each pipe works correctly.

To visualize the concepts mentioned above, here is a link: http://tinyurl.com/6xx88e.

17 September 2010

Caution when redirecting stdin/stdout/stderr in C

You must save the original preopened file descriptors using dup(). You then use dup2(), open() to do IO redirection. After done with IO redirection, you need to restore default stdin/stdout/stderr using sdup2() again, otherwise you program cannot interact with STDIO properly as it could before IO redirection! The previous article on this blog shows a good code example on how to do that.

C sample code - Program Using Pipes and IO redirection


Posted from Diigo. The rest of my favorite links are here.

15 September 2010

Important concepts about Unix Pipes architectures

  • UNIX pipe concepts

    • One important thing to note here is that each process in the pipeline is a child of the original child of the shell (pid 202)

    • They are not children of each other the further down the pipeline we go

    • Another thing to note is that only the shell (process 163) executes a wait. All the others simply die after they exec their respective command

Posted from Diigo. The rest of my favorite links are here.

09 September 2010

Memory leaks gone away!

I debugged all day and finally figured out what went wrong with my codes and now no memory leaks possessed by my cute little program! Thanks to valgrind and the following blog:

http://www.linuxprogrammingblog.com/using-valgrind-to-debug-memory-leaks

That blog helped me rethink about the usage and meaning of valgrind message. There were two memory leaks in my program, and both of them were obvious ones. If valgrind complains about obvious memory leaks ('definitely lost' category), then your program must have obvious memory leaks! Indeed, I just found how stupid I was not being able to spot those mistakes immediately!

Be cautious when you allocating heap memory with conditional branches in your codes. That is really a common mistakes.

Now I can move forward.

24 August 2010

C header files

Do not put variable definition in header files! Header files are only for declarations not for definitions! Put definitions globally in .c source files and use extern keyword to reference those global variables. The header guards (#ifdef and #endif) only prevent inclusion of the same source file, not for avoiding multiple definitions for the same variable!

C keywords concepts

Some important concepts about C keywords -

(1) keyword extern : it can be used both on variables and function declaration. And its purpose for both usages are the same, which is, to make one variable or function defined globally in one file visible by other source files. When used on a function declaration, it has the same effect as without it; all function declarations implicitly have the extern keyword stuck in front of them. The point is: it is much clearer to define the global in one place and then declare extern references to it in all other places. So it is a good programming practice and engineering. When you write reasonable big software in C you are going to need it for good software engineering and make linker happy. Do not put extern declarations in header files; put them in C source files!

07 August 2010

How to access environments variables in your C program under UNIX

"The ISO/ANSI C standard requires that a C library include the getenv function, which retrieves the value of a named environment variable. Both the name and value are character strings."

Use getenv function! Don't use getpwuid(getuid())->pw_dir to access struct passwd! getenv is a handy function to access environments variables like HOME and PWD.