1 character pointer
A character pointer is a pointer to a character. The type of the pointer is char *;
Let's look at a usage: point to a character
int main() { char ch = 'a'; char *pc = &ch; return 0; }
Analysis: pc is a pointer to the variable char of type char;
Another use is to use a character pointer to point to a string constant.
int main() { char* pstr = "hello world.";//Did you put a string into the pstr pointer variable? printf("%s\n", pstr); //Print as string content. Note that here is the pointer pstr; return 0; }
There is a question above, whether to "hello world." Put in pointer variable pstr?
A: No, you can't put it even if you want. pstr is a pointer, 32 is a machine, four bytes, and hello world This string has already exceeded four bytes.
It's actually hello world Put the first address of the string into the pointer variable pstr, and then the pointer variable pstr can find the first address of the string. When printing, it will print along the first address until the end.
But the pointer above is not written perfectly. We know "hello world." Is a constant string. The constant string is stored in the constant area. This constant string cannot be modified. Once you modify the character of the string through * pstr, the compiler will report an error.
The debugging results are as follows:
So we have a way to write it
char* pstr = "hello world."; Amend to read: const char* pstr = "hello world."; Add one const If you want to modify it, you can report an error at the compilation stage, so as not to report an error at runtime.
Let's take a look at an interview question: help you understand character pointers
int main() { char str1[] = "hello world."; char str2[] = "hello world."; char *str3 = "hello world."; char *str4 = "hello world."; if (str1 == str2) printf("str1 and str2 are same\n"); else printf("str1 and str2 are not same\n"); if (str3 == str4) printf("str3 and str4 are same\n"); else printf("str3 and str4 are not same\n"); return 0; }
Test results:
The result is easy to analyze: the pointers str3 and str4 point to the same memory, so str3 == str4; Will be established;
The array names str1 and str2 point to different memories. Although their values are the same, their address spaces are different, so str1 and str2 are different.
The reason is simple: using a character pointer will point to the address of the constant area where the string is located, while using an array name will only copy a copy of the string to the array for storage. Obviously, the stack space should be opened up when copying. Obviously, the address is different for the array name.
2 pointer array and array pointer
Many people confuse these two nouns. In fact, there is a way to remember them
Pointer array: array is behind, so pointer array is an array, and pointers are stored in the array;
Array pointer: the pointer is behind, so the array pointer is a pointer, a pointer to the array;
1) Pointer array
Pointer array int a = 10; int b = 20; int c = 30; int *arr[3] = {&a,&b,&c};
Pointer array is an array, and the elements in the array are pointers, that is, addresses;
Then the element I want to access the ARR array is arr [i]; For example, getting arr[0] is & a; That's the address of a. I want to get it
For the value of a, you need to dereference * arr[i]; For example: * arr[0], this is the value of a;
Therefore, there is a printing method to get the value of the variable address in the pointer array
int main() { int a = 10; int b = 20; int c = 30; int *arr[3] = { &a, &b, &c }; for (int i = 0; i < 3; i++) { printf("%d ", *(arr[i])); //arr[i] represents an array element, which is an address. The variable value is obtained by dereferencing the address. } return 0; }
There is another usage, look:
int main() { int arr1[] = { 1, 2, 3, 4, 5 }; int arr2[] = { 2, 3, 4, 5, 6 }; int arr3[] = { 3, 4, 5, 6, 7 }; int *parr[] = { arr1, arr2, arr3 }; return 0; }
Analyze: * this parr; First, parr is an array, each element of the array is int, and each element is the first address of other arrays** Draw the memory layout, which is roughly as follows.
If I want to access the value of the array through the array pointer parr, how do I access it?
First, we get the value pointed to by the pointer until we dereference the pointer, so * parr== arr1; However, arr1 is still an address. Let's dereference it, that is * (* parr) == arr1[0]; If you get the element of arr1[0], how do you get the element of arr1[1]? We can get arr[1] through * (arr1 +1), that is, we can also get arr1[1] through * (* parr+ 1);
And so on:
int main() { int arr1[] = { 1, 2, 3, 4, 5 }; int arr2[] = { 2, 3, 4, 5, 6 }; int arr3[] = { 3, 4, 5, 6, 7 }; int *parr[] = { arr1, arr2, arr3 }; for (int i = 0; i < 3; i++) { for (int j = 0; j < 5; j++) { printf("%d ", *(*(parr + i) + j)); // *(parr+i) =parr[i]; //*(parr[i] + j) = parr[i][j]; } printf("\n"); } return 0; }
This is similar to a two-dimensional array.
2) Array pointer
Array pointer is a pointer, pointing to an array;
Initialization of array pointer:
int arr[3] = {0}; int (*p)[3] = &arr; //Array pointer
How is this defined? Or how? Did I mention a method above (outlined in the first article):
I think so:
- First, if you want to write the array pointer, you should know that you need to write p to the left of the * equal sign, that is, the shape of * P =;
- Secondly, the type of your array (remove the array name and the rest is the type of the array): int [3];
- Then * p =; Add int[3] to the left of the asterisk; That is, int[3] * p =;
- Finally, write & arr to the right of the equal sign, that is, int [3] * P = & arr;
- The last is not finished yet. You need to adjust the position, that is, adjust int [3] * P = & arr to int (* P) [3] = & arr;
- This is the process of writing array pointers.
When we read this code, that is, int (* P) [3] = & arr, we should read it as follows:
First, p is a pointer to the array. The array has three elements, and the type of each element is int
For example: please write out the array pointer char* arr[5] pointing to the array;
Analysis: firstly, the array pointer is a pointer, so the left of the equal sign = write (* p) first. Secondly, look at the type of the array, which is char* [5], and then write char * (* p) [5] on the left of the equal sign =; finally, the writing format: char * (* p) [5] = & arr;
3) Common usage of array pointers
- Used with two-dimensional arrays;
Traversal of ordinary two-dimensional array
# include<stdio.h> int main() { int arr[3][4] = { { 1, 2, 3, 4 }, { 2, 3, 4, 5 }, { 3, 4, 5, 6 } }; for (int i = 0; i < 3; i++) { for (int j = 0; j < 4; j++) { printf("%d ", arr[i][j]); } printf("\n"); } return 0; }
result:
Traversing a two-dimensional array with an array pointer
void print(int (*p)[4], int x, int y) { for (int i = 0; i < x; i++) { for (int j = 0; j < y; j++) { printf("%d ", *(*(p + i) + j) ); }//*(*(p + i) + j) == p[i][j]; printf("\n"); } } # include<stdio.h> int main() { int arr[3][4] = { { 1, 2, 3, 4 }, { 2, 3, 4, 5 }, { 3, 4, 5, 6 } }; print(arr, 3, 4);//The array name is the address of the first element, return 0; }
First, we know that the array name is the address of the first element. In a two-dimensional array, we regard it as a one-dimensional array; How to understand?
Then arr means & arr [0] [0], then arr + 1; Represents the address of arr[1][0], then * (arr + 1) represents the element value of arr[1][0], and * (* (arr + 1) + 1) represents the element value of arr[1][1]
Then the array pointer, the pointer to the array, int (*p)[4] = arr; It can be understood as follows: * indicates that p is an array pointer. The array pointed to by p has four elements, and the type of each element is int;
3 reading examples of complex types combined with pointers and arrays
int arr[5]; analysis: arr Is an array. The array has 5 elements, and the type of each element is int; It can be said that: arr Yes, it contains five int Array of type. / int *parr1[10]; analysis: parr1 Is an array. The array has 10 elements, and the type of each element is int*; It can be said that: parr Yes, it contains 10 int*An array of type elements. / int (*parr2)[10]; analysis: parr2 Is a pointer to an array of 10 elements of type int; It can be said that: parr2 Points to 10 int An array of type elements, parr2 Is an array pointer. / int (*parr3[10])[5]; analysis: parr3 Is an array with 10 elements of type int(*)[5],That is, the type of each element is an array pointer, which points to an array containing 5 elements int An array of type elements. You can say so:parr3 Is an array containing 10 array pointer types. The array pointed to by the array pointer contains 5 int Array of type.
4. Design thinking mode of pointer parameter transmission and array parameter transmission
From the designer's point of view, many friends don't know how to design a function. Whether the parameter type is a primary pointer or a secondary pointer. They don't know what parameters the primary pointer can accept and what parameters the secondary pointer can accept.
From the perspective of the caller, when you pass parameters, you don't know whether the passed parameters can change the external arguments, or whether you pass addresses or variables.
Here I will take you to sweep away your doubts about this problem and see if it can help you solve this problem.
First of all, we have to have a cognition. When I am the caller, that is, when I want to call a function, passing in an argument is actually initializing the formal parameter. For example, let me look at the following function.
int Add (int x, int y) { return x+y; } int main() { int a = 10; int b = 10; int ret = 0; ret = Add(a,b); //Call function return 0; } _______________________________________________________ Add(a,b);For this function call, when you pass an argument, it is equivalent to initializing the formal parameter, From the perspective of formal parameters, this is the effect: int x = a,int y = b;For formal parameters, it is equivalent to this way. _______________________________________________________
Why do you say this? Because it helps us understand when designing arguments and formal parameters. Remember how we initialize a variable normally? Whether a variable is initialized by the = equal sign.
In other words, the types on both sides of the = equal sign need to be the same, that is, when I look at the = equal sign on the left, that is, from the perspective of the function designer, this type must be the same as the type on the right of the equal sign. Where does the type on the right of the equal sign come from? From the perspective of our caller, we can get the argument type from the argument in the calling function.
This idea is very important. You need this idea to know how to design function parameters and arguments reasonably.
1) Consider the design of formal parameters from the perspective of function design
So, when I'm a function designer, what do I think when I design the parameter int* x?
I mean, what parameters can I accept?
1. Receive ratio parameter x The address of the lower level variable, i.e int a, a yes int Type, ratio x Type of int*A lower level, after acceptance, is equivalent to: int* x = &a; You find the equal sign = The variable types on the left and right sides are consistent. 2. Receive variables of the same level, i.e int* a; a yes int* Type, and x Type of int* The same level, after acceptance, is equivalent to: int* x = a; You find the equal sign = The variable types on the left and right sides are consistent. 3. Receive a one bit array name. Because a one bit array name is essentially the address of the first element, for int arr[2] = {1,2}; The type of one bit array name is int*,After receiving, it is equivalent to int * x = arr; You find the equal sign=The variable types on the left and right are equal.
Secondly, I wonder if I need to change the arguments passed in from the outside world?
If I need to change the externally passed in argument, I need to receive the ratio parameter x The address of the variable of the lower level of the type; as int a = 10; afferent &a; If I don't need to change the externally passed in argument, I receive a and parameter x Variables of the same type; For example: int *p = &a; afferent p;
Here's a key point: no matter what type of variable you are, such as primary pointer variable, secondary pointer variable or multi-level pointer variable, you can't change the content of the pointer as long as you don't pass the address of the pointer variable; No matter what type of variable you are, as long as you pass in an address, if the variable needs to be a level lower than the formal parameter, you can modify the content of the variable.
2) Thinking about the design of arguments and parameters from the perspective of callers
Naturally, if you are the caller, if you pass the address of the variable, you need to design the function as a formal parameter type one level higher than the variable (that is, one more * asterisk). If you pass the variable, the design function needs a formal parameter type of the same type as the argument;
Do you want to modify the data of arguments through formal parameters? If you want to, you can pass the address of the argument. If you don't want to, you can pass the variable of the argument.
If I want to design a function of commutative number, first of all, you have to know whether you need to modify the argument, pass the address if you need it, and pass the variable if you don't need it. Obviously, the function of exchanging numbers needs to modify the arguments. So when you pass an argument, you pass the address. For example: int a = 10; int b = 20; swap(&a,&b); During parameter design, because the argument needs to be modified, a formal parameter variable one level higher than the argument is used to receive the argument, int swap(int*x,int*y);Formal parameters at this time x and y yes int*Types are all comparison arguments a and b All int Type, one level higher. If you don't need to modify external arguments, you don't need to pass addresses, In the past, no matter whether your argument variable is a pointer or not, the formal parameter is of the same type when it is received.
3) Some parameter passing exercises
Question: whether the parameters of the four statements in the main function are passed successfully.
#include <stdio.h> void test(int arr[])//ok? {} void test(int arr[10])//ok? {} void test(int *arr)//ok? {} void test2(int *arr[20])//ok? {} void test2(int **arr)//ok? {} int main() { int arr[10] = {0}; int *arr2[20] = {0}; test(arr); test2(arr2);
A: for test(arr); From the perspective of the caller, this is an array name, the address of the first element of the array &a [0], and the type is int *. Since the address is passed, it shows that the caller hopes to modify the arguments in the function.
Moreover, since the type of the actual parameter and the formal parameter need to correspond, the formal parameter of my design function must be of type int * or int [] (for arrays, this is a special formal parameter);
Therefore, the first four functions can transfer parameters successfully, except for the fifth function void test2(int **arr) {}, because its formal parameter type is int. from the perspective of function design, it wants to receive parameters**
- Receive the address of a variable one level lower than the formal parameter arr, that is, int* arr,
- Receive an argument of the same level, that is, int** arr;
- Receive the array name of a two-dimensional array, int arr [] [3] = {0}, {0}, {0};
As for whether to change the argument or not, it depends on whether you pass in the address variable or the variable of the same level.
For test2(arr2), from the perspective of the caller, the array name is the address of the first element, and the type of the address of the first element is int * *. Therefore, during design, for the above function, only the fifth function can receive this parameter.
This time I'll share it here. In the next article, we will continue to talk about function pointers, pointer functions, arrays pointing to function pointers, callback functions, etc.