1 / 32

Topic 8. Pointers and Arrays. Dynamic Memory Allocation

COMP ENG 2SH4 Principles of Programming McMaster University, 2017 Instructor: Sorina Dumitrescu. Topic 8. Pointers and Arrays. Dynamic Memory Allocation. Textbook Reading. Chapter 7, Sections 7-9. Pointer (Address) Arithmetic.

agnest
Download Presentation

Topic 8. Pointers and Arrays. Dynamic Memory Allocation

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. COMP ENG 2SH4 Principles of Programming McMaster University, 2017 Instructor: Sorina Dumitrescu Topic 8. Pointers and Arrays. Dynamic Memory Allocation

  2. Textbook Reading • Chapter 7, Sections 7-9

  3. Pointer (Address) Arithmetic • If pointer p points to an element of an array , and i>0 is of type int, then • p + i is a pointer which points to the element of the array situated i positions to the right, provided that it is within the array boundaries. • p - iis a pointer which points to the element of the array situated i positions to the left, provided that it is within the array boundaries. • Thus, p+i and p-i are pointers of the same type as p. • If p and q are pointers to elements of an array and q<p, then p – q isthe number of array elements between the pointed to elements, +1 (i.e. the difference between the array positions pointed to).

  4. Example 1 double a[10]={0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0}; double *aPtr; aPtr = &a[4]; /* aPtr points to a[4] */ • aPtr + 3 • is a pointer of type double*. • Its value is &a[4+3], • it points to a[7]. Consider the statement: *(aPtr + 3) = 10.0; /* a[7] gets the value 10.0 */

  5. Example 1 double a[10]={0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0}; double*aPtr; aPtr = &a[4]; /* aPtr points to a[4] */ • aPtr - 2 • is a pointer of type double*. • Its value is &a[4-2], • thus it points to a[2]. Consider the statements: *(aPtr -2) = 10.0; /* a[2] gets the value 10.0 */ *++aPtr = 10.0;/* same as *(++aPtr) = 10.0; */ /* aPtr is incremented by 1, thus it points to a[5]; a[5] gets the value 10.0 */

  6. Example 2 • When we subtract two pointers, the result is an integer • If aPtr and bPtr point to elements of the same array, then aPtr-bPtrequals the difference between the subscripts of the pointed to elements. int i; int a[10]={10,11,12,13,14,15,16,17,18,19}; int*aPtr, *bPtr; aPtr = &a[8]; bPtr= &a[3]; i = aPtr – bPtr; // i is 8-3

  7. Example 2 • When we subtract two pointers, the result is an integer • If aPtr and bPtr point to elements of the same array, then aPtr-bPtrequals the difference between the subscripts of the pointed to array elements. • In other words, aPtr-bPtr equals (value of aPtr – value of bPtr )/sizeof(T), where T is the data type of array elements. • sizeof(T) returns the number of bytes used to store a variable of type T. int i; int a[10]={10,11,12,13,14,15,16,17,18,19}; int*aPtr, *bPtr; aPtr = &a[8]; bPtr= &a[3]; i = aPtr – bPtr; /* (&a[8]– &a[3])/sizeof( int) == 8-3*/

  8. a[0] 0x22aa00 00 0x22aa01 00 0x22aa02 00 0x22aa03 0A a[1] 0x22aa04 00 0x22aa05 00 0x22aa06 00 0x22aa07 14 a[2] 0x22aa08 00 0x22aa09 00 0x22aa0A 00 0x22aa0B 1E 0x22aa0C 00 0x22aa0D 00 0x22aa0E 00 0x22aa0F 28 0x22aa10 00 0x22aa11 00 0x22aa12 00 0x22aa13 32 Example 3 int main( void ) { int a[5] = {10, 20, 30, 40, 50}; int *p=a; printf("%d\n", *p); p++; printf("%p\n", p); p = p+2; printf("%p\n", p); } p 10 0x22aa04 0x22aa0C p++ p+2

  9. Name of An Array • The name of an array is an address. • Therefore, it is of pointer type. • But, it is not a pointer variable. • It is aconstant pointer. • It cannot be modified. int a[6]; int *p=&a[1]; /* p is declared with type int* and assigned the address of a[1] */ a = p; /*syntax error – attempts to modify a constant pointer */

  10. Name of An Array • The name of an array is the address of the first element. • It is aconstant pointerto the first array element. intaa[6]; • aais a pointer to aa[0] • aa+iis a pointer to aa[i] • *(aa+i) is another way of referring to aa[i]

  11. Referring to Elements of An Array int a[10]; int *p; p = a; /* p is assigned &a[0]; p points to a[0] */ After p is assigned the value of a, we may regard p as another name for the array a. Then we have four possibilities to refer to element a[i] : • a[i] (array-subscript notation) • p[i] (pointer-subscript notation) • *(p+i) (pointer-offset notation) • *(a+i) (pointer-offset notation using array name)

  12. a 2 4 6 8 9 p ... p+1 p a p+4 Referring to Elements of an Array. Example int a[ ] = {2,4,6,8,9}; int *p = a; *(p+5)=6; /* may lead to destruction of data or to program crash */ /* p == &a[0]; p and a can be used interchangeably to refer to arrays’ elements.*/ Instead of a[4] we can use p[4], or *(p+4), or *(a+4).

  13. Looping through an Array int a[20]; int i; int*p; /* inputting data into the array*/ for(i=0;i<20;i++) scanf("%d",&a[i]); printf("\n"); /* printing each element of the array */ for(p=a;p<a+20;p++) printf("%d\t",*p); • The first loop uses the index i as the loop variable. • The second loop uses a pointer p as the loop variable. • Initially p points to the first array element. • At each iteration p is incremented. • After being incremented p points to the next array element.

  14. Parameters of Array Type • When an array name is passed to a function, what is actually passed? • The address of its first element. • What is the parameter receiving this address? • It is a pointer. In the parameter list of a function definition or declaration data_type a[ ] and data_type *a are equivalent.

  15. Parameters of Array Type. Example #include <stdio.h> #define N 3 void f1(int pa[], int n ); int main(void){ int i; int a[N]={0,1,2}; f1(a, N); for (i=0; i<N; i++) printf(“a[%d]=%d\t”,i,a[i]); } void f1( int pa[], int n ){ int i; for (i=0; i< n; i++) pa[i] *= 2; } #include <stdio.h> #define N 3 void f2(int *pa, int n ); int main(void){ int i; int a[N]={0,1,2}; f2(a, N); for (i=0; i<N; i++) printf(“a[%d]=%d\t”,i,a[i]); } void f2( int *pa, int n ){ int i; for (i=0; i< n; i++) pa[i] *= 2; }

  16. Pointer and Array Declarations int a[3] = {1,3,5}; /* when an array is defined, memory is allocated for all elements of the array */ int*q = {1,3,5}; //syntax error /* when a pointer variable is defined a single memory location is reserved for the pointer */ • Pointer declaration and array declaration in the function list of parameters are equivalent. • Array declaration and pointer declaration outside the parameter list of a function are not equivalent.

  17. Pointers and Strings char str[20]; scanf(“%s”, str); char str[20]; str=“Hello world!”; /* we can modify the elements of this array later */ char *p; scanf(“%s”, p);/* there is no space reserved in memory to store the characters; may lead to program failure or destruction of data; */ char *s; s = “John”; /* an array is created in the read-only memory to store the string. s is assigned the address of this array */

  18. ‘J’ ‘o’ ‘h’ ‘n’ ‘\0’ *s == s[0] == ‘J’ *(s+3) == s[3] == ‘n’ s Pointers and Strings char*s; s = “John”; /* an array to hold the string is created in the read-only memory; s is assigned the address of this array */ *s = ‘c’; /*  program failure */

  19. ‘J’ ‘o’ ‘h’ ‘n’ ‘\0’ Pointers and Strings #include <stdio.h> int main(void) { char*s0=“John“; int i=0; i = my_strlen(s0); printf(“%d\n”,i); } /* returns the length of the string – the number of characters not including ‘\0’*/ int my_strlen(char *s){ int k; for(k=0; *s!=‘\0’; s++) k++; return k; } s0 s

  20. Pointers and Strings #include <stdio.h> int main(void) { char array[]=“Welcome!“; char *ptr=“Bienvenue!“; int i=0; i += my_strlen(“Hello World!”); i += my_strlen(array); i += my_strlen(ptr); printf(“%d\n”,i); return 0; } int my_strlen(char *s){ int k; for(k=0; *s!=‘\0’; s++) k++; return k; } 30

  21. sizeof Operator • "sizeof" can be applied to a variable name, a data type or an expression • Returns the number of bytes used in memory . • The result returned is of typesize_t(an integral type) . • sizeof( char ) • sizeof( 3.0 + 5.0 ) • sizeof( int [4] ) • sizeof( int * ) float f[10]; char s[] = "Canada"; char *p = “Bye!”; sizeof( p ); /* # bytes to store a pointer variable */ sizeof( f ); /* # bytes to store all array elements */ sizeof( s ); /* # bytes to store all array elements – including ‘\0’*/

  22. Lifetime of C Objects • We have learnt how to create C objects ( e. g. variables, arrays) with • Automatic storage duration • Created when the block is entered • Destroyed when the block is exited • Static storage duration • Exist during the whole program execution • These two options allow for little control on the lifetime of objects.

  23. Memory Management Routines • If we need to be able to control when objects are created and destroyed • Use dynamic memory allocation via C library memory management functions. • Functions malloc(), calloc(), realloc()allocate a contiguous portion of memory (a sequence of consecutive bytes) and return a pointer to it(a pointer to the first byte). • This portion of memory remains allocated until we deallocate it by calling function free(). • #include <stdlib.h>

  24. Pointer to void • Pointer to void (void *) – a generic pointer – can represent any pointer type. • void*p; // declaration • A pointer to void contains a memory address, but the data type is unspecified (we don’t know to how many bytes it points to). • It cannot be dereferenced (using *p is not allowed) • Pointer arithmetic is not defined on void*.

  25. C Library Memory Allocation Routines • void*malloc( size_t n ); • Allocates n consecutive bytes of memory • Returns a pointer to it (i.e., to the first byte) • Or returns a NULL pointer if the request cannot be satisfied. • The storage is not initialized. • void*calloc( size_t m, size_t n ); • Allocates memory space for an array of m objects each of size n bytes and returns a pointer to it. • Or returns a NULL pointer if the request cannot be satisfied. • The storage is initialized to 0.

  26. Deallocating Memory • void free( void *p ); • Deallocates the portion of memory pointed to by p. • p must be a pointer to a block of memory previously allocated by malloc(), calloc() or realloc(). • It does nothing if p is NULL. • Allways free the memory that was dynamically allocated, when you do not need it anymore!!!

  27. Optional: realloc() • void *realloc( void *p, size_t new_size ); • Changes the size of the block of memory pointed to by p to new_size (the new block could be somewhere else in memory) • The contents will be unchanged up to the smallest between the old and new sizes. • If the new size is larger the additional space is not initialized. • Returns a pointer to the new block or NULL if the request cannot be satisfied.

  28. Variable Length Array #include<stdio.h> #include<stdlib.h> /* creates an array of size specified at run time*/ int main(void) { int n,i; float *p=NULL; printf(“Input the size of the array: n=“); scanf(“%d”,&n); if (n<0) { printf(“\nInvalid entry“); return 0; } printf(“\n”); p = malloc ( n * sizeof( float )); for( i = 0; i < n; i++ ) { printf(“Input array element %d:“, i); scanf(“%f”, p+i); } for( i = 0; i < n; i++ ) printf(“p[%d]=%6.2f\n”, i, *(p+i) ); free(p); return 0; }

  29. Example • We want to write a function to add two n dimensional vectors. • Each vector is stored in a an n-size array. • The array names corresponding to the vectors to be added are passed to the function as arguments. • Where to store the sum vector? • Options: • Create an array to store the sum of vectors in the caller and pass its name to the function. • Create an array to store the sum of vectors in the function and return a pointer to it to the caller.

  30. Adding Two Vectors #include <stdio.h> int* add( int v1[], int v2[], int n); int main(void) { int vec1[] = {1,2,3,4}; int vec2[] = {4,3,2,1}; int *p = NULL; p = add (vec1,vec2,4); … // some more code printf(“%d, %d, %d, %d\n”,p[0],p[1],p[2],p[3]); return 0;} Incorrect function add() int* add( int v1[], int v2[], int n){ int sum[n]; … // add vectors and store result in array sum return &sum[0]; }

  31. Adding Two Vectors #include <stdio.h> int* add( int v1[], int v2[], int n); int main(void) { int vec1[] = {1,2,3,4}; int vec2[] = {4,3,2,1}; int *p = NULL; p = add (vec1,vec2,4); … // some more code printf(“%d, %d, %d, %d\n”,p[0],p[1],p[2],p[3]); return 0;} Incorrect function add() int* add( int v1[], int v2[], int n){ int sum[N]; //provided N is sufficiently large … // add vectors and store result in array sum return &sum[0]; }

  32. Adding Two Vectors #include <stdio.h> int* add( int v1[], int v2[], int n); int main(void) { int vec1[] = {1,2,3,4}; int vec2[] = {4,3,2,1}; int *p = NULL; p = add (vec1,vec2,4); … // more work printf(“%d, %d, %d, %d\n”,p[0],p[1],p[2],p[3]); free(p); return 0; } Correct function add() int* add( int v1[], int v2[], int n){ int *q = malloc( n * sizeof(int) ); … /* q can be used as the name of an array of n ints; add vectors and store result in array q */ return q; }

More Related