250 likes | 387 Views
CPS 393 Introduction to Unix and C. START OF WEEK 9 (C-3). Pointers. Pointer is a data type which allows storage of location (address) of data rather than data itself. int main(void) { int Num; int *NumPtr; Num=5; NumPtr = & Num; printf(" %d <br>", * NumPtr ); * NumPtr = 7;
E N D
CPS 393Introduction to Unix and C START OF WEEK 9 (C-3) Course material created by D. Woit
Pointers Pointer is a data type which allows storage of location (address) of data rather than data itself. int main(void) { int Num; int *NumPtr; Num=5; NumPtr = &Num; printf(" %d \n", *NumPtr ); *NumPtr = 7; printf(" %p %d %d \n", NumPtr, *NumPtr, Num ); return(0); } NumPtr is a "pointer to int" &Num is the address of variable Num (1200 here) *NumPtr is the value at address in NumPtr (de-reference NumPtr) or, what NumPtr "points to" 8/28/2014 Course material created by D. Woit 2
After statements Num=5; NumPtr = &Num; memory allocation is; 1200 1204 1208 ... 1531 - memory addresses ------------------------ --------------- ... | 5 | | | ... |1200 | - memory storage ------------------------ ---------------- NumNumPtr After statement *NumPtr = 7; memory allocation is: 1200 1204 1208 ... 1531 - memory addresses ------------------------ --------------- ... | 7 | | | ... |1200 | - memory storage ------------------------ ---------------- NumNumPtr 8/28/2014 Course material created by D. Woit 3
Pointers and Arrays an array name is an address (i.e., a pointer) i.e. it is address of the 1st item of the array Code in ptr1.c int main(void) { int A[5] = {1,2,3,4,5}; int *p; p=A; printf("%d %d %d ", *p, *(p+1), *(p+2) ); putchar('\n'); printf("%d %d %d ", p[0], p[1], p[2] ); putchar('\n'); printf("%p %p %p ", p, p+1, p+2 ); printf("\nsize of int: %d\n",sizeof(int)); return(0); } 8/28/2014 Course material created by D. Woit 4
int A[5] = {1,2,3,4,5}; 100 104 108 112 116 ... 236 ... …. 300 ------------------------ ----- ------ ------ | 1 | 2 | 3 | 4 | 5 |... … | |....... |100| ------------------------ ----- ----- ------- A[0] A[1] A[2] A[3] A[4] A int *p; 100 104 108 112 116 ... 236 ... 300 ---------------------------- -------- ----- | 1 | 2 | 3 | 4 | 5 |... | |... |100| -------------------------- ---- ----------- A[0] A[1] A[2] A[3] A[4] pA p=A; 100 104 108 112 116 ... 236 ... 300 ----------------------------- ----- --- | 1 | 2 | 3 | 4 | 5 |... |100|... |100| ------------------------ ----- ------ ----- A[0] A[1] A[2] A[3] A[4] pA 8/28/2014 Course material created by D. Woit 5
Discussion of previous example in ptr1.c printf("%d %d %d ", *p, *(p+1), *(p+2) ); putchar('\n'); printf("%d %d %d ", p[0], p[1], p[2] ); putchar('\n'); printf("%p %p %p ", p, p+1, p+2 ); 1 2 3 1 2 3 100 104 108 //assuming above storage placement why 104 ? 4 byte ints on our machine--use sizeof(int) to see. ^ sizeof is a keyword (built-in like "for") depends on type of p. if int *p then p+1 is p+4bytes if char *p then p+1 is p+1byte 8/28/2014 Course material created by D. Woit 6
Pointers cont. Wrong usage , see ptrerr.c : char B[] = "bcd"; char *p = B; /*initialize ptr to address of B[0] or ...*/ /*or: char *p = &B[0]; */ assuming &B[0] is 1000, what is the output of: printf("%p %p %p ", p, p+1, p+2 ); SAME THING: char B[] = "bcd"; char *p; p=B; /*or p=&B[0]*/ Note p[1] same as B[1] same as *(p+1) i.e., 'c' p[0] same as B[0] same as *p i.e., 'b' 8/28/2014 Course material created by D. Woit 7
//Source: cptr.c char S[9]="Pointers"; char *cptr; cptr=S; # try to omit this line and compile and then run while ( putchar(*cptr++) ); //putchar returns the char it printed //this prints the '\0' but the following //do not: // or, more clearly // while ( *cptr ) putchar(*cptr++); // or even more clearly // while ( *cptr != '\0' ) putchar(*cptr++); // or even more clearly // while ( *cptr != '\0' ) { // putchar(*cptr); // cptr++; // } 8/28/2014 Course material created by D. Woit 8
/*Source: sample12d.c */ /*Input: a string max length 39 */ /*Output: the string in upper case */ /*Purpose: convert string to upper case */ #include <ctype.h> #include <stdio.h> int main(void) { char str[40], *p; printf("Enter a string: "); (void) gets(str); p=&str[0]; /*or p=str */ while ( *p != '\0' ) { /*or while(*p) */ *p++ = toupper(*p); } printf("%s\n",str); exit(0); } Note: the body of the while stmt is exactly same as { *p = toupper(*p); p++; } 8/28/2014 Course material created by D. Woit 9
/*Source highest.c*/ #define ELTS 5 #include <stdio.h> int main(void) { int i, *high, *p; int array[ELTS]={200,34,78,600,45}; high=array; p=array; for ( i=1; i< ELTS; i++ ) { p++; if (*p > *high) high = p; } printf("the highest number is %d \n", *high); printf("at address %p \n", high); printf("at index %d of array \n", high-array); exit(0); } 8/28/2014 Course material created by D. Woit 10
Pointers and String Constants when compiler encounters a string constant, it stores it in a string table and generates a pointer to the string (address) char *p; p="A String"; printf(p); Note that the following is BAD: char *p; gets(p); printf(p); Why bad? p has no storage allocated to it. It might "work" sometimes and not work other times because its storage is overwritten, or because the value IN p does not point to an accessible storage location. 8/28/2014 Course material created by D. Woit 11
Pointers as Parameters all parameters in C are passed by value However, we can fake pass by reference by passing the *address*, and then use * inside function to modify the data this explains: scanf("%d", &num ); Example: int A[20]; A is the address of the array (address of A[0]) Thus, a function call such as sum(A) passes the *address*; so any changes to A within sum are retained (i.e., like call by reference.) 8/28/2014 Course material created by D. Woit 12
(code in callByRef.c) Example for call by reference: void add1 (int *x) { *x = *x + 1 ; } ... int a=5; add1(&a); printf("a is %d\n",a); 8/28/2014 Course material created by D. Woit 13
/*Source: sample14.c*/ void swap(int *arg1, int *arg2); int main(void) { int i=0, j=2; printf("i is %d, j is %d \n", i,j); swap(&i,&j); printf("i is %d, j is %d \n", i,j); exit(0); } /*Function: swap Purpose: swap values of 2 integers Input: addresses of the 2 integers to swap Output: none */ void swap(int *arg1, int *arg2 ) { int temp; temp = *arg1; *arg1=*arg2; *arg2=temp; } prints? 8/28/2014 Course material created by D. Woit 14
/*Source: sample15.c */ void swap1 (int A[2] ); int main(void) { int A[2]={1,2}; printf("%d %d \n", A[0], A[1] ); swap1(A); printf("%d %d \n", A[0], A[1] ); exit(0); } void swap1 (int A[2] ) { int temp; temp = A[0]; A[0] = A[1]; A[1] = temp; } These function prototypes are all the same: void swap1(int A[2]); void swap1(int A[]); void swap1(int *A); 8/28/2014 Course material created by D. Woit 15
/*Source: sample16.c*/ #include <stdio.h> #include <string.h> char *addXX(char *S); int main(void) { char str1[25], *str2; gets(str1); str2=addXX(str1); puts(str2); exit(0); } char *addXX(char *S) { strcat(S,"XX"); return (S); } Does str2 have storage allocated? No need. What happens if the user enters a string that is more than 23 chars long? A function may have type "pointer to type" 8/28/2014 Course material created by D. Woit 16
HMWK 1. Write a function with prototype: void swap_string1(char *A, char *B); The function swaps the strings in A and B. It does this by looping through the string(s) and swapping individual characters. If your function needs to know the length of a string, it can use strlen from string.h, or it can just look for the '\0' at the string end. Write a main program to test swap_string1. Your main must allocate all the storage required for the strings. DO NOT copy junk from memory. Only copy characters from the strings. 8/28/2014 Course material created by D. Woit 17
Multiple Indirection char **mp, *p, ch; 1080 ... 1248 ... 1272 ----------- ---------- ---------- ... | | ... | | ... | | ----------- ---------- ---------- mp p ch p=&ch; mp=&p; **mp='A'; 1080 ... 1248 ... 1272 ----------- ---------- -------------- ... | 1248 | ... | 1272 | ... | A | ----------- ---------- --------------- mp p ch This is same as simply ch= ‘A’ 8/28/2014 Course material created by D. Woit 18
Precedence of Array & Ptr operations: • Operator Precedence Associativity (see below) • () [] -> . left • ++ -- sizeof ! ~ (type) + - * & right (ALL ARE UNARY OPERATORS) • * / % left • + - left (BINARY) • << >> left • < <= > >= left • == != left • & left (BINARY) • ^ left • | left • && left • || left • ?: right • = += -= *= /= %= &= ^= |= <<= >>= right • , left 8/28/2014 Course material created by D. Woit 19
Associativity means if 2 operators with equal precedence are in an expression, they will be done from left-to-right if left-assoc and from right-to-left if right-assoc ~ is one's complement (unary) ! is logical not: if (!x) ++ -- are unary inc/decrement prefix or postfix: i++ or ++i unary * unary & are ptr dereference, address of << >> left bit shift, right bit shift && || logical and, or & | ^ bitwise and, or, Xor ?: ternary operation (for conditional e.g., z = (a>b) ? a : b ; resolves to: z = a OR z = b , depending 8/28/2014 Course material created by D. Woit 20
Note: **a means *(*a) &(&a) means &a (&&a is invalid) &a[1] means &(a[1]) *a[1] means *(a[1]) 8/28/2014 Course material created by D. Woit 21
Dealing with errors Compile this program with gcc –lm –o sqrt sqrt.c • //source sqrt.c • #include <stdio.h> • #include <errno.h> • #include <math.h> • #define POSITIVE 25 • #define NEGATIVE -25 8/28/2014 Course material created by D. Woit 22
int main(void){ double ret; errno = 0; ret = sqrt(NEGATIVE); if (errno == EDOM) /*EDOM Signifies Domain Error*/ //printf("Domain Error : Invalid Input To Function\n"); perror("sqrt"); else printf("Valid Input To Function\n"); errno = 0; ret = sqrt(POSITIVE); if (errno == EDOM) printf("Domain Error : Invalid Input To Function\n"); else printf("Valid Input To Function\n"); return 0; } 8/28/2014 Course material created by D. Woit 23
If a function sets errno, it is stated in man page. e.g., • man scanf • then search for errno • then search for ERROR