C Programming Basics II Xianyi Zeng xzeng@utep.edu Department of Mathematical Sciences The University of Texas at El Paso. September 20, 2016.
Pointers and Passing by Address Upon declaring a variable, space in the stack is allocated to store its value. double x; The address of this chunck of storage is called the pointer to the variable. Pointer is a special data type. double *ptr x = &x; Some familiar examples: scanf("%lf",&x); printf("%lf\n",x); How to declare: double *ptr1, x, y, *ptr2=null;
Pointers and Passing by Address Pointers to different variable types are different data types. All pointers have the same size (4/8 bytes on 32/64-bit machine). A pointer is the address at the beginning of a block of memory. Pointers cannot be used uninitialized! The following will generate a run-time error. int* myptr; *myptr = 3; A correct version: int val; int* myptr = &val; *myptr = 3; Or instead, one can use dynamic memory allocation to create space in heap for a pointer at run-time.
Pointers and Passing by Address In C, function arguments are passed by value: When we call a function, variables local to this function block are created according to the argument list. Thus only the values of the arguments are passed to the function body, not the memory spaces of the arguments in the function call. Example: Consider a function that increases an integer by one: void increase int by one( int val ) { val++; } The next piece of code int a = 3; increase int by one( a ); printf("%d\n",a); will print out 3 rather than 4.
Pointers and Passing by Address Passing by address (pointer) to modify the value of an input argument: When an input argument is a pointer, the value of the address is copied. The function body can still use this address to get access to the same location in the memory. The example revisited: Consider a function that increases an integer by one: void increase int by one( int *val ) { (*val)++; } The next piece of code int a = 3; increase int by one( &a ); printf("%d\n",a); will print out 4.
Encapsulation and Structures Let s think about how do we have a function modify the value of variables: Assign the return value to this variable: a=sqrt(a); Pass by pointer: increase int by one( &a ); Declare a global variable. Encapsulate all the data and define a new data type. We will use two keywords of C: typedef: Define a new data type. typedef double my real; struct: A collection of variables of known data types. struct Books { }; char Title[255]; char Author[255]; int Year; double Price;
Encapsulation and Structures In this example, we can declare a book variable by: struct Books a book; Alternatively, we combine the two and use: typedef struct Books {... } Book; and declare a book variable by: Book a book; Note: The typedef is not required in C++.
Encapsulation and Structures Another example of typedef: Combined with enum. We can define a new variable type that can only takes finite number of possible values: typedef enum Meals { BREAKFAST; LUNCH; DINNER; } Meal; Meal my last meal = DINNER; Another example of struct: The linked list data structure. Linked list is one of the simplest structures that allow dynamic size. One visit the members one by one until the end (NULL) is hit. struct LLData { }; OtherDataType data; LLData* next lldata; Advantage: Easy to delete/insert a new element. Disadvantage: No random data access, larger overhead over arrays.
Arrays and Memory Management C uses arrays ([][][]) to assign contiguous memory space for a number of variables of the same type. int M[10][10]; struct Books mybooks[100]; To access an element of the array: scanf("%d",&m[1][2]); printf("%d\n", M[1][2]); and struct Books tempbook = mybooks[90]; mybooks[90] = mybooks[91]; mybooks[91] = tempbook;
Arrays and Memory Management Array and pointer. double x[100]; In this case, x is actually the beginning address of the array: x == &(x[0]); // is true. And x+1 is the address of x[1]: One can use: printf("%lf\n",*(x+10)); Passing an array to a function can modify its values. void somefunction( int M[][10] );
Arrays and Memory Management In previous cases, the array sizes are known at compile time. An alternative approach is to allocate spaces dynamically. malloc: Allocate a single block of requested size of bytes. double* ptr = malloc( 100 * sizeof(double) ); calloc: Allocate multiple blocks of request elements. double* ptr = calloc( 100, sizeof(double) ); it is almost equivalent to malloc plus initilization to zero. malloc and calloc allocate space on the heap and must be freed by: free( ptr ); otherwise there is a bug known as memory leak. Compare to: double ptr[100]; ptr[100] allocate space on the stack and the space is freed automatically upon destroying the variable.
C-style Strings Strings are arrays of chars that end with a null ( \0 ). It is not necessary to allocate space with exact string length: char mystring[80]; strcpy( mystring, "Today is Tuesday" ); In this case, mystring can hold up to 79 characters. Include <string.h> for several useful string operations. Get the actual length by strlen. strcpy/strcmp/strcat. These functions rely on the existence of \ or enough space for holding the target. They do not perform check on bounds. strncpy/strncmp/strncat. These functions take an additional argument, the number of characters to operate on (in an at most sense). However, they do not guarantee, for example, there is an \0 attached to the destination.