Michael Brudno 8/1/00 C C - C++ is what Java is based on. It also happens to be a horror to write anything in it. It is actually losing its vogue in the buiseness: most of the modern systems are actually written in either C, or more recently Java. C++ is a horror to debug, a horror to write in, and just a horror overall. That is why I'll teach you C, which is syntactically cleaner, but is still a horror to debug. In general, however, C++ is the Object Oriented Version of C: They took a very good, compact, programming language and added on an OOP part (Classes, templates and the like) to make a monster. C/C++, suffer from a deficency (or an advantage) that nothing is defined. the results of semi-illegal operation will not ususally cause errors: execution may just happily continue and you may never find what the bug is. Explicit Pointers -------- -------- In Java you have two basic types: primitive types and reference types. The two are quite distinct. Primitive types are only a few things: ints, shorts, doubles, etc. Anything which you as a programmer define is going to be a reference type. You can never get your hands on the object itself, you always deal with a pointer to it. In C there is no such distinction between primitives and objects: you can get your hands on the object itself, while you can also have pointers to primitive types. consider the following declarations: int a = 5; //Just like in java, declare a to be equal to 5 int *b; //This is new: b will be a pointer to an int b = &a; //b will now be equal to the memory address of a *b = 6; //dereference b, and write 6 into the resulting memory address. After you are done with these operations a will also be equal to 6. Lets consider what the box and pointers will look like after each line is executed: ___ 1. a |5| originally we have just the variable a, it's value equal to 5. 2. b[ ] we add b to our name space, and it initially contains an undefined value (not null!) 3. _ a [5] ^ | b [ ] after line 3 b points to the location of a in memory. 4. _ a [6] ^ | b [ ] after line 4 the value to which b pointed was changed, and hence a was too. This concept of pointers is extended to classes, but this will be covered later. If you remember early in the course we stressed the idea that in Java the arrays are actually pointers to some object in memory which hold the values of whatever we have in the array. Well, in C the story is not much different. When you declare an array, you actually create a pointer to it's first element. Thus the C equivalent of the java declaration int[] k = new int[5]; is int *k = (int*) malloc (5 * sizeof(int)); It is important to note that malloc will always return a pointer (to the newly allocated object). Because k is a pointer, we can do all sorts of weird stuff with it: instead of writing k[0], for instance, we could write *k. Instead of k[p] we can write *(k+p). Thus in C you can add to pointers, subtract from them and to other weird stuff. For instance, given the declaration of k above, I could write: k[0] = 7; k = k+1; printf("%d", k[-1]); this will print out 7, because I readjusted k to point to the second element of itself, thus the 7. I am not sure whether all versions of C support negative indecies for arrays, but the one I am using (gcc) does. Once we are done using the array however, we must return it. No automatic garbage collection! free(k); Stack v Heap Storage ----- - ---- ------- C provides you with another way to declare arrays. The syntax int k[5]; creates an array of 5 integers, but not on the heap (as you are used to), but on the stack. k is declared as a const int *, a pointer whose value cannot change. Again, you don't have access to the array as is, just to a pointer to it. However the pointer cannot change (if you have another int n[], the statement k = n is illegal.) When you try to return k from a procedure you wrote you are actually returning a pointer to the array. But if the array was declared on the stack it will no longer be there when you exit from the procedure, and the pointer to it is actually pointing to garbage. This is perhaps the most common mistake of the beginning C programmer. And as usual, the compiler will not warn you, your program will execute ok, and you will be sitting there, wondering why that element you just assigned to be a 5 is suddenly 4955321 or some other weird number. However always allocating memory on the heap is also dangerous: perhaps the most common bug in C is memory leaks, when you forget to de-allocate some piece of memory you created. As a result your program will run out of memory. Remember, unlike Java there is no automatic garbage collection done for you. Structures (section by Jonathan Shewchuk). | struct DListNode { ---------- | void *item; C doesn't have classes, but it does have | struct DListNode *next; structures, which are agglomerations of data. | struct DListNode *prev; At right, we have a declaration of a DListNode | }; structure, which includes two pointers to other | DListNode structures. | struct DListNode theNode; | struct DListNode otherNode; Don't forget the semicolon at the end of the | struct DListNode *nodePtr; structure declaration! Another syntactic | difference between structures and classes is the | theNode.next = &otherNode; need to write "struct DListNode" instead of just | nodePtr = &theNode; "DListNode" in variable declarations. | (*nodePtr).prev = NULL; | /* ^ Sets theNode.prev */ There's a much more dramatic difference. If you write theNode otherNode "DListNode theNode" in Java, you declare theNode to be -------- -------- a _reference_ to a DListNode. In C/C++, when you write |item ?| |item ?| "struct DListNode theNode", you declare theNode to be |next .+--->|next ?| a _whole_structure_. To declare a _pointer_ (reference) |prev X| |prev ?| to the structure, use "*" as in the declarations of -------- -------- "next" and "prev" above. To _create_ a pointer to a ^ structure, use "&" as in the line "nodePtr = &theNode;". |---[.] nodePtr Just as arrays, you can declare structs both on the stack (as above) or on the heap: struct DListNode* nodeptr = (struct DListNode *) malloc(sizeof(struct DListNode));