Pointers
Heap & Pointers
● Types of storage:
– global (defined in the static data segment)
– automatic or local (defined in the program stack)
– dynamic
● Dynamic memory blocks required by the program(mer) come from a memory pool
called a heap—they are allocated and deallocated
● C does not have garbage collection. All allocated variables must be deallocated by the
program(mer)
● A pointer is a variable whose value is a memory address representing the allocated
memory block
Declaring a Pointer
● Different types of pointers required for different data blocks:
– int *p; /* An uninitialized pointer to an integer number or an
array of integer numbers of size sizeof(int) */
– char *s; /* A pointer to a character array—a string (if NULL-
terminated) */
– void *v; /* An unstructured uninitialized pointer—USE WITH
CAUTION! */
– int *p1, *p2, p3; /* Two integer pointers and an integer */
– int **pp; /* A pointer to a pointer */
– double ***foo; /* A pointer to a pointer to a double pointer */
● Types of pointers can be modified by casting:
– int *p = …;
– char *c = (char *)p; /* Now, c points to the first byte of the
number! */
– c++; /* Now, it points to the second byte! */
● Casting pointers should be avoided.
Declaring a Pointer
● Different types of pointers required for different data blocks:
– int *p; /* An uninitialized pointer to an integer number or an
array of integer numbers of size sizeof(int) */
– int* p1; /* Where and whether you put the space, is up to you */
– char *s; /* A pointer to a character array—a string (if NULL-
terminated) */
– void *v; /* An unstructured uninitialized pointer—USE WITH
CAUTION! */
– int *p1, *p2, p3; /* Two integer pointers and an integer */
– int **pp; /* A pointer to an integer pointer */
– double ***foo; /* A pointer to a pointer to a double pointer */
● Types of pointers can be modified by casting:
– int *p = …;
– char *c = (char *)p; /* Now, c points to the first byte of the
number! */
– c++; /* Now, it points to the second byte! */
● Casting pointers should be avoided.
Initializing a Pointer
● The & operator calculates the address of a static or automatic variable:
– int z = 0;
– int *zp = &z; /* The address of z is now in zp */
– printf (“z=%i, &z=%xn”, z, zp);
● Remember that the address of an automatic variable makes no sense outside of the
function:
– int *foobar (void) {
– int localVar = 617363;
– int *ptr = &localVar;
– return ptr; /* Bad idea! After foobar returns, localVar is no
more!—Unless it's also static */
– }
Dereferencing a Pointer
● To dereference a pointer is to obtain the value of the variable that it refers to. Operator
* dereferences a pointer:
– int var1 = 77, var2;
– int *ptr = &var1;
– var2 = *ptr; /* Now the value of var2 is 77 */
– (*ptr)++; /* Now, var1 is 78 */
– *ptr++; /* Dereference the pointer and then increment it; var1 is
still 78, but ptr changed by 1 */
– (*ptr) = 10; /* Now, var1 is 10 */
● Operators & and *, if properly used, are complementary: *&x is the same as x.
However, &*x is not legal.
“Constant” Pointers
● A pointer to a constant;
– const int *p; /* p can change, but *p cannot */
– int const *p; /* same as above */
● A constant pointer to a variable:
– int *const p; /* *p can change, but p cannot */
● A constant pointer to a constant:
– const int *const p; /* nothing can change */
Generic Pointers
● A generic pointer cannot be dereferenced:
– void *generic = ….;
– *generic = ... /* Illegal */
● Any pointer can be safely cast to a generic pointer:
– int var = 564;
– int *iptr = &var;
– void *generic = (void*)iptr;
● A generic pointer can be cast to a specific pointer of the original type, if known:
– *(int*)generic; /* 564 */
● What's a NULL? It's a macro defined in stdlib.h:
– #define NULL (void*)0
Pointer Arithmetic
● Operators +, -, ++, and – increment/decrement pointers by the number of object sizes:
– char *s = …;
– s++; /* s is incremented by 1 */
–
– int *ptr = …;
– ptr += 2; /* ptr is increased by 2*sizeof(int) */
● Very useful to work with arrays in general and strings (NULL-terminated character
arrays) in particular:
– char *source = “Hello, world”; /* source is the address of the
first element of the string */
– char *dest = …; /* allocate memory for the copy */
– while (*dest++ = *source++); /* copy while not NULL */
● Pointers of the same type can be subtracted, and the difference is the number of
objects between hgem:
– int diff = ptr2 – ptr1;
● Pointers of the same type can be compared with >, >=, <, <=, ==, and !=. Comparing
the pointers does not involve comparing the memory they point to.
Memory Allocation
● Memory allocation functions are defined in stdlib.h. They return a pointer to a freshly
allocated block or NULL in case of failure.
● Function void *malloc(size_t) gets a block of uninitialized memory.
– int *myArray;
– if (NULL == (myArray = malloc (32 * sizeof(int))) {
– perror (“malloc”);
– exit (EXIT_FAILURE);
– }
● Function void *calloc(size_t,size_t) gets a block zero-filled memory.
– if (NULL == (myArray = calloc (32, sizeof(int))) {...
● Function void *realloc(void*, size_t) changes the size of a previously allocated block
and returns a new pointer, if necessary. The content of the block is preserved.
– if (NULL == (myArray = realloc (myArray , 64 * sizeof(int))) {…
● If the return value is not saved, the allocated block is inaccessible (memory leak).
Memory Deallocation
● Any previously allocated block must be deallocated with free():
– free (myArray);
● The value of myArray did not change, but should not be used anymore. For safety,
nullify it:
– myArray = NULL;
Working with Memory Blocks
● memcpy() copies one block to another if they do not overlap
● memmove() copies one block to another; the blocks may overlap
● memcmp() compares two memory blocks, bytewise
● bzero() zero-fills a block
The Mystery of scanf()
● All parameters to scanf, expect for the format string, must be pointers to the previously
allocated storage variables:
– int a;
– double b;
– char c;
– char *str = malloc (128);
– if (4 != scanf (“%i %lf %c %s”, &a, &b, &c, str)) {… /* str is
already a pointer */
The Mystery of FILE*
● FILE* is a pointer to a variable of type FILE, which is defined in stdio.h. In fact, the
standard I/O streams are simply variables of this type:
– FILE *stdin, *stdout, *stderr;
Binary I/O
● Function long ftell(FILE*) returns the current reading/writing position in an open file.
● Function int fseek(FILE*, long offset, int mode) changes the current position in an open
file by offset. The mode can be SEEK_SET (from the beginning of the file), SEEK_CUR
(from the current position) or SEEK_END (from the end of the file).
– fseek (f, sizeof (double), SEEK_CUR); /* go to the next double */
● Function size_t fread(void *buff, size_t size, size_t count, FILE *f) reads size*count
bytes into the previously allocated buffer buff from the previously open file f:
– const int BUFF_SIZE = 1024;
– FILE *infile = fopen(“myfile.txt”, “r”); /* check return value */
– char *data = malloc (BUFF_SIZE); /* check return value */
– if (BUFF_SIZE != fread (data, 1, BUFF_SIZE, infile)) {…
● Function size_t fwrite(void *buff, size_t size, size_t count, FILE *f) writes size*count
bytes from the previously allocated buffer buff to the previously open file f. Both
functions return the number of successfully read/written objects.
Passing Arguments by Reference
● If you pass a pointer to an object to a function, the function can modify the object:
– void addToInt (int *ptr, int change) {
– (*ptr) += change;
– }
– ...
– int val = 10;
– addToInt (&val, 5); /* val is 15 now */
● Always pass large objects (arrays and structs) by reference
● If the object shall not be modified, use a const pointer:
– void functionThatShallNotChangeX (const int* x) { ...
● Pass small objects by reference only when the function shall change their value
Pointers to Blocks of Pointers
● Memory-allocating functions can allocate memory for pointers to other blocks:
– int **table;
– table = malloc (sizeof (int*) * 100); /* a table of 100 integer
pointers */
– for (i = 0; i < 100; i++)
– table[i] = malloc (sizeof (int) * 256); /* each pointer, in
turn, points to a block of 256 integers */
–
– /* Did I tell you that C does to define variables only before the
first executable statement of a function? */
–
– int *q = table[0]; /* the address of the first block */
– int c = table[0][0]; /* the value at the beginning of the first
block */

C for Java programmers (part 2)

  • 1.
  • 2.
    Heap & Pointers ●Types of storage: – global (defined in the static data segment) – automatic or local (defined in the program stack) – dynamic ● Dynamic memory blocks required by the program(mer) come from a memory pool called a heap—they are allocated and deallocated ● C does not have garbage collection. All allocated variables must be deallocated by the program(mer) ● A pointer is a variable whose value is a memory address representing the allocated memory block
  • 3.
    Declaring a Pointer ●Different types of pointers required for different data blocks: – int *p; /* An uninitialized pointer to an integer number or an array of integer numbers of size sizeof(int) */ – char *s; /* A pointer to a character array—a string (if NULL- terminated) */ – void *v; /* An unstructured uninitialized pointer—USE WITH CAUTION! */ – int *p1, *p2, p3; /* Two integer pointers and an integer */ – int **pp; /* A pointer to a pointer */ – double ***foo; /* A pointer to a pointer to a double pointer */ ● Types of pointers can be modified by casting: – int *p = …; – char *c = (char *)p; /* Now, c points to the first byte of the number! */ – c++; /* Now, it points to the second byte! */ ● Casting pointers should be avoided.
  • 4.
    Declaring a Pointer ●Different types of pointers required for different data blocks: – int *p; /* An uninitialized pointer to an integer number or an array of integer numbers of size sizeof(int) */ – int* p1; /* Where and whether you put the space, is up to you */ – char *s; /* A pointer to a character array—a string (if NULL- terminated) */ – void *v; /* An unstructured uninitialized pointer—USE WITH CAUTION! */ – int *p1, *p2, p3; /* Two integer pointers and an integer */ – int **pp; /* A pointer to an integer pointer */ – double ***foo; /* A pointer to a pointer to a double pointer */ ● Types of pointers can be modified by casting: – int *p = …; – char *c = (char *)p; /* Now, c points to the first byte of the number! */ – c++; /* Now, it points to the second byte! */ ● Casting pointers should be avoided.
  • 5.
    Initializing a Pointer ●The & operator calculates the address of a static or automatic variable: – int z = 0; – int *zp = &z; /* The address of z is now in zp */ – printf (“z=%i, &z=%xn”, z, zp); ● Remember that the address of an automatic variable makes no sense outside of the function: – int *foobar (void) { – int localVar = 617363; – int *ptr = &localVar; – return ptr; /* Bad idea! After foobar returns, localVar is no more!—Unless it's also static */ – }
  • 6.
    Dereferencing a Pointer ●To dereference a pointer is to obtain the value of the variable that it refers to. Operator * dereferences a pointer: – int var1 = 77, var2; – int *ptr = &var1; – var2 = *ptr; /* Now the value of var2 is 77 */ – (*ptr)++; /* Now, var1 is 78 */ – *ptr++; /* Dereference the pointer and then increment it; var1 is still 78, but ptr changed by 1 */ – (*ptr) = 10; /* Now, var1 is 10 */ ● Operators & and *, if properly used, are complementary: *&x is the same as x. However, &*x is not legal.
  • 7.
    “Constant” Pointers ● Apointer to a constant; – const int *p; /* p can change, but *p cannot */ – int const *p; /* same as above */ ● A constant pointer to a variable: – int *const p; /* *p can change, but p cannot */ ● A constant pointer to a constant: – const int *const p; /* nothing can change */
  • 8.
    Generic Pointers ● Ageneric pointer cannot be dereferenced: – void *generic = ….; – *generic = ... /* Illegal */ ● Any pointer can be safely cast to a generic pointer: – int var = 564; – int *iptr = &var; – void *generic = (void*)iptr; ● A generic pointer can be cast to a specific pointer of the original type, if known: – *(int*)generic; /* 564 */ ● What's a NULL? It's a macro defined in stdlib.h: – #define NULL (void*)0
  • 9.
    Pointer Arithmetic ● Operators+, -, ++, and – increment/decrement pointers by the number of object sizes: – char *s = …; – s++; /* s is incremented by 1 */ – – int *ptr = …; – ptr += 2; /* ptr is increased by 2*sizeof(int) */ ● Very useful to work with arrays in general and strings (NULL-terminated character arrays) in particular: – char *source = “Hello, world”; /* source is the address of the first element of the string */ – char *dest = …; /* allocate memory for the copy */ – while (*dest++ = *source++); /* copy while not NULL */ ● Pointers of the same type can be subtracted, and the difference is the number of objects between hgem: – int diff = ptr2 – ptr1; ● Pointers of the same type can be compared with >, >=, <, <=, ==, and !=. Comparing the pointers does not involve comparing the memory they point to.
  • 10.
    Memory Allocation ● Memoryallocation functions are defined in stdlib.h. They return a pointer to a freshly allocated block or NULL in case of failure. ● Function void *malloc(size_t) gets a block of uninitialized memory. – int *myArray; – if (NULL == (myArray = malloc (32 * sizeof(int))) { – perror (“malloc”); – exit (EXIT_FAILURE); – } ● Function void *calloc(size_t,size_t) gets a block zero-filled memory. – if (NULL == (myArray = calloc (32, sizeof(int))) {... ● Function void *realloc(void*, size_t) changes the size of a previously allocated block and returns a new pointer, if necessary. The content of the block is preserved. – if (NULL == (myArray = realloc (myArray , 64 * sizeof(int))) {… ● If the return value is not saved, the allocated block is inaccessible (memory leak).
  • 11.
    Memory Deallocation ● Anypreviously allocated block must be deallocated with free(): – free (myArray); ● The value of myArray did not change, but should not be used anymore. For safety, nullify it: – myArray = NULL;
  • 12.
    Working with MemoryBlocks ● memcpy() copies one block to another if they do not overlap ● memmove() copies one block to another; the blocks may overlap ● memcmp() compares two memory blocks, bytewise ● bzero() zero-fills a block
  • 13.
    The Mystery ofscanf() ● All parameters to scanf, expect for the format string, must be pointers to the previously allocated storage variables: – int a; – double b; – char c; – char *str = malloc (128); – if (4 != scanf (“%i %lf %c %s”, &a, &b, &c, str)) {… /* str is already a pointer */
  • 14.
    The Mystery ofFILE* ● FILE* is a pointer to a variable of type FILE, which is defined in stdio.h. In fact, the standard I/O streams are simply variables of this type: – FILE *stdin, *stdout, *stderr;
  • 15.
    Binary I/O ● Functionlong ftell(FILE*) returns the current reading/writing position in an open file. ● Function int fseek(FILE*, long offset, int mode) changes the current position in an open file by offset. The mode can be SEEK_SET (from the beginning of the file), SEEK_CUR (from the current position) or SEEK_END (from the end of the file). – fseek (f, sizeof (double), SEEK_CUR); /* go to the next double */ ● Function size_t fread(void *buff, size_t size, size_t count, FILE *f) reads size*count bytes into the previously allocated buffer buff from the previously open file f: – const int BUFF_SIZE = 1024; – FILE *infile = fopen(“myfile.txt”, “r”); /* check return value */ – char *data = malloc (BUFF_SIZE); /* check return value */ – if (BUFF_SIZE != fread (data, 1, BUFF_SIZE, infile)) {… ● Function size_t fwrite(void *buff, size_t size, size_t count, FILE *f) writes size*count bytes from the previously allocated buffer buff to the previously open file f. Both functions return the number of successfully read/written objects.
  • 16.
    Passing Arguments byReference ● If you pass a pointer to an object to a function, the function can modify the object: – void addToInt (int *ptr, int change) { – (*ptr) += change; – } – ... – int val = 10; – addToInt (&val, 5); /* val is 15 now */ ● Always pass large objects (arrays and structs) by reference ● If the object shall not be modified, use a const pointer: – void functionThatShallNotChangeX (const int* x) { ... ● Pass small objects by reference only when the function shall change their value
  • 17.
    Pointers to Blocksof Pointers ● Memory-allocating functions can allocate memory for pointers to other blocks: – int **table; – table = malloc (sizeof (int*) * 100); /* a table of 100 integer pointers */ – for (i = 0; i < 100; i++) – table[i] = malloc (sizeof (int) * 256); /* each pointer, in turn, points to a block of 256 integers */ – – /* Did I tell you that C does to define variables only before the first executable statement of a function? */ – – int *q = table[0]; /* the address of the first block */ – int c = table[0][0]; /* the value at the beginning of the first block */