Pointers and Structure Bin Li Assistant Professor Dept. of Electrical, Computer and Biomedical Engineering University of Rhode Island 1
Pointer Variables Each variable in a C program occupies space in memory during its lifetime: The address of a variable is the address of its first byte in memory. A pointer variable is a variable capable of storing the address of ( pointing to ) another variable. 2
Pointer Variables When a pointer variable is declared, its name is preceded by an asterisk: int *p; The * indicates that p is not an integer variable, but rather a variable capable of pointing to an integer. Each pointer variable can point only to objects of a particular type: int *p; /* points only to integers */ float *q; /* points only to float values */ char *r; /* points only to characters */ Before it has been assigned a value, a pointer points to nothing in particular. 3
The Address Operator A pointer can be given a value by assigning it the address of a variable. To determine the address of a variable, use the address operator (represented by the & symbol): int i, *p; p = &i; After this assignment, p points to i: 4
Pointer Representation in Memory The following figure shows the representation of the pointer in memory, assuming that integer variable y is stored at location 600,000, and pointer variable yptr is stored at location 500,000. The operand of the address operator (&) must be a variable; the address operator (&) cannot be applied to constants or expressions. 5
The Indirection Operator To determine what a pointer currently points to, use the indirection operator (represented by the * symbol): int i, *p; p = &i; printf("%d\n", *p); printf will display the value of i. 6
The Indirection Operator The unary * operator, commonly referred to as the indirection operator or dereferencing operator, returns the value of the object to which its operand (i.e., a pointer) points. For example, the statement printf("%d", *yptr); prints the value of variable y, namely 5. Using * in this manner is called dereferencing a pointer. 7
The Indirection Operator If p points to i, then *p is just another name for i: int i, *p; p = &i; i = 1; printf("%d\n", i); /* prints 1 */ printf("%d\n", *p); /* prints 1 */ *p = 2; printf("%d\n", i); /* prints 2 */ printf("%d\n", *p); /* prints 2 */ 8
& and * Operators #include<stdio.h> int main() { int a = 7; int *aptr = &a; //set aptr to the address of a printf("the address of a is %p\n The value of aptr is %p\n\n", &a, aptr); printf("the value of a is %d\n The value of *aptr is %d\n\n", a, *aptr); printf("showing that * and & are complements of each other \n &*aptr = %p\n *&aptr = %p\n", &*aptr, *&aptr); } 9
Pointer Assignment One pointer may be assigned to another, provided that both have the same type: int i, *p, *q; p = &i; q = p; After the assignment, both p and q point to i: Any number of pointers may be pointing to the same variable. 10
Pointer Assignment Don t confuse pointer assignment with assignment using the indirection operator: int i, j, *p, *q; p = &i; q = &j; i = 1; *q = *p; 11
Passing Arguments to Functions by Value #include<stdio.h> int cubebyvalue(int n); int main() { int number = 5; // initialize number printf("the original value of number is %d\n", number); number = cubebyvalue(number); //pass number by value to cubebyvalue printf("the new value of number is %d\n", number); } // calculate and return cube of integer argument int cubebyvalue(int n) { return n * n * n; //cube local variable n and return result } 12
Passing Arguments to Functions by Reference #include<stdio.h> void cubebyvalue(int *nptr); int main() { int number = 5; // initialize number printf("the original value of number is %d\n", number); //pass address of number to cubebyvalue cubebyvalue(&number); printf("the new value of number is %d\n", number); } // calculate cube of *nptr; actually modifies number in main void cubebyvalue(int *nptr) { *nptr = (*nptr) * (*nptr) * (*nptr); //cube *nptr } 13
Pass-By-Value 14
Pass-By-Value 15
Pass-By-Value 16
Pass-By-Reference 17
Pass-By-Reference 18
Swap with Pass-By-Value How to write a function that swaps the values stored in two variables? swap(a, b); void swap(int x, int y) { int temp; At assembly time, this function call will be expanded to create three variables in the stack area. The stack pointer will be increased as the result. } temp = x; x = y; y = temp; The return statement is hidden. At assembly time, the return statement will be expanded to delete three variables in the stack area. The stack pointer will be decreased as the result. Is the above function correct? If not, why? 19
Swap with Pass-By-Value swap(a, b); void swap(int x, int y) { int temp; } temp = x; x = y; y = temp; At this moment Varible name value address a 1 A b 2 B x 1 C y 2 D temp? E 20
Swap with Pass-By-Value swap(a, b); void swap(int x, int y) { int temp; } temp = x; x = y; y = temp; At this moment Varible name value address a 1 A b 2 B x 2 C y 1 D temp 1 E 21
Swap with Pass-By-Value swap(a, b); void swap(int x, int y) { int temp; } temp = x; x = y; y = temp; At this moment Varible name value address a 1 A b 2 B 22
Pointers as Arguments For a function to be able to modify a variable, it must be given a pointer to the variable: void swap(int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp; } swap(&x, &y); scanf is an example of a function whose arguments must be pointers: scanf("%d%d", &i, &j); 23
Swap with Pass-By-Reference How to write a function that swaps the values stored in two variables? swap(&a, &b); void swap(int *px, int* py) { int temp; } temp =???;???;??? = temp; At this moment Varible name value address a 1 A b 2 B px A C py B D tmp? E 24
Swap with Pass-By-Reference swap(&a, &b); void swap(int *px, int* py) { int temp; } temp = *px; *px = *py; *py = temp; Varible name value address a 1 A b 2 B px A C py B D tmp 1 E 25
Swap with Pass-By-Reference swap(&a, &b); void swap(int *px, int* py) { int temp; } temp = *px; *px = *py; *py = temp; Varible name value address a 2 A b 2 B px A C py B D tmp 1 E 26
Swap with Pass-By-Reference swap(&a, &b); void swap(int *px, int* py) { int temp; } temp = *px; *px = *py; *py = temp; Varible name value address a 2 A b 1 B px A C py B D tmp 1 E 27
Swap with Pass-By-Reference swap(&a, &b); void swap(int *px, int* py) { int temp; } temp = *px; *px = *py; *py = temp; Varible name value address a 2 A b 1 B 28
Using Pointers for Array Processing Pointers to Array Elements A pointer variable may point to an element of an array: int a[10], *p; p = &a[0]; *p = 5; /* stores 5 into a[0] */ Use this ability for scanf: scanf("%d", &a[i]);
Pointer Arithmetic Three arithmetic operations are defined for pointers: Adding an integer to a pointer Subtracting an integer from a pointer Subtracting two pointers
Adding an Integer to a Pointer Adding an integer j to a pointer p yields a pointer to the element that is j places after the one that p points to. int a[10], *p, *q; p = &a[2]; q = p + 3;
Adding an Integer to a Pointer p += 6;
Subtracting an Integer from a Pointer If p points to the array element a[i], then p - j points to a[i-j]. p = &a[8]; q = p - 3; p -= 6;
Subtracting Pointers When two pointers are subtracted, the result is the distance (measured in array elements) between the pointers. p = &a[5]; q = &a[1]; i = p - q; /* i is 4 */ i = q - p; /* i is -4 */ Note: Performing arithmetic on a pointer p gives a meaningful result only when p points to an array element. Subtracting two pointers is meaningful only when both point to elements of the same array
Pointer Comparison Any two pointers of the same type may be compared using the equality operators (== and!=). Pointers may also be compared using the relational operators, provided that they point to elements of the same array. Example: int a[10], *p, *q; p = &a[5]; q = &a[3]; if (p < q) /* false */
Using a Pointer to Step Through an Array A pointer can be used to step through an array: #define N 10 int a[n], sum, *p; sum = 0; for (p = &a[0]; p < &a[n]; p++) sum += *p; At the end of the first iteration:
Using a Pointer to Step Through an Array At the end of the second iteration: At the end of the third iteration:
Using an Array Name as a Pointer Arrays and pointers are related in the following way: The name of an array can be used as a pointer to the first element in the array. The first element of an array a can be accessed by using a as a pointer: int a[10]; *a = 0; /* stores 0 in a[0] */ The second element of a can be accessed through a + 1: *(a+1) = 1; /* stores 1 in a[1] */
Using an Array Name as a Pointer In general, the expression a+i is another way to write &a[i]. Using this knowledge, we can simplify our arraysumming loop: #define N 100 int a[n], sum, *p; sum = 0; for (p = a; p < a + N; p++) sum += *p;
Array Arguments Pass array to the function int find_largest(const int a[], int n) { } Because of the relationship between arrays and pointers, an array parameter may be declared as a pointer instead: void store_zeroes(int *a, int n) { }
Using a Pointer as an Array Name When a pointer points to an array, it can be used in place of the array s name: #define N 100 int a[n], i, sum, *p; p = a; sum = 0; for (i = 0; i < N; i++) sum += p[i];
Declaring Structures A structure (aggregate) is a collection of one or more components (members), which may be of different types. A structure is a derived data type. Members of the same structure type must have unique names, but two different structure types may contain members of the same name without conflict. Each structure definition must end with a semicolon. Declaring structure variables can be done as follows: struct { char name[25]; int id, age; char sex; } s1, s2;
Declaring Structures Member names don t conflict with any other names in a program. Structure variables may be initialized: struct { char name[25]; int id, age; char sex; } s1 = { "Smith, John", 2813, 25, 'M'}, s2 = { "Smith, Mary", 4692, 23, 'F'};
Structure Tags A structure can be given a name (a structure tag) for later use: struct student { char name[25]; int id, age; char sex; }; struct student s1, s2; The two declarations can be combined if desired, with the same effect: struct student { char name[25]; int id, age; char sex; } s1, s2;
Declaring Structures A structure cannot contain an instance of itself. A pointer to struct employee, however, may be included. struct employee { char firstname[20]; char lastname[20]; unsigned int age; char gender; double hourlysalary; struct employee person; // ERROR struct employee *eptr; // pointer }; self-referential structure
Structure Tags Structure definitions do not reserve any space in memory; rather, each definition creates a new data type that s used to define variables. Structure variables are defined like variables of other types. struct card acard, deck[52], *cardptr; struct card { char *face; char *suit; } acard, deck[52], *cardptr;
Structure Tags The structure tag name is optional. If a structure definition does not contain a structure tag name, variables of the structure type may be declared only in the structure definition not in a separate declaration. struct { char name[25]; int id, age; char sex; } s1, s2;
Initializing Structures Structures can be initialized using initializer lists as with arrays. To initialize a structure, follow the variable name in the definition with an equals sign and a braceenclosed, comma-separated list of initializers. struct card { char *face; char *suit; }; struct card acard = {"Three", "Hearts"};
Accessing Structure Members struct student { char name[25]; int id, age; char sex; } s; strcpy(s.name, "Doe, John"); s.id = 18193; s.age = 18; s.sex = 'M'; struct student class[30]; strcpy(class[12].name, "Doe, John"); class[12].id = 18193; class[12].age = 18; class[12].sex = 'M';
Accessing Structure Members Two operators are used to access members of structures: the structure member operator (.) also called the dot operator and the structure pointer operator (->) also called the arrow operator. The structure member operator accesses a structure member via the structure variable name. For example, to print member suit of structure variable acard, use the statement printf("%s", acard.suit); // displays Hearts
Accessing Structure Members The expression cardptr->suit is equivalent to (*cardptr).suit, which dereferences the pointer and accesses the member suit using the structure member operator. The parentheses are needed here because the structure member operator (.) has a higher precedence than the pointer dereferencing operator (*). The structure pointer operator and structure member operator, along with parentheses (for calling functions) and brackets ([]) used for array subscripting, have the highest operator precedence and associate from left to right.
An Example //structure member operator and pointer operator #include <stdio.h>//card structure definition struct card { char *face; // define pointer face char *suit; // define pointer suit }; int main(){ struct card acard; //define one struct card variable // place strings into acard acard.face = "Ace"; acard.suit = "Spades"; printf("%s%s%s\n",acard.face, " of ", acard.suit); struct card *cardptr = &acard; // assign address of acard to cardptr printf("%s%s%s\n",cardptr->face, " of ", cardptr->suit); printf("%s%s%s\n",(*cardptr).face, " of ", (*cardptr).suit); }
typedef The keyword typedef provides a mechanism for creating synonyms (or aliases) for previously defined data types. Names for structure types are often defined with typedef to create shorter type names. C programmers often use typedef to define a structure type, so a structure tag is not required. typedef struct { char name[25]; int id, age; char sex; } Student; Student s1, s2; typedef struct card Card; or typedef struct { char *face; char *suit; } Card; Card deck[52];