Computer Organization and Design Pointers Arrays and Strings

  • Slides: 23
Download presentation
Computer Organization and Design Pointers, Arrays and Strings in C Montek Singh Feb 19,

Computer Organization and Design Pointers, Arrays and Strings in C Montek Singh Feb 19, 2018

C vs. Java ã For our purposes C is almost identical to Java except:

C vs. Java ã For our purposes C is almost identical to Java except: l C has “functions”, JAVA has “methods” Ø function == method without “class” Ø i. e. , a global method l C has “pointers” explicitly Ø Java has them (called “references”) but hides them under the covers Ø JVM takes care of handling pointers, so the programmer doesn’t have to ã C++ is sort of in-between C and Java In this class, we will see how pointers/references are implemented in C

What is a “pointer” in C? ã A pointer is an explicit memory address

What is a “pointer” in C? ã A pointer is an explicit memory address ã Example l int i Ø i is an integer variable in memory Ø located at, say, address 1056 l int *p Ø p is a variable that “points to” an integer Ø p is located at, say, address 2004 l p = &i Ø the value in p is now equal to the address of variable i Ø i. e. , the value stored in Mem[2004] is 1056 (the location of i) Memory address i 1056 1060 1064 1068 p 1056 2000 2004

Referencing and Dereferencing ã Referencing an object means Memory l … taking its address

Referencing and Dereferencing ã Referencing an object means Memory l … taking its address and assigning it address to a pointer variable (e. g. , p = &i) ã Dereferencing a pointer means i 5 l … going to the memory address pointed to by the pointer, and accessing the value there (e. g. , *p) 1056 1060 1064 1068 ã Example int i; int *p; p = &i; *p = 5; // // // i is an int variable p is a pointer to int referencing i p is assigned 1056 dereference p i assigned 5 p 1056 2000 2004

Pointer expressions and arrays ã Dereferencing could be done to an expression l So,

Pointer expressions and arrays ã Dereferencing could be done to an expression l So, not just *p, but can also write *(p+400) Ø accesses memory location that is 400 th int after i ã Arrays in C are really pointers underneath! l int a[10]; // array of integers l a itself simply refers to the address of the l a is the same as &a[0] l a is a constant of type “int *” l a[0] is the same as *a l a[1] is the same as *(a+1) l a[k] is the same as *(a+k) l a[j] = a[k]; is the same as *(a+j) = *(a+k); start of the array // address of a[0]

Pointer arithmetic and object size ã IMPORTANT: Pointer expressions automatically account for the size

Pointer arithmetic and object size ã IMPORTANT: Pointer expressions automatically account for the size of object pointed to l Example 1 Ø if p is of type “int *” Ø and an int is 4 bytes long Ø if p points to address 1056, (p+2) will point to address 1064 Ø C compiler automatically does the multiply-by-4 Ø BUT… in machine language, we will have to explicitly do the multiply-by-4 l Example 2 Ø char *q; // char is 1 byte Ø q++; // really does add 1 Memory address i 1056 1060 1064 1068 p 1056 1064 2000 2004

Pointer examples int i; int a[10]; int *p; // simple integer variable // array

Pointer examples int i; int a[10]; int *p; // simple integer variable // array of integers // pointer to integer p = &i; p = a; p = &a[5]; *p *p = 1; *(p+1) = 1; p[1] = 1; p++; // // & means address of a means &a[0] address of 6 th element of a value at location pointed by p change value at that location change value at next location exactly the same as above step pointer to the next element

Pointer pitfalls int int i; // a[10]; *p; // simple integer variable // array

Pointer pitfalls int int i; // a[10]; *p; // simple integer variable // array of integers pointer to integer(s) So what happens when p = &i; What is value of p[0]? What is value of p[1]? Very easy to exceed bounds l C has no bounds checking!

Iterating through an array ã 2 ways to iterate through an array l using

Iterating through an array ã 2 ways to iterate through an array l using array indices void clear 1(int array[], int size) { for(int i=0; i<size; i++) array[i] = 0; } l using pointers void clear 2(int *array, int size) { for(int *p = &array[0]; p < &array[size]; p++) *p = 0; } l or, also using pointers, but more concise (more cryptic!) void clear 3(int *array, int size) { int *arrayend = array + size; while(array < arrayend) *array++ = 0; }

Pointer summary ã In the “C” world and in the “machine” world: l a

Pointer summary ã In the “C” world and in the “machine” world: l a pointer is just the address of an object in memory l size of pointer itself is fixed regardless of size of object l to get to the next object: Ø in machine code: increment pointer by the object’s size in bytes Ø in C: increment pointer by 1 (compiler knows object’s size) l to get the i-th object: Ø in machine code: add i*sizeof(object) to pointer Ø in C: add i to pointer ã Examples: l int R[5]; // 20 bytes storage l R[i] is same as *(R+i) l int *p = &R[3] is same as p = (R+3) (p points 12 bytes after start of R)

Strings in C ã There is no string type in C �� What? !

Strings in C ã There is no string type in C �� What? ! l Only low-level support for strings as character arrays Ø char s[] // array of characters Ø char *s // pointer to the beginning of a string l But a rich library of string processing functions (string. h) Ø reading: scanf(), fgets(), etc. Ø printing: printf(), puts(), etc. Ø processing: strcpy(), strlen(), strcat(), strcmp()

Strings in C: NULL termination ã All C functions assume string terminates with a

Strings in C: NULL termination ã All C functions assume string terminates with a NULL l NULL = ASCII 0 character Ø also written as ‘’ ã Example: l “hello” is actually { ‘h’ ‘e’ ‘l’ ‘o’ ‘’ } l uses 6 characters, not 5 Ø so, for a string with N real characters, declare it as char S[N+1] l but C functions define its length as 5 Ø strlen(“hello”) returns 5 l fputs(), printf(), etc. will print the string until they see a ‘’ ã Be mindful of the terminating character!

Declaring strings statically ã Statically (if size is known at compile time) l char

Declaring strings statically ã Statically (if size is known at compile time) l char S[6] = “hello”; // compiler puts in the size l char string_array[5][10]; l char S[] = “hello”; Ø an array of 5 strings, each up to 9 characters long (plus NULL) Ø string_array[0] is the 0 -th (very first) string Ø string_array[4] is the 4 th (last) string Ø string_array[0][4] is the 4 th character of the first string Ø etc.

Declaring strings dynamically ã Dynamically (if size is known only at run time) 1.

Declaring strings dynamically ã Dynamically (if size is known only at run time) 1. declare a pointer Ø 2. determine size (at run time), e. g. , 99 real characters + NULL Ø 3. char *s; size is 100 allocate space in memory Ø Ø s = malloc(100); BUT remember: there is no bounds checking, so do not put a string with more than 99 real characters in s… ã Comparison to Java l char *s = malloc(100); l char[] s = new char[100]; // in C // in Java ã When finished with string l free(s); // free up the 100 bytes l Java: no need to free; JVM does garbage collection

Declaring strings statically/dynamically ã Examples 1. Declare an array of NUM strings, each at

Declaring strings statically/dynamically ã Examples 1. Declare an array of NUM strings, each at most LEN long (incl. the terminating NULL), where NUM and LEN are known at compile time Ø char string_array[NUM][LEN]; 2. Declare array of NUM strings, where only NUM is known at compile time Ø char *string_array[NUM]; Ø string_array[0] = malloc(length of string 0…); Ø string_array[1] = malloc(length of string 1…); Ø etc. 3. Declare an array of strings, where we don’t know how many strings there will be, and how long each will be, at compile time Ø char **string_array; Ø string_array = malloc(how many strings … * sizeof(char *)); Ø string_array[0] = malloc(length of string 0…); Ø string_array[1] = malloc(length of string 1…); Ø etc.

Declaring strings statically 1. Declare an array of NUM strings, each at most LEN

Declaring strings statically 1. Declare an array of NUM strings, each at most LEN long (incl. the terminating NULL), where NUM and LEN are known at compile time Ø char string_array[NUM][LEN]; Example: char string_array[3][10]; for(int i=0; i<3; i++) fgets(string_array[i], 10, stdin) H e H A l o n # $ ( i n # $ ( ! ^ * l a ! ! ! n o l h

Declaring strings dynamically 2. Declare array of NUM strings, where only NUM is known

Declaring strings dynamically 2. Declare array of NUM strings, where only NUM is known at compile time Ø char *string_array[NUM]; Ø string_array[0] = malloc(length of string 0…); Ø string_array[1] = malloc(length of string 1…); Ø etc. Example: char *string_array[3]; char temp[MAXLEN]; for(int i=0; i<3; i++) { fgets(temp, MAXLEN, stdin); string_array[i] = malloc(strlen(temp)+1); strcpy(string_array[i], temp); } H H e A i n l l l o o n h a ! ! ! n

Declaring strings dynamically ã For sorting: Swap strings by swapping pointers, not by copying

Declaring strings dynamically ã For sorting: Swap strings by swapping pointers, not by copying contents! l char *t; // pointer to char l t = string_array[i]; // swap pointers! l string_array[i] = string_array[j]; // no copying chars l string_array[j] = t; t H H e A i n l l l o o n h a ! ! ! n

One more thing… Passing pointers as arguments to functions

One more thing… Passing pointers as arguments to functions

Passing arguments by reference ã Example 1: l reading values into variables int x,

Passing arguments by reference ã Example 1: l reading values into variables int x, y, z; scanf(“%d%d%d”, &x, &y, &z); l scanf() changes the values of x, y and z! How? Ø we provide it the addresses where x, y and z are located ã Example 2: l a function to double the value given to it void double_it(int x) { x = x*2; } l doesn’t work… because x is “passed by value” Ø a copy of x is modified inside the function, not the original

Passing arguments by reference ã Example 2 take 2: l a function to double

Passing arguments by reference ã Example 2 take 2: l a function to double the value given to it void double_it(int *x) { *x = (*x) * 2; } int main() { int y = 10; double_it(&y); // y is now 20 } l works! Because y is “passed by reference” Ø the address in memory where y is stored is sent to the function, which modifies it correctly at that location

Passing arguments: C vs. Java ã Which of these will work in Java? WHY?

Passing arguments: C vs. Java ã Which of these will work in Java? WHY? 1. Modify an integer double_it(int x) { x = x*2; } 2. Modify an object double_it(Point p) { p. x = p. x*2; } 3. Swap two objects swap(Point p 1, Point p 2) { Point temp = p 1; p 1 = p 2; p 2 = temp; }

Passing arguments: C vs. Java ã Java: l passes arguments by value for all

Passing arguments: C vs. Java ã Java: l passes arguments by value for all the primitive data types Ø int, double, float, etc. double_it(int x) { x = x*2; } // won’t work l passes objects by reference Ø so member data of an object can be modified double_it(Point p) { p. x = p. x*2; } // works! l BUT: references are passed by value to methods… Ø so cannot swap two objects swap(Point p 1, Point p 2) { Point temp = p 1; p 1 = p 2; p 2 = temp; } // won’t work! ã Understanding C pointers will demystify everything!