C++ to C in an Hour
Main Differences
struct instead of class
I/O is different, using printf and scanf instead of cin and cout
Function prototypes are subtlely different.
Memory management is more basic, using malloc and free
Can still make programs object-oriented and modular.
Comments
// doesn't work in C, only in C++ and Java
Must use /* blah */ instead in ANSI C.
This works with C, C++ and Java, so use it.
Structures instead of classes
In C++
class Employer { int number; Person *employees; void hire(Person p); void fire(Person p); }
Structures instead of classes
In C
typedef struct Employer Employer; struct Employer { int number; Person *employees; } void employer_hire(Employer me, Person p); void employer_fire(Employer me, Person p);Putting the structure name within the function name is a good idea, to avoid clashing with any other functions called hire or fire.
The instance of the structure you are working on (the "object" in O-O terminology) is the first parameter. In C++, that object is implicit and is always called this. In C, we must give it an explicit parameter name.
Recursive structures
typedef struct Employer Employer; typedef struct Person Person; struct Employer { int number; Person *employees; } struct Person { int number; Employer *employers; }Note that the typedefs are both before the structure definitions. This allows the names to be used within either structure.
Strings
Strings are just arrays of ASCII chars, and terminated by a char of value 0.
What does the string "Hello world" look like in memory?
H e l l o w o r l d /0Here's how to find the length of a string:
int strlen(char *s) { int length; for (length = 0; *s != '/0'; s++) length++; return length; }Functions such as strlen are already defined, just
#include <string.h>
The main function
The main function should be defined as
int main(int argc, char *argv[]) { /* some code */ return 0; }The argc parameter tells you how many parameters were passed on the command line, and the argv parameter is an array of strings containing those parameters. There is an extra string at the end of the array, which is guaranteed to be NULL.
Output
In C++ you can print something to the standard output stream by using << with the stream cout:
cout << i << s; // C++In C we use the printf function:
printf("%d%s", i, s); /* C */Or we can use the fprintf function and the stdout stream:
fprintf(stdout, "%d%s", i, s); /* C */There is also a predefined stream called stderr which works in the same way as stdout, and corresponds to the cerr stream in C++.
Using I/O in C
To use any C input/output functions, we must do the following:
#include <stdio.h>This allows the current source file to know about the standard I/O functions, such as printf. It's the C equivalent of doing the following in C++:
#include <iostream>The stdio.h header file should also include a definition of NULL as something like
#define NULL ((void*)0)so you should never need to declare this yourself. Note it is NULL in C, not null (as in Java).
Using printf
The %d and %s in printf tell the function how to print the other parameters.
%d means print a decimal integer, e.g. 1234
%x means print a hexadecimal integer, e.g. f1d0
%lx means print a hexadecimal long integer, e.g. f1d0d1d0
%f means print a floating point number, e.g. 3.14159
%s means print a string, e.g. Hello world.
Look up how the precision works, using man printf.
Input
There is a standard input stream stdin which works like cin. Functions such as scanf automatically use stdin, so
cin >> i >> s; // C++becomes
scanf("%d%s", &i, s); /* C */or
fscanf(stdin, "%d%s", &i, s); /* C */Note the need for pointers to int (but strings are already pointers to char).
C++ equivalents to printf and scanf
In C++ there are functions called form and scan which do the same thing as printf and scanf:
cout.form("%d%s", i, s); // C++ cin.scan("%d%s", &i, s); // C++
Function Prototypes
Use void when defining a function prototype if there is no return type, or no parameters to the function.
void func(void); /* ANSI C */This is different to Java and C++, where you can write
void func(); /* Java */Put prototypes and definitions of structures into header files, which have a suffix of .h
Source Code Files
C source code files are suffixed with .c and should contain functions and any definitions which you want to use just inside that file. If you want a function to not be visible outside the file, declare it using the static keyword.
static void func(int x, int y) { /* some code here */ }If you want a function to be visible outside the file, put a function prototype in a header file, and declare the function normally. Put declarations and constants into header files too if another file will need them.
#define BUFFER_SIZE (1<<27) int countlength(char *name);
Header Files and #include
Names of header files traditionally end in .h
Never #include a C source code file, only #include header files.
Inside a header, just put function prototypes, enums and #defines, and struct and union definitions. Don't put anything which compiles to actual code. Specifically, don't put functions inside a header.
Also, avoid including another header from inside a header.
The << and >> Operators
Bit shift operators move bits around in an integer. Does not perform I/O in ANSI C.
int i, j; i = 0x0039; j = i << 4; /* j now 0x0390 */ j = j << 8; /* j now 0x9000 */ j = j >> 4; /* j now 0x0900 or 0xF900 */ j = j & 0x0F00; /* j now 0x0900 */Left shifting puts zeros into the new bits, but right shifting may put zeros or ones if the number is negative (it's implementation dependent).
Memory management in C
Memory is an array of bytes in the C language (and in most computer's hardware). C has functions to ask for blocks of that memory from the operating system (malloc) and return such blocks to the operating system for use by other programs (free):
Employee *e; e = malloc(sizeof(Employee)); init_employee(e); /* your own initialiser */ /* do some work using e ... */ free(e);If you do not free a block of memory, it will be freed at the end of the program for you. Sometimes you will want to free the memory during the running of the program, however.
Type conversion
In the C language, there are few circumstances where type conversion occurs automatically.
This is a good thing.
In C++, you can sometimes convert one type of data into another type of data implicitly (automatically):
string s = "123"; int i = s;This is bad news. This feature has deliberately not been implemented in Java, because type conversion should, by and large, be explicit - the programmer should control it.
There are exceptions to this rule, but in general, automatic type conversion can lead to errors being silenced (always a bad thing).
Type conversion in C
In C:
char *s = "123"; int i = (int) s; /* doesn't work */The above does not work. The only type conversions in C are between numeric types such as int and float. Use functions such as atoi(s) to return the integer value printed inside a string.
atoi stands for alphanumeric string to integer. You can guess what atof does.
The abort function
What does abort do?
It crashes your program, and on UNIX systems it causes a core dump.
Why are core dumps good?
Because they produce debugging information.
Using gdb
The gdb program is a debugger which can tell you where an error occurred in your program.
Use it like this:
bash$ ztest 3 ztest: overwriting the end of a block. zfree: end buffer corrupted at offset 10. Block length is 10. Start buffer is 0x5AFEC0DE. End buffer is 0xC0CAC01A. Abort (core dumped) bash$ gdb ztest core Core was generated by `ztest 3'. Program terminated with signal 6, Aborted. #0 0xef774594 in _kill () (gdb) where #0 0xef774594 in _kill () #1 0xef73a62c in abort () #2 0x11314 in zfree (v=0x22860) at zutil.c:146 #3 0x10c78 in main (argc=2, argv=0xeffff8dc) at ztest.c:52 (gdb)
Using Makefiles
Makefiles specify rules which allow the compiler to just recompile the bits which have changed since the last compilation. They look like this:
rcat: rcat.o zutil.o gcc rcat.o zutil.o -o rcatThe above is one single rule, called rcat. Note that the second line must have a tab character at the start. To use this makefile to create the rcat program, type:
make rcatThe rule specifies that the files rcat.o and zutil.o are needed before we can proceed. (The make program knows how to turn .c files into .o files). The second line of the rule says what to do after that, in this case we are using gcc to compile the object files into an executable called rcat.
Makefiles must be named makefile or Makefile.
Compiler Warnings are Good
Turn compiler warnings on because they help you find bugs.
gcc -ansi -Wall -g -pedanticThis turns on a lot of warnings for common problems. Often the compiler is better at noticing low-level details than I am.
On your compiler at home, turn on ANSI C mode, and switch on as many warnings as seem sensible. Always test your code at university using gcc before submitting.