Arrays, Pointers and Strings Chapter 6 in ABC
One Dimensional Arrays #defineN100 int a[N]; for ( i = 0; i< N; ++i ) sum += a[i]; space for a[0],..., a[99] is allocated process element a[ i ]
One Dimensional Arrays float f[5] = { 0.0, 1.0, 2.0, 3.0, 4.0 }; int a[100] = { 0 }; int a[] = { 2, 3, 5, -7 }; char s[] = “abc”; char s[] = { ‘a’, ‘b’, ‘c’, ‘\0’ };
Pointers p = 0; p = NULL; p = &i; p = (int *) 1776; equivalent to p = 0 an absolute address in memory
abp 12 int a = 1, b = 2, *p; p = &a; b = *p; is equivalent to b = a; abp 12 Pointers
int a = 1, b = 2, *p; p = &a; b = *p; is equivalent to b = a; This is also correct: int a = 1, b = 2, *p = &a;
Pointers #include int main(void) { int i = 7, *p; p = &i; printf( “%s%d\n%s%u\n”, “ Value of i: ”, *p, “Location of i: ”, p ); return 0; } Value of i: 7 Location of i: The result of the printing
Declarations and Initializations int i = 3, j = 5, *p = &i, *q = &j, *r; double x; ExpressionEquivalent ExpressionValue p == &ip == ( &i )1 **&p* ( * ( &p ) )3 r = &xr = ( & x )illegal 7 * *p / *q + 7( ( ( 7 * ( *p ) ) ) / ( *q ) ) *( r = &j ) *= *p( *( r = ( &j ) ) ) *= ( *p )15
Declarations and Initializations Declaration int *p; float *q; void *v; More illegal: &3, &(k + 99), register v; &v Legal AssignmentIllegal Assignment p = 0;p = 1; p = ( int* ) 1;v = 1; p = v = q;p = q; p = ( int* ) q;
Call by Refernce #include void swap(int *p, int *q) { int tmp; tmp = *p; *p = *q; *q = tmp; } int main(void) { int i = 3, j = 5; swap(&i, &j); printf( “%d %d\n”, i, j ); return 0; } 5 3 is printed
Arrays and Pointers a[i] is equivalent to *(a + i) p[i] is equivalent to *(p + i) p = a is equivalent to p = &a[0] p = a + 1is equivalent to p = &a[1] An array name is an address! Pointer arithmetic ~ array indexing
Arrays and Pointers for ( p = a; p < &a[ N ]; ++p ) sum += *p; is equivalent to: for ( i = 0; i < N; ++i ) sum += *( a + i ); is equivalent to: p = a; for ( i = 0; i< N; ++i ) sum += p[ i ];
Arrays and Pointers Illegal expressions a = p ++a a += 2 &a a = p ++a a += 2 &a
Pointer Arithmetic and Element Size double a[2], *p = NULL, *q = NULL; p = a; q = p +1; printf(“%d\n”, q - p); printf(“%d\n”, (int)q - (int)p); points to the base the array equivalent to q = &a[ 1 ] 1 is printed 8 is printed
Arrays as Function Arguments double sum(double a[], int n) { int i = 0; double sum = 0.0; for ( i = 0; i < n; ++i ) sum += a[i]; return sum; } n is the size of a[]
An Example: Bubble Sort void bubble( int a[], int n ) { int i = 0, j = 0; void swap( int *, int * ); for ( i = 0; i < n - 1; ++i ) for ( j = n - 1; j > i; --j ) if ( a[ j-1] > a[ j ] ) swap( &a[ j-1], &a[ j ] ); } n is the size of a[]
Another Example void merge(int a[], int b[], int c[], int m, int n) { int i = 0, j = 0, k = 0; while ( i < m && j < n ) { if ( a[i] < b[j] ) c[k++] = a[i++]; else c[k++] = b[j++]; } while ( i < m ) c[k++] = a[i++]; while (j < n) c[k++] = b[j++]; } Merge a[] of size m and b[] of size n into c[]. pickup any remainder
Mergesort #include void merge(int *, int *, int *, int, int); void mergesort(int key[], int n) { int j = 0, k = 0, m = 0, *w = NULL; for ( m = 1; m < n; m *= 2 ) ; if ( m != n ) { printf( “ERROR: Size of the array is not a power of 2 - bye!\n” ); exit( 1 ); } Use merge() to sort an array of size n no additional statements for this loop
Mergesort w = calloc( n, sizeof( int ) ); for ( k = 1; k < n; k *= 2 ) { for ( j = 0; j < n - k; j += 2 * k ) merge( key + j, key + j + k, w + j, k, k ); for (j = 0; j < n; ++j) key[j] = w[j]; } free(w); w = NULL; } allocate workspace merge into w write w back into key free the workspace
Mergesort #include #define KEYSIZE 16 void mergesort(int *, int); int main(void) { int i, key[] = { 4, 3, 1, 67, 55, 8, 0, 4, -5, 37, 7, 4, 2, 9, 1, -1 }; mergesort(key, KEYSIZE); printf( “After mergesort:\n” ); for ( i = 0; i < KEYSIZE; ++i ) printf( “%4d”, key[i] ); putchar( ‘\n’ ); return 0; }
Strings char *p = “abcde” printf( “%s %s\n”, p, p +1 ); char s[] = “abcde” is equivalent to: char s[] = {‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘\0’}; abcde bcde is printed
Strings char *p = “abcde” vs. char s[] = “abcde” s p abcde\0 abcde
Strings “abc”[1] and *(“abc” + 2) make sense char *s = NULL; int nfrogs = 0;.. s = (nfrogs == 1)? “” : “s”; printf( “we found %d frog%s in the pond!\n”, nfrogs, s ); NULL Strings
Count the number of words in a string #include int word_cnt(char *s) { int cnt = 0; while (*s != '\0') { while (isspace(*s)) ++s; if (*s != '\0') { ++cnt; while (!isspace(*s) && *s != '\0') ++s; } return cnt; } skip white spaces found a word skip the word
char *strcat(char *s1, const char *s2); int strcmp(const char *s1, const char *s2); char *strcpy(char *s1, const char *s2); unsigned strlen(const char *s); String Handling Functions in the Standard Library
unsigned strlen( const char *s ) { register int n = 0; for ( n = 0; *s != '\0'; ++s ) ++n; return n; }
String Handling Functions in the Standard Library char *strcat( char *s1, const char *s2 ) { register char *p = s1; while ( *p ) ++p; while ( *p++ = *s2++ ) ; return s1; } no more statements in this loop
Multidimensional Arrays int sum( int a[][5] ) { int i = 0, j = 0, sum = 0; for ( i = 0; i < 3; ++i ) for ( j = 0; j < 5; ++j ) sum += a[i][j]; return sum; }
Multidimensional Arrays int sum( int a[][9][2] ) { int i = 0, j = 0, k = 0, sum = 0; for ( i = 0; i < 7; ++i ) for ( j = 0; j < 9; ++j ) for ( k = 0; k < 2; ++k ) sum += a[i][j][k]; return sum; }
Sort Words Lexicographically #include #define MAXWORD 50 /* max word size */ #define N 1000 /* array size */ void sort_words(char *[], int); void swap(char **, char **);
Sort Words Lexicographically int main(void) { char *w[N]; char word[MAXWORD]; int n = 0, i = 0; for ( i = 0; scanf("%s", word) == 1; ++i ) { if ( i >= N ) { printf( “Sorry, at most %d words can be sorted.”, N ); exit(1); } w[i] = calloc(strlen(word) + 1, sizeof(char)); strcpy(w[i], word); } an array of pointers work space number of wrods to be stored
Sort Words Lexicographically n = i; sort_words( w, n ); for ( i = 0; i < n; ++i ) printf( “%s\n”, w[i] ); return 0; } print the sorted words
void sort_words( char *w[], int n ) { int i = 0, j = 0; for ( i = 0; i < n; ++i ) for ( j = i + 1; j < n; ++j ) if ( strcmp(w[i], w[j]) > 0 ) swap( &w[i], &w[j] ); } void swap( char **p, char **q ) { char *temp = NULL; temp = *p; *p = *q; *q = temp; } Sort Words Lexicographically n elements to be sorted
Arguments to main() #include void main(int argc, char *argv[]) { int i = 0; printf( “argc = %d\n”, argc ); for ( i = 0; i < argc; ++i ) printf( “argv[%d] = %s\n”, i, argv[i] ); }
Ragged Arrays #include int main(void) { char a[2][15]= { “abc:”, “a is for apple” }; char *p[2]= { “abc:”, “a is for apple”}; printf( “%c%c%c %s %s\n%c%c%c %s %s\n”, a[0][0], a[0][1], a[0][2], a[0], a[1], p[0][0], p[0][1], p[0][2], p[0], p[1] ); return 0; } abc abc: a is for apple
Functions as Arguments double sum_square( double f(double), int m, int n ) { int k = 0; double sum = 0.0; for ( k = m; k <= n; ++k ) sum += f(k) * f(k); return sum; } double sum_square( double (*f)(double), int m, int n ) {.....
Functions as Arguments #include double f(double), sin(double), sum_square(double (*)(double), int, int); int main(void) { printf( “%s%.7f\n%s%.7f\n”, “ First computation: ”, sum_square(sin, 2, 13), “Second computation: ”, sum_square(f, 1, 10000)); return 0; } double f(double x) { return 1.0 / x; First computation: } Second computation:
Find a root of f() by the bisection method #define EPS 1e-12 double root(double f(double), double a, double b) { double m = (a + b) / 2.0; if (f(m) == 0.0 || b - a < EPS) return m; else if (f(a) * f(m) < 0.0) return root(f, a, m); else return root(f, m, b); } epsilon midpoint
Find a root of f() by the bisection method #include double p(double); double root(double (*)(double), double, double); int main(void) { double x = root( p, 0.0, 3.0 ); printf( “%s%.16f\n%s%.16f\n”, “Approximate root: ”, x, “ Function value: ”, p( x ) ); return 0; }
Find a root of f() by the bisection method double p(double x) { return (x * x * x * x * x * x - 3.0); } Approximate root: Function value:
Const const type qualifier; comes after storage class static const int k=3; const int a = 7; int *p = &a; /* compiler warning */ const int a = 7; const int *p = &a; /* ok */ int a=7; int * const p = &a; /* the pointer is a constant */ int a=7; const int * const p = &a; /* both pointer and pointed int are constants. */
qsort: a generic sorting procedure qsort's prototype in stdlib.h (using size_t from stddef.h): void qsort(void *array, size_t n_elem, size_t elem_size, int compare(const void *, const void *)); compare(a,b) returns negative int if a<b returns 0 if a=b returns positive int if a>b
// qsort an array of ints #include #define KEYSIZE 16 int compare_int(const void *p1, const void *p2); void print_array(char *title, int *key, int n_elem); int main(void) { int key[] = { 4, 3, 1, 67, 55, 8, 0, 4, -5, 37, 7, 4, 2, 9, 1, -1 }; print_array("before ", key, KEYSIZE); qsort(key, KEYSIZE, sizeof(int), compare_int); print_array("after ", key, KEYSIZE); return 0; }
void print_array(char *title, int *key, int n_elem) { int i; printf("\n %s:\n",title); for (i = 0; i < n_elem; ++i) printf("%4d", key[i]); putchar('\n'); } // the compare function to be passed as a parameter to qosrt int compare_int(const void *p1, const void *p2) { const int *q1 = p1, *q2 = p2; return ((*q1) - (*q2)); }
Handling nXn matrices // allocating the matrix int i,j,n; double **a; a = calloc(n,sizeof(double *)); for (i=0; i<n; ++i) a[i] = calloc(n,sizeof(double));... // filling in the matrix with numbers in the range [-N,N]: for (i = 0; i < n; ++i) for (j = 0; j < n; ++j) a[i][j] = rand() % (2 * N + 1) - N; …
... // computing the trace double trace(double **a, int n) { int i; double sum = 0.0; for (i=0; i<n; ++i) sum += a[i][i]; /* sum the elements on the main diagonal */ return sum; }
The trace program (Chapter 12.6) The space for the elements of the matrix is allocated all at once. * Pointers are offset so that the indexing starts at 1, not // trace.h #include #include typedef double dbl; // could be substituted with other types
The trace program (Chapter 12.6) The space for the elements of the matrix is allocated all at once. Pointers are offset so that the indexing starts at 1, not פרוטוטייפס void check_cmd_line(int argc, char **argv); void fill_matrix(dbl **a, int m, int n); dbl ** get_matrix_space(int m, int n); void release_matrix_space(dbl **a); dbl trace(dbl **a, int m, int n); void wrt_info(const char *pgm_name); void wrt_matrix(const char *s, dbl **a, int m, int n);
// main.c #include "trace.h" int main(int argc, char **argv) { int m; /* number of rows */ int n; /* number of columns */ int val; dbl **a; /* matrix */ srand(time(NULL)); /* seed the random number generator */ check_cmd_line(argc, argv); printf("%s\n", "---\n" "This program creates space for an mxn matrix A, fills it with\n" "randomly distributed digits from - 9 to +9, and then prints\n" "the matrix A and its trace.\n"); for ( ; ; ) { printf("Input m and n: "); val = scanf("%d%d", &m, &n); if (val != 2 || m < 1 || n < 1) break; putchar('\n'); a = get_matrix_space(m, n); fill_matrix(a, m, n); … }
// main.c … srand(time(NULL)); /* seed the random number generator */ check_cmd_line(argc, argv); printf("%s\n", "---\n" "This program creates space for an mxn matrix A, fills it with\n" "randomly distributed digits from - 9 to +9, and then prints\n" "the matrix A and its trace.\n"); for ( ; ; ) { printf("Input m and n: "); val = scanf("%d%d", &m, &n); if (val != 2 || m < 1 || n < 1) break; putchar('\n'); a = get_matrix_space(m, n); fill_matrix(a, m, n); wrt_matrix("A", a, m, n); printf("trace(A) = %.1f\n\n", trace(a, m, n)); release_matrix_space(a); } printf("\nBye!\n\n"); return 0; }
// check-cmd-line.c #include "trace.h" void check_cmd_line(int argc, char **argv) { if (argc > 1 && strcmp(argv[1], "-h") == 0) { wrt_info(argv[0]); exit(1); } if (argc > 1) { printf("\nERROR: No command line arguments needed.\n\n"); wrt_info(argv[0]); exit(1); }
// allocate-free.c #include "trace.h" dbl **get_matrix_space(int m, int n) { int i; dbl *p; dbl **a; p = malloc(m * n * sizeof(dbl)); /* get the space all at once */ a = malloc(m * sizeof(dbl *)); assert(p != NULL); assert(a != NULL); /* // Offset pointers to change the indexing. */ --a; /* index from 1, not 0 */ for (i = 1; i <= m; ++i) a[i] = p + ((i - 1) * n) - 1; /* index from 1, not 0 */ return a; }
// allocate-free.c #include "trace.h" void release_matrix_space(dbl **a) { dbl *p; /* // The effects of offsetting the pointers // must be undone before releasing space. */ p = a[1] + 1; /* base address in memory */ free(p); free(a + 1); }
// write.c #include "trace.h" void wrt_matrix(const char *s, dbl **a, int m, int n) { int i, j; printf("%s =\n", s); for (i = 1; i <= m; ++i) { for (j = 1; j <= n; ++j) printf("%6.1f", a[i][j]); putchar('\n'); } putchar('\n'); }
// fill-matrix.c #include "trace.h" void fill_matrix(dbl **a, int m, int n) { int i, j; for (i = 1; i <= m; ++i) for (j = 1; j <= n; ++j) a[i][j] = rand() % ; /* from -9 to +9 */ }
// compute-trace.c #include "trace.h" dbl trace(dbl **a, int m, int n) { int i; int k; dbl sum = 0.0; k = (m < n) ? m : n; for (i = 1; i <= k; ++i) sum += a[i][i]; return sum; }