Tormented by pointers (3)

1. Character pointer variable

We know that character pointers are pointers that store characters, so can character pointers store strings? let’s take a look

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{<!-- -->
char* p = "asdfghjkl";

printf("%c\\
", *p);

return 0;
}

Will it output a string?

As you can see, the string cannot be output, only the character a is output.
So the conclusion is drawn: instead of storing the entire string in the pointer variable p, the address of the first element character a is stored in p.

Since the character pointer stores the address of the first element character when storing a string, is it impossible to print out the entire string using a pointer variable? Let’s take a look at the following code

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{<!-- -->
char* p = "asdfghjkl";

printf("%s\\
", p);
    //Review: The role of %s: output the characters in the string until the null character in the string (the string ends with '\0', this '\0' is the null character)

return 0;
}

The running results are as follows

As you can see, the entire string can be output

Why can the entire string be printed based on just the address of the first element character?
That’s because: the nature of the character pointer pointing to the stringis because the string is stored continuously. In fact, the character pointer still points to the address of the first element “a”, but because the string is in memory It is stored continuously, so when the character pointer points to a, the characters after a in the string can also be accessed.

Next, look at the following code

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{<!-- -->
char* p = "asdfghjkl";

*p = 'f';
printf("%s\\
", p);

return 0;
}

What does this code output?
The answer is nothing is output.
Because “asdfghjkl” is a constant string. Since it is a constant, it cannot be modified. It cannot be modified but if your pointer still needs to modify it, will there be a problem? In order to prevent this problem from occurring, we can usually Add a const, so that *p can be restricted from being modified.

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{<!-- -->
const char* p = "asdfghjkl";

*p = 'f';
printf("%s\\
", p);

return 0;
}

As shown in the figure below (*p cannot be modified):

2. Array pointer

What is an array pointer? An array pointer is a pointer that stores an array. It is a kind of pointer.

2.1 Array pointer variables and their initialization

1. What is an array pointer variable?

An array pointer variable is a pointer that can store an array, a pointer variable that can point to an array

int (*p)[10];

What does this mean?

Disassemble int (*p)[10] one by one

* p: p is the name of an array pointer variable. There is an * in front of it, which means p is a pointer.
[10]: means that the number of elements p points to the array is 10, that is, the number of elements p points to the array
int : means that the element type of the array pointed to by p is an integer, that is, the element type of the array pointed by p

Note: Why can’t it be written as int *p[10], but should be written as int (*p)[10]?

Because: [] has a higher priority than *, then p will be combined with [] first. At this time, p[] is an array, and p is the name of the array. The element type of the array is int * type, which is a storage pointer. The array is called an array pointer.
And int (*p)[10], () has the highest priority at this time, then (*p) means that p is a pointer, (*p) [10]Prove that the number of elements in the array pointed to by p is 10, int (*p)[10] means that p points to an integer array of size 10

2. Initialization of array pointer variables

How should array pointer variables be initialized? As we said before, & amp;arr takes out the address of the entire array, so we only need & amp;arr and then assign it to the array pointer variable.

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{<!-- -->
int arr[10] = {<!-- --> 0 };

int(*p)[10] = & amp;arr;


return 0;
}

Looking through debugging:

As you can see, p stores the address of the entire arr array.

2.2 The essence of two-dimensional array parameter passing

Once you understand array pointers, you can learn the essence of passing parameters in a two-dimensional array.

First, let’s review two-dimensional arrays

2.2.1 Two-dimensional array

Look at the picture first

Each row of a two-dimensional array is a one-dimensional array. We can think of a one-dimensional array as an element of a two-dimensional array, so we can also think that a two-dimensional array is an array, an array that stores one-dimensional arrays.

2.2.2 Address of two-dimensional array

We know that the array name represents the address of the first element, so is arr the address of the first element of the two-dimensional array?
The answer is correct, arr represents the address of the first element. As we just said, a two-dimensional array is an array that stores a one-dimensional array, so arr represents the address of the first element, which is the address of the first row of the one-dimensional array, which stores the address of the one-dimensional array. , we use pointers to store it. Since it is an array, we use array pointers to store it. The type of a one-dimensional array is int [5], so the array pointer type is int (*) [5]. In this way, we get the essence of passing parameters in a two-dimensional array: passing parameters in a two-dimensional array is essentially an address. This address is the address of the one-dimensional array, which is the address of the first element. We can write the two-dimensional array in the form of a pointer. , easier for us to understand

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void test(int(*arr)[5], int row, int col)
{<!-- -->
int i = 0;
int j = 0;
for (i = 0; i < row; i + + )
{<!-- -->
for (j = 0; j < col; j + + )
{<!-- -->
printf("%d", *(*(arr + i) + j));
}
printf("\\
");
}
}
int main()
{<!-- -->
int arr[3][5] = {<!-- --> {<!-- -->1,2,3,4,5}, {<!-- -->2,3,4, 5,6}, {<!-- -->3,4,5,6,7} };
int row = 3;
int col = 5;
\t
test(arr, row, col);

return 0;
}

3. Function pointer

3.1 Function pointer variable

Let’s make an analogy first
An integer pointer is a pointer to an integer and a pointer that stores an integer address.
An array pointer is a pointer to an array and a pointer that stores the address of the array.
So,
A function pointer is a pointer to a function, a pointer that stores the address of the function.

3.1.1 Creation of function pointers

Since we know that function pointers store the address of a function, then to store the address of a function, a function pointer variable must be used. So how should a function pointer variable be created?

Creation of function pointer:

int (*pf) (int x, int y);
int (*pf) (int, int);
  • (*pf): represents function pointer variable
  • int: the return type of the function pointed to by the function pointer
  • (int x, int y): the parameter type and number of parameters of the function pointed to by the function pointer pf
    • The x and y inside can be omitted, you only need to know the parameter type and number of parameters.

The type of function pointer: removing the variable is the type of function pointer

int (*)(int , int)

3.1.2 Initialization of function pointers

We know how function pointers are created, then let’s take a look at how function pointers are initialized.

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int Add(int x, int y)
{<!-- -->
return x + y;
}
int main()
{<!-- -->
int x = 3;
int y = 4;

int (*pf)(int, int) = Add;

int ret = pf(x, y);
int ret2 = (*pf)(x, y);

printf("%d\\
", ret);
printf("%d\\
", ret2);



return 0;
}

Let’s look at this first

int (*pf)(int, int) = Add;

This is the initialization of the function pointer. We can directly pass Add to pf, because the Add function name represents the address of the function.
We can also write like this

int (*pf)(int, int) = & amp;Add;

This way you can also get the address of the function

Then let’s take a look at the results of this code
The running results are as follows:

We can see that the results returned by ret and ret2 are both 7, which means that both usages can call the function through pointers. (*pf)(x,y) will More clearly, we know at a glance that (*pf) is a pointer variable, and we can access the address of the function by dereferencing it. In fact, the compiler can call it as long as it knows the address of the function.

3.1.3 typedef keyword

Usage: used for type renaming, which can simplify complex types

We can simplify the type of function pointers
If we want to rename the above int (*)(int, int) type to pf_t, we can write it like this

typedef int (*pf_t)(int, int);
//Rename int (*)(int, int) to pf_t

Then adapt the above code

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
typedef int (*pf_t)(int, int);
int Add(int x, int y)
{<!-- -->
return x + y;
}
int main()
{<!-- -->
int x = 3;
int y = 4;

pf_t pf = Add;

int ret = pf(x, y);

printf("%d\\
", ret);

return 0;
}

3.2 Function pointer array

3.2.1 Definition of function pointer array

Array of function pointers: an array that stores function pointers

int (*parr[4])(int ,int);
  • Parr is first combined with [], then parr[3] is an array, and the element type of this array is the function pointer type: int(*)(int,int)

3.2.2 Function pointer array initialization

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int Add(int x, int y)
{<!-- -->
return x + y;
}

int Sub(int x, int y)
{<!-- -->
return x - y;
}
int main()
{<!-- -->
int x = 6;
int y = 4;

int(*parr[4])(int, int) = {<!-- --> Add, Sub };



return 0;
}

The type of each element placed in the array is the same, so the element types in this function pointer array must be int(*)(int, int)