/* ** $Id: arrays.c 736 2008-02-09 00:17:15Z phf $ ** ** Just some random functions to explain array stuff. */ #include #include #include #define SIZE 4 // better than having "4" all over the place below // Start reading in main(), come back up here when we // call the following functions from main(). void bar() { puts( "--------------------" ); } // Print an array of doubles of the given length. // Note that arrays don't have a ".length" field // like in Java, and note that we can't enforce // that callers pass an appropriate length. Sad. // Also note that the array is *not* copied! We // see that in clear_array() as well. void print_array( double array[], int length ) { for (int i = 0; i < length; i++) { printf( "%f\n", array[i] ); } } // Clear an array of doubles, setting them all to // 0.0 or so. This *modifies* the array we pass, // so it doesn't get copied. What really gets // passed is a pointer to the first element, but // the details have to wait until next lecture. void clear_array( double array[], int length ) { for (int i = 0; i < length; i++) { array[i] = 0.0; } } // Just to illustrate that a plain int gets // copied, the assignment here does *not* affect // the int we pass! void hmm( int x ) { x = 10; } // Since it would be a mistake for print_array() // to modify the array (maybe by accident) we can // use C's "const" feature to say "this thing will // not be changed" and have the compiler check it. // A good rule of thumb is to make everything const // unless you *really* need to change it. :-) void print_const( const double array[], const int length ) { for (int i = 0; i < length; i++) { printf( "%f\n", array[i] ); //array[i] = 27.1; // doesn't work, try it! } //length = 12; // doesn't work either, try it! } // A version of strlen(), but the *real* strlen() looks a // bit different as we'll see in the next lecture... :-) int slen( char s[] ) { int l = 0; while (s[l] != '\0') { l += 1; } return l; } int main( int argc, char *argv[] ) { // We'll get to some of these declarations later... int i; // Forget about the "*" for the moment, the "[]" for "argv" // above means that it's an array of stuff (strings in this // case). We've seen this in the first lecture already: for (i = 0; i < argc; i++) { puts( argv[i] ); } // One thing to notice compared to Java: Arrays in C don't // know how long they are (there's no ".length"). Instead, // the "argc" parameter tells us how long the array "argv" // really is. bar(); // We declare arrays like this: double numbers[SIZE]; // We can initialize an array like this: for (i = 0; i < SIZE; i++) { numbers[i] = i; } // We can print it in the obvious way: for (i = 0; i < SIZE; i++) { printf( "%f\n", numbers[i] ); } // We can also initialize arrays like this: double more[SIZE] = {4, 3, 2, 1}; // This is called an "array initializer" and it only works // when creating/defining an array, not later. // more = {0, 0, 1, 1}; // won't work, try it! // Again, we can print it in the obvious way: for (i = 0; i < SIZE; i++) { printf( "%f\n", more[i] ); } // If we use an initializer, we can even leave out the // size of the array, the compiler will fill in the right // size for us: double fun[] = {5, 6, 7, 8}; for (i = 0; i < SIZE; i++) { printf( "%f\n", fun[i] ); } // Of course we can pass arrays to functions as well, for // example we can print the same arrays using the print_array() // function defined above; note that we have to pass the // length of the array explicitly again. bar(); print_array( numbers, SIZE ); bar(); print_array( more, SIZE ); // Now here's a scary example; we just printed numbers[] // and saw 0, 1, 2, 3 as the output. Now we call clear_array() // and print again. bar(); clear_array( numbers, SIZE ); print_array( numbers, SIZE ); // And behold: The function was able to *change* the array // passed to it. The reason is that C passes basic types // "by value" (making a copy) it array types "by reference" // (not making a copy, just another name for existing boxes) // instead. Compare this with an example that just uses an int: bar(); int j = 4711; hmm( j ); printf( "%d\n" , j ); // As you see, "j" is *not* changed at all even though // an assignment is made inside the hmm() function. // If you want to make sure that a function does *not* // accidentily an array passed to it, you can use the // "const" keyword as shown in the following variation // of print(): bar(); print_const( more, SIZE ); // Here's an example that illustrates how passing the // "wrong" length goes undetected by the C compiler: bar(); print_array( more, SIZE-2 ); // too short, but safe bar(); print_array( more, SIZE+2 ); // too long, dangerous! // Arrays can't be assigned to each other using the // usual "=" operator. If we wanted to copy one array // into another, we'd have to write a function to do // so. // numbers = more; // won't work, try it! // Comparisons seem to work, but they don't do what // you would expect: bar(); clear_array( numbers, SIZE ); clear_array( more, SIZE ); printf( "%d\n", numbers == more ); // false although content identical printf( "%d\n", numbers < more ); // mystery part 1 printf( "%d\n", numbers > more ); // mystery part 2 // Strings in C are basically just arrays of type "char"; // by convention, strings are "terminated" with a '\0' // character (i.e. to find the length of a string, you // run down the string looking for '\0' somewhere. Here's // a basic string: bar(); char name[] = "Bla"; puts( name ); // There's a correspondence between arrays and pointers // as we'll see next week in detail. For now, we could // also write the same string like this: char *game = "Chess"; puts( game ); // In these examples, the C compiler essentially builds // an array of 4 or 5 characters (since the '\0' is added // automatically when you use the notation with quotes). // You could also initialize everything yourself: char same[] = {'B', 'l', 'a', '\0'}; puts( same ); // Bad things happen if you forget to add a '\0' at the // and of a string: char fame[] = {'B', 'l', 'a'}; char some_crap[] = "Yuck!"; char some_other_crap[] = "Aha!"; puts( fame ); // horrible, prints BlaYuck! instead of just Bla puts( some_crap ); puts( some_other_crap ); // There are a lot of functions for strings in the standard // C library, here are just a few examples: char source[] = "This is the source!"; char target[] = "Target for all the other stuff we do!"; bar(); printf( "%s\n", source ); printf( "%s\n", target ); printf( "%zu\n", strlen( source ) ); // length of a string // Of course we can write functions that deal with strings // ourselves, here we call our own slen() function, doing // exactly what strlen() does. printf( "%d\n", slen( source ) ); // length of a string // We need a function to compare strings, this returns a // negative number, 0, or a positive number depending on // the outcome of the comparison. printf( "%d\n", strcmp( source, source ) ); // comparing strings printf( "%d\n", strcmp( source, target ) ); // comparing strings printf( "%d\n", strcmp( target, source ) ); // comparing strings // We also need a function to copy/assign strings around. strcpy( target, source ); // copy a string printf( "%s\n", target ); // Note that at this point the "rest" of the previous "target" // is still around. We can see this if we replace target[19] // which strcpy set to '\0' with another character and print // again. target[19] = 'X'; printf( "%s\n", target ); // You can find many more string function by looking up // "man string"; note that many of these are "dangerous" // since a missing '\0' somewhere can have dire consequences. // If you take a course in computer security, you are bound // to run into this again, together with a recommendation to // always use explicit lengths (for example strncpy instead // of strcpy). return EXIT_SUCCESS; }