C Programming Review 1 A Overview Integer Errors

  • Slides: 30
Download presentation
C Programming Review 1

C Programming Review 1

A Overview • Integer Errors • Representation, conversion, operations • Common misunderstandings, sources of

A Overview • Integer Errors • Representation, conversion, operations • Common misunderstandings, sources of error • • Pointers Arrays Dynamic memory allocation Memory Errors 2

A Brief Review of C Pointers • Lots of power; lots of danger. •

A Brief Review of C Pointers • Lots of power; lots of danger. • C’s relatively unstructured notion of a pointer lets one access a program’s address space at the byte level. • Suppose x is an int. Then &x is the address of x. • If one declares int *px, then px is a storage cell in which one may store the address of some int. (Equivalently, may store a pointer to some int. ) How much memory must be allocated for a pointer? Does a char * need less than a long * ? Why track type of object at pointer address? 3

Brief Review of C Pointers • Given the declarations: int x; int *px; then

Brief Review of C Pointers • Given the declarations: int x; int *px; then the assignment: px = &x; assigns the address of x to the variable px. • In the context of expression evaluation, * is an indirect reference operator. int x, y, *px; px = &x; y = *px; // same as y = x • The * operator treats its argument as the address of the ultimate value and accesses the value through the address. 4

A • Pointer assignment: int x, *py; char c; px py *py px =

A • Pointer assignment: int x, *py; char c; px py *py px = &x; = px; = 0; = &c; // ? ? ? • Pointer arithmetic: foo *ptr; ptr++; ptr = ptr + 6; *ptr++; (*ptr)++; Information may be lost. For example, on a byte addressable machine with integers aligned on four byte boundaries, either (1) convert to valid int *; value changes, will not be the same on conversion back to char * (2) use invalid int * (See next overhead) foo *s, *t; . . . s – t. . . 5

Integers aligned on 4 byte boundaries • Even on byte addressable machine, else four

Integers aligned on 4 byte boundaries • Even on byte addressable machine, else four fetches vs. one (slow) #include <stdio. h> struct s{ char c 1; //-- One byte (usually) char c 2; int i; //-- Four bytes (usually) }; int main(){ struct s str; printf("Address of str. c 1 is %pn", &(str. c 1)); printf("Address of str. c 2 is %pn", &(str. c 2)); printf("Address of str. i is %pn", &(str. i)); printf("Size of struct is %un", sizeof(struct s)); } $. /align Address of str. c 1 is 0 x 7 fff 5 b 324 b 28 Address of str. c 2 is 0 x 7 fff 5 b 324 b 29 Address of str. i is 0 x 7 fff 5 b 324 b 2 c Size of struct is 8 28 29 2 A 2 B c 1 c 2 PADDING 2 C i 6

A #include <stdio. h> main(){ int x, *px; char c, *pc; px=&x; pc=&c; printf("px

A #include <stdio. h> main(){ int x, *px; char c, *pc; px=&x; pc=&c; printf("px %p &x %p pc %p &c %p n", px, (int *)&x, pc, (char *)&c); printf("Size of: integer %u, char %un", sizeof(int), sizeof(char)); px++; pc++; printf("px after inc %p pc after inc %pn", px, pc); } $. /ptr. Arith px 0 xbff 6 bf 04 &x 0 xbff 6 bf 04 pc 0 xbff 6 bf 03 &c 0 xbff 6 bf 03 Size of: integer 4, char 1 px after inc 0 xbff 6 bf 08 pc after inc 0 xbff 6 bf 04 7

 • The & operator may be applied to variables and array elements. pc

• The & operator may be applied to variables and array elements. pc = &mystring[5]; // same as pc = mystring + 5 • Things like &(x+1) and &3 are not allowed. • Pointers with indirection are OK in expressions. Generally speaking, *px OK where x OK: y = *px + 1; *px = 0; printf(“%dn”, *px); *px += 1; d = sqrt((double)*px); (*px)++; // () deliberate 8

Using pointers to modify arguments #include <stdio. h> void swap(int *first, int *second) {

Using pointers to modify arguments #include <stdio. h> void swap(int *first, int *second) { int temp; temp = *first; *first = *second; *second = temp; } main() { int x, y; x = 3; y = 5; printf("Before: x=%d y=%dn", x, y); swap(&x, &y); printf("After: x=%d y=%dn", x, y); } % good. Swap Before: x=3 y=5 After: x=5 y=3 9

Arrays • Close correspondence between array of type T and pointer to T •

Arrays • Close correspondence between array of type T and pointer to T • Value of array identifier converted to pointer to zeroth element of the array char mystring[20]; char *pc; . . . pc = mystring; pc = &mystring[0]; . . . a[i]=5; *((a) + (i))=5 10

A int i. Arr[5]={0, 1, 2, 3, 4; { char ch. Arr[5]={'a', 'b', 'c',

A int i. Arr[5]={0, 1, 2, 3, 4; { char ch. Arr[5]={'a', 'b', 'c', 'd', 'e'}; int *iptr; char *cptr; iptr=i. Arr; iptr++; printf("i. Arr[1] is %dn", *iptr); cptr=ch. Arr; cptr++; printf("ch. Arr[1] is %cn", *cptr); iptr=(int *)ch. Arr; iptr++; printf("What is four bytes past &cptr[0]? %cn", *(char *)iptr); cptr=(char *)i. Arr; cptr++; printf("Too weird. Here it is: %d. Just say no. n", *(int *)cptr); } $. /arrays i. Arr[2] is 1 ch. Arr[2] is b What is four bytes past &cptr[0]? e Too weird. Here it is: 16777216. Just say no. 11

Dynamic Memory Allocation NAME calloc, malloc, free, realloc - Allocate and free dynamic memory

Dynamic Memory Allocation NAME calloc, malloc, free, realloc - Allocate and free dynamic memory SYNOPSIS #include <stdlib. h> void *calloc(size_t nmemb, size_t size); void *malloc(size_t size); void free(void *ptr); void *realloc(void *ptr, size_t size); DESCRIPTION The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not initialized. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be success fully passed to free(). The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed. The calloc() function allocates memory for an array of nmemb elements of size bytes each and returns a pointer to the allocated memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either NULL, or a unique pointer value that can later be successfully passed to free(). 12

realloc() changes the size of the memory block pointed to by ptr to size

realloc() changes the size of the memory block pointed to by ptr to size bytes. The contents will be unchanged to the minimum of the old and new sizes; newly allocated memory will be uninitialized. If ptr is NULL, the call is equivalent to malloc(size); if size is equal to zero, the call is equivalent to free(ptr). Unless ptr is NULL, it must have been returned by an earlier call to malloc(), calloc() or realloc(). RETURN VALUES For calloc() and malloc(), the value returned is a pointer to the allocated memory, which is suitably aligned for any kind of variable, or NULL if the request fails. free() returns no value. realloc() returns a pointer to the newly allocated memory, which is suitably aligned for any kind of variable and may be different from ptr, or NULL if the request fails or if size was equal to 0. If realloc() fails the original block is left untouched - it is not freed or moved. SEE ALSO brk(2) 13

A Small, but Nontrivial, Example /* bintree. c */ #include <stdio. h> #include <stdlib.

A Small, but Nontrivial, Example /* bintree. c */ #include <stdio. h> #include <stdlib. h> #define NILNODE (struct node *)0 struct node { char data; struct node *left, *right; }; int main(){ struct node *gimme(), *n 1, *n 2, *n 3, *n 4, *n 5, *n 6, *n 7; void inorder(); n 1 n 2 n 3 n 4 n 5 n 6 n 7 = = = = gimme('a', gimme('b', gimme('c', gimme('d', gimme('e', gimme('f', gimme('g', NILNODE, n 1, n 2); NILNODE, n 3, n 4); NILNODE, n 5, n 6); NILNODE); 14

inorder(n 7); printf("n"); return 0; } struct node *gimme(val, l, r) char val; struct

inorder(n 7); printf("n"); return 0; } struct node *gimme(val, l, r) char val; struct node *l, *r; { struct node *tmp; tmp = (struct node *) malloc(sizeof(struct node)); tmp->data = val; tmp->left = l; tmp->right = r; return(tmp); } void inorder(r) struct node *r; { if (r != NILNODE) { inorder(r->left); printf("%c", r->data); inorder(r->right); } } %. /bintree acbedgf g e c a f d b 15

Arrays of Pointers • Sometimes convenient to use array of pointers. • Allocate memory

Arrays of Pointers • Sometimes convenient to use array of pointers. • Allocate memory for array contents only as needed • Commonly used for strings (more in a minute) struct stats { unsigned int age; unsigned int sex; unsigned int weight; }; //-- Four bytes int main(){ struct stats *everyone[5]; printf("size of: struct stats * %u struct stats %u everyone %un", sizeof(struct stats *), sizeof(struct stats), sizeof(everyone)); 16

A (continued) everyone[0]=malloc(sizeof(struct stats)); everyone[0]->age=5; everyone[0]->sex=1; everyone[0]->weight=50; everyone[1]=malloc(sizeof(struct stats)); everyone[1]->age=15; everyone[1]->sex=11; everyone[1]->weight=150; printf("everyone at

A (continued) everyone[0]=malloc(sizeof(struct stats)); everyone[0]->age=5; everyone[0]->sex=1; everyone[0]->weight=50; everyone[1]=malloc(sizeof(struct stats)); everyone[1]->age=15; everyone[1]->sex=11; everyone[1]->weight=150; printf("everyone at <%p>teveryone[0] is %p value at ptr location %un", everyone[0], *(unsigned int *)everyone[0]); printf("everyone+1 at <%p>teveryone[1] is %p value at ptr location %un", everyone+1, everyone[1], *(unsigned int *)everyone[1]); $. /arrays 2 size of: struct stats * 8 struct stats 12 everyone 40 everyone at <0 x 7 ffe 50 a 8 a 890> everyone[0] is 0 x 12 ec 010 value at ptr location 5 everyone+1 at <0 x 7 ffe 50 a 8 a 898> everyone[1] is 0 x 12 ec 030 value at ptr location 15 17

A Dynamically allocated array of Pointers type **arr; Expect *arr is a pointer to

A Dynamically allocated array of Pointers type **arr; Expect *arr is a pointer to type To create, initialize array of pointers dynamically: (1) Create space for the array arr=malloc(elements*sizeof(type *)) (2) Initialize each value in the array for i = 0 to elements-1 arr[i]=((arr)+i)=malloc(sizeof(type)) . . . X Y Z (3) Set value of individual elements for i = 0 to elements-1 *(arr[i])=*((arr)+i)=value 18

#define MAX 3 int main(){ int i; int **arr; Example: • Create an array

#define MAX 3 int main(){ int i; int **arr; Example: • Create an array of integer pointers dynamically • Initialize array • Initialize integers arr=malloc(MAX*sizeof(int *)); printf("arr <%p>n", arr); for (i=0; i<MAX; i++) printf("arr[%d] value before initialization <%p>n", i, arr[i]); for (i=0; i<MAX; i++) arr[i]=malloc(sizeof(int)); for (i=0; i<MAX; i++) printf("arr[%d] value after initialization <%p>n", i, arr[i]); for (i=0; i<MAX; i++) *arr[i]=i+7; for (i=0; i<MAX; i++) printf("arr[%d] val <%p> ptr value <%d> val at ptr addrn", i, arr[i], *arr[i]); for (i=0; i<MAX; i++) free(arr[i]); //--- Space allocated for ints free(arr); //--- Space allocated for array of pointers } 19

Strings • We will look at a few examples playing with pointers and strings

Strings • We will look at a few examples playing with pointers and strings • C has no intrinsic data type called a string. • An array of char, terminated with a null byte (byte of all 0’s) (char constant ‘’) is a string, by convention • A char * is often used to refer to a string. Just the address of the first char in the array that is the string • Note carefully the difference between the two declarations: char *str 1; char str 2[20]; 20

Brief Review of C Pointers and Strings int strlen(s) /* returns num. of characters

Brief Review of C Pointers and Strings int strlen(s) /* returns num. of characters in a "string" */ char *s; { char *p; p = s; while (*p) p++; return p-s ; } strcpy(s, t) /* version 1 */ char *s, *t; { while ((*s = *t) != '') { s++; t++; } } 21

strcpy(s, t) /* version 2 */ char *s, *t; { while ((*s++ = *t++)

strcpy(s, t) /* version 2 */ char *s, *t; { while ((*s++ = *t++) != '') ; } strcpy(s, t) /* version 3 */ char *s, *t; { while (*s++ = *t++); } 22

#include <stdio. h> void strcpy 1(s, t) /* version 1 */ char *s, *t;

#include <stdio. h> void strcpy 1(s, t) /* version 1 */ char *s, *t; { while ((*s = *t) != '') { s++; t++; } printf("s %p t %pn", (void *)s, (void *)t); } void strcpy 2(s, t) /* version 2 */ char *s, *t; { while ((*s++ = *t++) != ''); printf("s %p t %pn", (void *)s, (void *)t); } int main(int argc, char *argv[]){ char buf[100]; strcpy 1(buf, argv[0]); strcpy 2(buf, argv[0]); return(0); } s 0 x 7 fff 5 ac 84 ac 7 t 0 x 7 fff 5 ac 84 c 47 s 0 x 7 fff 5 ac 84 ac 8 t 0 x 7 fff 5 ac 84 c 48 23

A Arrays of Strings char **sptr; char *str. Array[] = {"one", "two", "three", "four"};

A Arrays of Strings char **sptr; char *str. Array[] = {"one", "two", "three", "four"}; sptr=str. Array; o n e t w o t h r e e f o u r 24

int main( int argc, char *argv[] ){ int i; char **arr; Differences from integer

int main( int argc, char *argv[] ){ int i; char **arr; Differences from integer allocation example noted in red arr=malloc(argc*sizeof( char * )); printf("arr <%p>n", arr); /* not int* */ for (i=0; i<argc; i++) printf("arr[%d] value before initialization <%p>n", i, arr[i]); for (i=0; i<argc; i++) arr[i]=malloc( strlen(argv[i])+1 ); //- strlen does not include ‘’ for (i=0; i<argc; i++) printf("arr[%d] value after initialization <%p>n", i, arr[i]); for (i=0; i<argc; i++) strcpy(arr[i], argv[i]); //-- strcpy includes ‘’ for (i=0; i<argc; i++) printf("arr[%d] val <%p> val at ptr addr <%s>n", i, arr[i]); for (i=0; i<argc; i++) free(arr[i]); //--- Space allocated for individual integers free(arr); //--- Space allocated for array of pointers } 25

C Programming Errors to Avoid • Always important. . . but errant programs with

C Programming Errors to Avoid • Always important. . . but errant programs with root access can affect any system resource • access/modify system configuration files • erase user data • halt the system, … • Can’t cover all errors, we’ll look at: • Buffer overflows • Memory leaks • Dereferencing invalid pointers 26

Buffer Overflow • Write beyond allocated array bounds (allocated memory) char buf[120]; int get.

Buffer Overflow • Write beyond allocated array bounds (allocated memory) char buf[120]; int get. User. Data() { char copy[60]. . . gets(buf); /* User can input string of ANY length */. . . strcpy(copy, buf); /* Copies until string termination in buf*/ } main(){. . . char input[50]; char *str. Ptr; . . . get. User. Data(); strcpy(str. Ptr, input); /* No memory allocation for str. Ptr */ } 27

Memory Leak • Lose access to allocated memory segment -- cannot be reclaimed int

Memory Leak • Lose access to allocated memory segment -- cannot be reclaimed int func() { void *ptr; ptr=malloc(100); /* When function returns, value of ptr inaccessible */ } main(){ char *bptr; int * an. Int; an. Int=malloc(sizeof(int)); for (i=1, i<10; i++){ bptr=malloc(sizeof(char)); /* Previous value overwritten */ *bptr=i; } /* No memory freed */ } 28

Dereference Invalid Pointer int func(node *n){ if (n->value == 0) free(n) return(0); } main(){

Dereference Invalid Pointer int func(node *n){ if (n->value == 0) free(n) return(0); } main(){ node *p, *q; p=malloc(sizeof(node)); p->value=0; printf("Node p value <%d>", p->value); func(p); printf("After func p value <%d>", p->value); /* p already freed */ printf("Node q value <%d>", q->value); /* q never initialized */ } 29

A Overview • Integer Errors • Representation, conversion, operations • Common misunderstandings, sources of

A Overview • Integer Errors • Representation, conversion, operations • Common misunderstandings, sources of error • • Pointers Arrays Dynamic memory allocation Memory Errors • Review and practice with pointers, arrays of pointers • Any C text is a reference; Harbison and Steele on reserve • Practice problems available on course web page. 30