Presentation is loading. Please wait.

Presentation is loading. Please wait.

Department of Computer Engineering Faculty of Engineering, Prince of Songkla University 1 3 – Pointers.

Similar presentations


Presentation on theme: "Department of Computer Engineering Faculty of Engineering, Prince of Songkla University 1 3 – Pointers."— Presentation transcript:

1 Department of Computer Engineering Faculty of Engineering, Prince of Songkla University 1 3 – Pointers

2 2 Why Pointer Variables ? most difficult part of C the most useful can use them to code call by reference can use them to build lists, queues, stacks, trees, etc.

3 3 Boxes Again The box occurs at memory address 1232 int x; x x 1232

4 4 What is a Pointer Variable ? A pointer variable can contain the memory address of another variable. x 1232 int *y; y int x;

5 5 Declaring a Pointer Variable int *countptr; Read this declaration ‘backwards’: countptr can contain the address of an integer variable or (more usually): countptr can point to an integer variable

6 6 Assignment to Pointers The operator for returning the address of a variable is & int x = 5; int *countptr; countptr = &x;

7 7 Assigment in Pictures int x = 5; x 5 1232 int *countptr; countptr ? countptr = &x; countptr 1232 x 5 countptr Usually, drawn as:

8 8 Some Tricky Things int a; int *aptr; aptr = &a; is equivalent to: But, int a, *aptr; aptr = &a; int a, *aptr = &a; int *aptr = &a, a;/* WRONG */

9 9 Initialising a Pointer i nt *xptr; float *yptr; xptr = NULL; yptr = NULL;

10 10 Accessing a Pointer int c = 13; int *countptr; countptr = &c; printf("The value of countptr is %lu\n", countptr); 26634232 Result :

11 11 printf("The value of the integer pointed to by countptr is %d\n",*countptr); This is called dereferencing a pointer Result: 13

12 12 Two Uses of * int *countptr; means countptr can point to an integer variable All other occurrences of * mean dereference: printf("...", *countptr);

13 13 More Examples agptr a a int a = 3; *gptr; gptr = &a; *gptr = 7; 3? 3 7

14 14 agptr a *gptr = *gptr + 2; (*gptr)++; 9 10

15 15 The & and * Operators #include int main() { int a = 7; int *aptr; aptr = &a; /* continued on next slide */

16 16 printf("Address of a is %lu\n", &a); printf("Value of aptr is %lu\n\n", aptr); printf("Value of a is %d\n", a); printf("Value of *aptr is %d\n\n", *aptr); printf("%s\n", "Proving that * and & are complements of each other."); printf("&*aptr = %lu\n", &*aptr); printf("*&aptr = %lu\n", *&aptr); return 0; }

17 17 Address of a is 2042756 Value of aptr is 2042756 Value of a is 7 Value of *aptr is 7 Proving that * and & are complements of each other. &*aptr = 2042756 *&aptr = 2042756

18 18 Declarations and Initialisations int i = 3, j = 5, *p = &i, *q = &j, *r; double x; ExpressionEquivalent Expression Value p == &ip == (&i)1 (true) p = i + 7p = (i + 7)illegal **&p*p3 r = &xr = (&x)illegal int double

19 19 Coding Call by Reference Call by Value Reminder Call by Reference Version Swapping

20 20 Call by Value Reminder /* increment using call by value */ #include int add1(int); int main() { int count = 7; printf("The original value of count is %d\n", count); count = add1(count); printf("The new value of count is %d\n", count); return 0; }

21 21 int add1(int c) { return c++; /* increments local var c */ } The original value of count is 7 The new value of count is 8

22 22 Call By Reference /* Incrementing a variable using call by reference coded with pointers */ #include void addp1(int *); int main() { int count = 7; printf("The original value of count is %d\n", count); addp1(&count); printf("The new value of count is %d\n", count); return 0; }

23 23 void addp1(int *countptr) { (*countptr)++; /* increments count in main() */ } The original value of count is 7 The new value of count is 8

24 24 addp1() in pictures int main() {... addp1(&count);... } count7 void addp1(int *countptr) { (*countptr)++; } countptr

25 25 #include void swap(int *, int *); int main() { int a = 3, b = 7; printf("%d %d\n", a, b); /* 3 7 printed*/ swap(&a,&b); printf("%d %d\n", a, b); /* 7 3 printed*/ return 0; } Swapping

26 26 void swap(int *p, int *q) { int tmp; tmp = *p; *p = *q; *q = tmp; }

27 27 Swap() int main() { int a =3, b = 7;... swap(&a, &b);... } b 7 void swap(int *p, int *q) { int tmp; tmp = *p; *p = *q; *q = tmp; } a 3 qp tmp

28 28 Pointers, Arrays & Functions

29 29 #include #define SIZE 10 void array_swap(int [], int, int); int main() { int a[SIZE]={2,6,4,8,10,12,89,68,45,37}; int cntr, pass; printf("Data items in original order\n"); for (cntr = 0; cntr < SIZE; cntr++) printf("%4d", a[cntr]); : continued Bubble Sort without Pointers

30 30 for (pass = 0; pass a[cntr+1]) array_swap(a, cntr, cntr+1); printf("\nItems in ascending order\n"); for (cntr = 0; cntr < SIZE; cntr++) printf("%4d", a[cntr]); printf("\n"); return 0; } continued

31 31 void array_swap(int a[], int x, int y) /* swap a[x] and a[y] */ { int temp; temp = a[x]; a[x] = a[y]; a[y] = temp; }

32 32 Bubble Sort with Pointers #include #define SIZE 10 void swap(int *, int *); int main() { int a[SIZE]={2,6,4,8,10,12,89,68,45,37}; int cntr, pass; printf("Data items in original order\n"); for (cntr = 0; cntr < SIZE; cntr++) printf("%4d", a[cntr]); : continued

33 33 for (pass = 0; pass a[cntr+1]) swap(&a[cntr], &a[cntr+1]); printf("\nItems in ascending order\n"); for (cntr = 0; cntr < SIZE; cntr++) printf("%4d", a[cntr]); printf("\n"); return 0; }

34 34 void swap(int *x, int *y) /* swap x and y */ { int temp; temp = *x; *x = *y; *y = temp; }

35 35 Pointers to Arrays An Array is a Sequence of Boxes A Pointer Can Point at an Array Element Moving the Pointer Along the Array Moving the Pointer Backwards The Difference Between Two Pointers Allowable Pointer Arithmetic Pointers and Relational Operators Four Ways of Referring to Array Elements Arrays and Pointers are Different

36 36 An Array is a Sequence of Boxes int a[3]; a[0]a[1]a[2] Memory addresses shown: a[0]a[1]a[2] 234523492353

37 37 A Pointer Can Point at an Array Element int a[3], *aptr; : aptr = a; aptr a[0]a[1]a[2] 234523492353 572

38 38 Another way of achieving aptr = &a[0]; printf("%d", *aptr); /* 5 printed */ a[0]a[1]a[2] 234523492353 572 aptr

39 39 Moving the Pointer along the Array aptr = aptr + 2; Results in: printf("%d", *aptr); /* 2 printed */ a[0]a[1]a[2] 234523492353 aptr 572

40 40 Moving the Pointer Backwards aptr = aptr - 1; Results in: printf("%d", *aptr); /* 7 printed */ a[0]a[1]a[2] 234523492353 aptr 572

41 41 The Difference Between Two Pointers void main() { double db[3], *p, *q; p = &db[0]; q = p + 1; printf("%d\n", q - p); /* 1 printed */ printf("%d\n", (int)q - (int)p); /* probably 8 is printed */ }

42 42 In picture form: db[0]db[1]db[2] 100910171025p q

43 43 Allowable Pointer Arithmetic int g[6], *p; *q p = g; /* same as &g[0] */ q = g; All the following are possible: ++p p-- p += 5 p = p - 2 p - g Only use Pointer Arithmetic with Arrays

44 44 Pointers and Relational Operations int n[3], *nptr1, *nptr2; nptr1 = &n[0]; nptr2 = n + 2; if (nptr2 > nptr1) /* 5143 > 5135? */... ; n[0]n[1]n[2] 513551395143 nptr1 nptr2

45 45 Four Ways of Referring to Array Elements! int b[5], *bptr; bptr = b; /* could also write bptr = &b[0] */ printf("4th element of b is %d\n", b[3] ); /* ordinary array subscripting */

46 46 printf("4th element of b is %d\n",*(bptr+3)); /* pointer/offset with a pointer */ printf("4th element of b is %d\n",*(b+3)); /* pointer/offset with the array name */ printf("4th element of b is %d\n",bptr[3]); /* pointer subscript notation */

47 47 Arrays and Pointers are Different int a[3], *p; /* The following statements are illegal because they attempt to change a */ a = p; ++a; a += 2; An array is sometimes called a “constant pointer”

48 48 Using Array Pointers in Functions Array and Pointer Correspondence Three Ways to Sum an Array

49 49 Array and Pointer Correspondence void function_name(int [], int,...); : void function_name(int arr[], int x,...) { /* implementation */ }

50 50 int arr[] is equivalent to int *arr void function_name(int *, int,...); : void function_name(int *arr, int x,...) { /* same implementation */ }

51 51 Three Ways to Sum an Array The first version is the clearest (best) way: int sum(int a[], int n) { int sum = 0, i; for(i = 0; i < n; ++i) sum += a[i]; return sum; } continued

52 52 int sum(int a[], int n) { int sum = 0, *p; for(p = a; p < &a[n]; ++p) sum += *p; return sum; } continued

53 53 int sum(int *a, int n) { int sum = 0, i, *p = a; for(i = 0; i < n; ++i) sum += p[i]; return sum; } There are many more variations.

54 54 Pointers to Functions Bubble Sort Again Improving Bubble Sort The Comparison Functions Calling the Improved Bubble Sort The New bubble()

55 55 Bubble Sort Again #include #define SIZE 10 void bubble(int []); void swap(int *, int *); int compare(int, int); : /* main, etc */ continued

56 56 void bubble(int work[]) { int pass, cnt; for (pass = 0; pass < SIZE - 1; pass++) for (cnt = 0; cnt < SIZE - 1; cnt++) if ( compare(work[cnt],work[cnt + 1])) swap(&work[cnt], &work[cnt+1]); } int compare(int a, int b) { return a > b; }

57 57 Improving Bubble Sort It would be more useful if it could sort in different ways – in ascending and descending order for instance. Pass the chosen comparison function ( ascending (), descending ()) to bubble () as an argument. Actually pass bubble() a pointer to the chosen function.

58 58 The Comparison Functions int ascending(int a, int b) { return a > b; } int descending(int a, int b) { return a < b; }

59 59 Calling the Improved Bubble Sort #include #define SIZE 10 void bubble(int [], int (*)(int, int)); void swap(int *, int *); int ascending(int, int); int descending(int, int); : continued

60 60 int main() { int a[SIZE] = {2,6,4,8,10,12,89,68,45,37}; int cnter, order; scanf("%d", &order); printf("Items in original order\n"); for (cnter = 0; cnter < SIZE; cnter++) printf("%4d", a[cnter]); : continued

61 61 if (order == 1) { bubble(a, ascending); printf("Items in ascending order\n"); } else { bubble(a, descending); printf("Items in descending order\n"); } for (cnter = 0; cnter < SIZE; cnter++) printf("%4d", a[cnter]); return 0; } continued

62 62 The New bubble() void bubble(int work[], int (*compare)(int, int)) { int pass, cnt; for (pass = 0; pass < SIZE-1; pass++) for (cnt = 0; cnt < SIZE-1; cnt++) if ((*compare)(work[cnt],work[cnt + 1])) swap(&work[cnt], &work[cnt + 1]); }

63 63 The Usual Error int (*compare)(int, int) /* RIGHT */ This is a pointer called compare, that points to a function that has two integer arguments and returns an integer. int *compare(int, int) /* WRONG */ This is a function called compare, that takes two integer arguments and returns a pointer to an integer.

64 64 Pointers and Structures

65 65 A struct can Contain Strings struct card{ char *face; char *suit; }; : struct card a = {"Three", "Hearts"}; : printf("%s", a.suit); /* prints Hearts */

66 66 Shuffling Cards #include #include #include struct card { char *face; char *suit; }; typedef struct card Card; void filldeck(Card [], char *[], char *[]); void shuffle(Card []); void deal(Card []); continued

67 67 int main() { Card deck[52]; char *face[] = {"Ace", "Deuce", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine","Ten","Jack", "Queen", "King"}; char *suit[] = {"Hearts", "Diamonds", "Clubs", "Spades"}; srand(clock());/* set random num */ filldeck(deck, face, suit); shuffle(deck); deal(deck); return 0; } continued

68 68 void filldeck(Card wdeck[], char *wface[], char *wsuit[]) /* initialise the deck of cards */ { int i; for (i = 0; i <= 51; i++) { wdeck[i].face = wface[i % 13]; wdeck[i].suit = wsuit[i / 13]; } } continued

69 69 void shuffle(Card wdeck[]) /* randomly rearrange the deck of cards */ { int i, j; Card temp; for (i = 0; i <= 51; i++) { j = rand() % 52; /* get rand num */ if (i != j) { temp = wdeck[i]; wdeck[i] = wdeck[j]; wdeck[j] = temp; } } } continued

70 70 void deal(Card wdeck[]) /* display the deck */ { int i; for (i = 0; i <= 51; i++) printf("%5s of %-8s%c", wdeck[i].face, wdeck[i].suit, (i + 1) % 2 ? '\t' : '\n'); }

71 71 Output : Eight of DiamondsAce of Hearts Eight of ClubsFive of Spades : :

72 72 Pointers to Structs struct card a, *c; a = {"Four", "Spades"}; c = &a; : printf("%s", c->suit); /* prints Spades */ c->suit is equivalent to (*c).suit

73 73 #include struct card { char *face; char *suit; }; Example continued

74 74 int main() { struct card a; struct card *aptr; a.face = "Ace"; a.suit = "Spades"; aptr = &a; printf("%s of %s\n%s of %s\n%s of%s\n", a.face, a.suit, aptr->face, aptr->suit, (*aptr).face, (*aptr).suit); return 0; }

75 75 Output: Ace of Spades Ace of Spades Ace of Spades

76 76 Updating a struct Code fragment: struct card { char *face; char *suit; }; int main() { struct card a; a.face = “Three; printf(“%s”, a.face); }

77 77 Discussion This code works, so what is the problem? Answer: the scope of “Three” at the end of main(), “Three” goes out of scope and is deleted this does not matter for this example because the scope of main() is the entire program

78 78 A More Dangerous Example int main() { struct card a; a = initialise(); printf(“%s”, a.face); : printf(“%s”, a.face); } struct card initialise(void) { struct card b; b.face = “Three”; return b; }

79 79 Discussion The scope of “Three” is initialise(), and so will be deleted after initialise() returns return copies out the b struct, including its two pointers a is assigned the pointers, but what do they point at? the deletion may not happen immediately, but depend on the memory usage of the rest of the program the first printf() may work, sometimes!

80 80 First Solution struct card1( char face[10]; char suit[10]; }; int main() { struct card1 a; a = initialise1(); : printf(“%s”, a.face); } struct card1 initialise1(void) { struct card1 b; strcpy(b.face, “Three”); return b; }

81 81 Discussion The general solution is to make a copy of the string “Three” is copied into the fixed size array b.face using strcpy() that array is copied out as part of the b struct using return

82 82 Second Solution struct card( char *face; /* no fixed size */ char *suit; }; int main() { struct card a; a = initialise2(); : printf(“%s”, a.face); } struct card initialise2(void) { struct card b; b.face = (char *)malloc(6); strcpy(b.face, “Three”); return b; }

83 83 Discussion The second solution still uses copying, but now calls malloc() to make dynamic memory return only copies out the pointers inside b but malloc’ed memory is not deleted even though the scope of b is initialise2() so a.face will point to the malloc’ed memory from initialise2()

84 84 Third Solution struct card( char *face; /* no fixed size */ char *suit; }; int main() { struct card a; initialise3(&a); : printf(“%s”, a.face); } void initialise3(struct card *ap) { ap->face = (char *)malloc(6); strcpy(ap->face, “Three”); }

85 85 Discussion The third solution uses malloc() to make dynamic memory, but for the a struct. pass in a pointer to a, and alter a via the pointer (this is how C implements call-by- reference). this is the most common coding style for manipulating structs inside functions

86 86 Arrays of Pointers

87 87 An Array of Pointers int *b[10]; int x[3], y[35]; : : b[0] = x;b[1] = y;

88 88 A 2D Array of Characters char names[][5] = { "Bob", "Jo", "Ann", "Fred"}; printf("%s", names[0]); ‘B’‘o’‘b’‘\0’ ‘J’‘o’‘\0’ ‘A’ ‘n’ ‘\0’ ‘F’ ‘r’ ‘e’‘d’‘\0’ names

89 89 An Array of char * char *names[] = {"Augustin", "Ann", "Bob", "Freddy"} printf("%s", names[0]); A ugustin\0 Ann Bob Freddy names[0] names[1] names[2] names[3] names

90 90 Sorting Words test.dat : A is for apple or alphabet pie which all get a slice of, come taste it and try. Sort the words: $ sort_words < test.dat Output: A a all alphabet... which

91 91 sort_words.c #include #include #include #define MAXWORD 50 /* max word length */ #define SIZE 1000 /* array size */ void sort_words(char [][MAXWORD], int); void string_swap(char **, char **); : continued

92 92 int main() { char w[SIZE][MAXWORD]; /* array of fixed length strings */ int num, i; for (i=0; scanf("%s", w[i]) == 1; i++){ if (i >= SIZE) { printf("Too many Words!"); exit(1); } } continued

93 93 : num = i; sort_words(w, num); for (i=0; i < num; i++) printf("%s\n", w[i]); return 0; }

94 94 Dynamic Memory Allocation sort_words.c can save space by defining the size of each w[i] dynamically at run time. New data structure: char *w[SIZE]; Make a pointer to a block of memory using: calloc(, )

95 95 New Top Level #include #include #include #define MAXWORD 50 /* max word length */ #define SIZE 1000 /* array size */ void sort_words(char *[], int); void string_swap(char **, char **); : continued

96 96 int main() { char *w[SIZE]; /* array of pointers */ char word[MAXWORD]; /* work space */ int num, i; for (i=0; scanf("%s", word) == 1; i++){ if (i >= SIZE) { printf("Too many Words!"); exit(1); } w[i] = calloc(strlen(word)+1, sizeof(char)); strcpy(w[i], word); } : continued

97 97 : num = i; sort_words(w, num); for (i=0; i < num; i++) printf("%s\n", w[i]); return 0; }

98 98 Some Comments calloc(strlen(word)+1, sizeof(char)) cannot just use strcpy(w[i], word)

99 99 void sort_words(char *w[], int n) /* n elements are to be sorted */ /* similar to bubble sort */ { int i, j; for(i = 0; i 0) string_swap(&w[i], &w[j]); }

100 100 In picture form: Augustin\0 Ann Bob Freddy w[0] w[1] w[2] w[3] w

101 101 void string_swap(char **p, char **q) /* swap the strings using pointers */ { char *temp; temp = *p; *p = *q; *q = temp; }

102 102 In picture form: Augustin\0 Ann w[0] w[1] Augustin\0 Ann w[0] w[1] Before After

103 103 A Dynamic Array #include #include int main() { int *a; /* will point to the array */ int i, size, sum = 0; printf("An array will be created dynamically. Input an array size followed by values: "); : continued

104 104 scanf("%d", &size); /* allocate space in a for size int's */ a = (int *)malloc(size * sizeof(int)); for (i=0; i < size; i++) scanf("%d", &a[i]); for(i=0; i < size; i++) sum += a[i]; printf("Sum is %d\n", sum); free(a); return 0; }

105 105 Static versus Dynamic Memory The choice between static or dynamic memory is usually based on if you know how much data will be stored in your program. If you know that an array of 100 integers is required then declare: int data[100]; If you do not know, then consider creating dynamic memory.

106 106 Dynamic Memory Allocation #1 Allocated storage is memory whose lifetime is under the control of the programmer. Compare with static storage (used with globally defined variables). Compare with automatic storage (used with variables defined within a function). When allocated memory is no longer needed, it is released by calling a library routine. malloc() is used to request a block of allocated storage, also called “(dynamically) allocated memory”. Benefit: Program can request a specific amount of memory and retain that memory exactly as long as needed. 106

107 107 Dynamic Memory Allocation #2 The prototype for malloc() is found (directly or indirectly) in stdlib.h (which is located where?) void *malloc( size_t size ); size_t is used instead of int to allow for larger sizes than an int might contain. For our purposes, int is fine (and will be used in the rest of these slides). What is void * ? A pointer type that can be assigned to any pointer type. 107

108 108 Memory Allocation Basics Here is code that requests a block of allocated memory that is large enough for 100 int values: int *int_ptr; int_ptr = malloc( 100 * sizeof(int) ); /* no cast required! */ if ( int_ptr == NULL ) { fprintf(stderr, "main: malloc failed\n"); exit(1); } The block of allocated memory can be treated like an array by subscripting int_ptr: int i; for ( i = 0; i < 100; i++) int_ptr[i] = i * 2; 108

109 109 What is wrong? int i, *int_ptr; int_ptr = malloc( sizeof (int_ptr) ); for ( i = 0; i < sizeof(int_ptr); i++ ) int_ptr[i] = i * 3; 109

110 110 Example Functions often return a pointer to storage that has been allocated within the function: char * replicate(int num, char ch) { char *buf_ptr, *ptr; buf_ptr = malloc( (num + 1) * sizeof(char) ); ptr = buf_ptr; while( num-- ) *ptr++ = ch; *ptr = '\0'; return buf_ptr; } /* replicate */ Usage: char *as = replicate(5, 'A'); char *dots = replicate(3, '.'); printf("%s%s%s\n", as, dots, as); Prints: AAAAA...AAAAA 110

111 111 Free Memory allocated memory must be explicitly released via the free() function. This will run forever in C: int i, *ptr; for (;;) { ptr = malloc(100 * sizeof(int) ); if ( ptr == NULL ) { fprintf(stderr, "..."); exit(1); } for (i = 0; i < 100; i++) ptr[i] = i * 3; free(ptr); } 111 If the call to free() is removed, the C program will exhaust memory. The if statement asking if ptr is NULL will become true!

112 112 main() Arguments /* my_echo.c: Echo command line input */ #include int main(int argc, char *argv[]) { int i; printf("argc = %d\n", argc); for (i = 0; i <= argc-1; ++i) printf("argv[%d] = %s\n",i, argv[i]); return 0; }

113 113 Compilation and Execution: $ gcc -Wall -o my_echo my_echo.c $ my_echo a is for apple argc = 5 argv[0] = my_echo argv[1] = a argv[2] = is argv[3] = for argv[4] = apple

114 114 Pictorially $ my_echo hello, world produces: my_echo\0 world argv[0] argv[1] argv[2] argv[3] hello,\0 NULL argv


Download ppt "Department of Computer Engineering Faculty of Engineering, Prince of Songkla University 1 3 – Pointers."

Similar presentations


Ads by Google