Download presentation
Presentation is loading. Please wait.
Published byDominic Craig Modified over 9 years ago
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
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.