C language pointer

Time:2021-6-5

(1) Pointer knowledge forerunner

1. Memory space and memory address

int num=100;
Data in computer is stored in memory, so the essence of reading and writing data is actually reading and writing memory. At present, the only way to read and write memory is through variable name, which is called “direct access” memory.

In a computer, the minimum unit of memory space is bytes. The operating system will number each byte of memory space, and this number is unique in the current program.

Suppose the picture is a row of rooms in a hotel, each room has a player, for example: Room 101 has player 7, room 105 has player 2, and room 113 has player 1.

If you want to find player 2 in this row of rooms, just know that he lives in room 105. Room 101 is equivalent to memory address, room 101 is equivalent to memory space, player 7 is equivalent to data in memory space.

As I said before, to find player number 7, you have to find it by room number. Similarly, in the computer, if you want to read and write the data in the memory space, you can also find the memory space through the memory address, and then read and write.

There are two ways to read and write memory
The first way is to read and write memory through variable names.
A variable is essentially a memory space with a name. The memory is read and written through the variable name, as shown in the figure

The second way is to read and write memory through memory address.
In computer memory, each byte of memory space has a number, which is called memory address. The corresponding memory space can be read and written through this address, as shown in the figure

2. Explore memory

In the previous section, we discussed the relationship between memory space and memory address. In order to better understand the relationship between the two, we will use vs2012’s own tools to make a more vivid analysis.

The test code is as follows:

#include
int main(void)
{
    int num=999;
    printf("%p\n",&num); // Output variable num address
    getchar();
    return 0;
}

[note]
In line 5, & (Shift + 7) is the address character in C language& Num is the address number of the memory space corresponding to the calculation variable num, which is the so-called memory address P means to output the memory address in hexadecimal format.
After writing the above program, let’s explore the memory space step by step through the tool.
Step 1: on line 6 of the test program, click Add breakpoint:
Step 2: run the program, and the console will output hexadecimal address data (it may be different each time),
As shown in the figure:

Step 3: click debug > Window > memory > memory 1 to open the memory window, as shown in the figure

Step 4 input the data output from the console into the address column of the memory 1 window, and then press enter, as shown in the figure:

Step 5 right click in the [memory 1] window, and then select [4-byte integer (4)] and [display with symbol], as shown in the figure:

[description]
Because num is an int type and occupies 4 bytes in a 32-bit system, select 4-byte integer in step 5 and other types of data in turn.

Step 6 check the [memory 1] window to see the integer + 999. In fact, 999 only displays the sign bit + as shown in the figure

analysis:
1. In the whole process above, first line 4 writes integer 999 to memory space through variable name num.
2. In line 5, use & num to calculate the memory address 0019fe50 corresponding to the variable num.
3. Through breakpoint debugging, view the data 999 saved in 0019fe50 address space.
4. After the above analysis, the full memory model of variable num is shown in the figure

5. As you can see, you can access a piece of memory by variable name or memory address.
[debugging skills]
In order to view the memory easily by using memory 1, it is recommended to set the column option to auto, as shown in the figure

3. Pointer variable

As mentioned earlier, the essence of a variable is a memory space with a name. In fact, this memory space not only has a name, but also a number. In 32-bit system, the number is a 4-byte integer. You can get this integer by (& variable name), for example:
int num=10;
printf(“%p\n”,&num); // Output in hexadecimal format
This number is one-to-one corresponding to a memory space, through which the corresponding memory space can be found. Similar to real life, know a person’s home address, you can find his home through the address. In the C language program, this number is called “memory address”, and the corresponding memory space can be found through the memory address.

At present, the only way to get the memory address in the program is: & variable name. Because the memory address obtained in this way is the memory space address corresponding to the variable, and it is obtained through the variable name, it can be called “variable address”. It must be clear here that the variable address is essentially the memory address.

A variable used to hold the memory address is called a pointer variable. In C language program, not only variables have types, but also data have types, such as 1 (integer), 3.14 (floating-point number),’c ‘(character), which need to be saved with matching type variables. Similarly, memory address is also a kind of data, which is pointer type, so pointer type variable is needed to save this kind of data.

4. Pointer variable definition and initialization

The general form of defining pointer variables is as follows:
Type name * variable name;
The type name indicates that the pointer variable can only save the address of the type variable, * indicates that the variable is a pointer variable and can only save the address data, and the variable name is the name of the variable.
For example: int * P_ a;
Int indicates that the pointer variable can only store the address of int type variable, * indicates the variable P_ A is a pointer variable, which can only store address data, P_ A is the name of the pointer variable.

Pointer variables are initialized in the same way as ordinary variables. They can be initialized when a variable is defined, or they can be defined first and then initialized. For example:

int a=10;
int* p_ a=&a; // Defines the int pointer variable P_ a. The address of variable a is assigned to P_ a
perhaps
int a=10;
int*p_ a; // First define the int pointer variable P_ a
p_ a=&a; // Then the address of variable a is assigned to variable P_ a

In C language program, if the address of a variable is assigned to a pointer variable, it is considered that the pointer variable points to a variable

int a=10;
int*p_a=&a;

In the above program, the address of integer variable a is assigned to pointer variable P_ a. I think P_ A points to the variable a, as shown in the figure

As you can see, the integer 10 is stored in the variable a, while the variable P_ The address of variable a is stored in a. It’s a bit like a real-life intermediary. If you want to access data 10, you must first find the pointer variable P_ a. Through the variable p_ Data in a & A, find variable a, and finally access data 10.

5. Reference pointer variable

There are two cases of pointer variable reference
The first refers to pointer variables.

#include
int main(void)
{
    int a=10;
    int b=20;
    int *p1,*p2; // Define pointer variables P1 and P2
    p1=&a; // P1 points to variable a
    p2=p1; // P2 points to variable a. P2 points to the variable P1 currently points to
    printf("&a=%p p1=%p p2=%p\n",&a,p1,p2);
    p1=&b; // P1 points to variable B
    p2=p1; // P2 points to variable B
    printf("&b=%p p1=%p p2=%p\n",&b,p1,p2);
    getchar();
    return 0;
}

The running results are shown in the figure (the running results may be different each time)

The second refers to the variable pointed by the pointer variable.

#include
int main(void)
{ 
    int a=10;
    int* p=&a; // P points to variable a
    printf("a=%d *p=%d\n",a,*p);
    *p=20; // Modify p to point to the data in variable a
    printf("a=%d *p=%d\n",a,*p);
    getchar();
    return 0;
}

The running results are shown in the figure

Easy to mix: when defining a variable, * is placed in front of the variable, and the table name variable is a pointer type; When using variables, it is used to read and write the value pointed to by pointer variables.
Shorthand:

  1. &Take the variable address;
  2. *When defined, it means that it is a pointer variable* When used, represents the value of a read-write pointer variable.

6. Pointer variable as function parameter

In C language, function parameters can be not only character type, integer type, floating point type, etc., but also pointer type, which is used to pass variable address to function parameters.
The main purpose is to modify the value of external variables inside the function.
Here are two examples to illustrate the usage of pointer variables as function parameters.

In case 1, the value of external variable is changed inside the function

void test1(int* p)
{
    Printf ("read the value pointed to by the pointer in the function::% D / N", * P));
    *p=*p+1;
}
int main(void)
{
    int num=999;
    test1(&num);
    Printf ("read value of variable out of function::% D / N", Num));
    getchar();
    return 0;
}

Case 2: encapsulating functions, exchanging the values of two integer variables.

#include
void swap(int* p_a,int* p_b)
{
    int temp=*p_a;
    *p_a=*p_b;
    *p_b=temp;
}
int main(void)
{
    int a=10;
    int b=20;
    swap(&a,&b);
    Printf ("after exchange, a = D, B = D, n", a, b));
    getchar();
    return 0;
}

7. Scanf get input data function

Scanf function prototype:
int scanf(const char * _Format, ...)
Header file:
#include
Parameter list:
_ Format: format control string, which is the same as the format control function in printf function.
...: address list, consisting of several addresses.
Function:
Get the data input by the user key, and write it to the variable, or array in the specified format.
#include 
int main(void)
{
    int a;
    scanf("%d",&a); // Enter an integer from the keyboard and write it into the variable a
    printf("%d",a); // The value of output variable a
    getchar(); // Receive the Enter key pressed when using scanf
    getchar(); // The program pauses, waiting for user input
    return 0;
}
int main(void)
{
    int i,j;
    Printf ("please enter the first number): (n));
    scanf("%d",&i);
    Printf ("please enter the second number): (n));
    scanf("%d",&j);
    printf("%d\n",i+j);
    getchar();
    getchar();
    return 0;
}

Scanf can also receive multiple input data, such as:

#include 
int main(void)
{
    int a,b;
    scanf("%d %d",&a,&b); // Get the input data and write it to variables A and B
    printf("a=%d\n",a); // Output variable a
    printf("b=%d",b); // Output variable b
    getchar();
    getchar();
    return 0;
}

Input: 1 2 (1 and 2 are separated by spaces), and then press enter. The running result is as follows:

The data type must not be used incorrectly in scanf. The float type must use% F, the double type must use% LF, and the int type must use% d. if it is used incorrectly, you will find that the result is very strange.

Problems in using scanf
(1) In scanf function, you should pass in the variable address instead of the variable name
int a,b;
scanf(“%d %d”,a,b);
This kind of writing is wrong. We should change “a, B” to “& A, B”.

(2) When getting multiple data from the keyboard, space, enter and tab can be used as the separator between adjacent data. For example:
int a,b;
scanf(“%d %d”,&a,&b);
The first input method:
1 2 // 1 and 2 are separated by spaces
Second input mode:
1 2 // 1 and 2 are separated by tab
Third input mode:
1
two // 1 and 2 are separated by carriage returns

(3) * if there are other characters in the format control string in the scanf function besides the place holder, the same character must be entered in the corresponding position. For example:
int a,b,c;
scanf(“%d,%d,%d”,&a,&b,&c); // Note that% d is separated by “,” in scanf
Input:
1,2,3 (input data must also be separated by “,”)

(4) When using scanf to get a string, you only need to pass in the name of the character array and take the address character & which can be omitted. For example:
char c[10];
scanf(“%s”,c); // It can be omitted&
Input:
hello
Note that when using% s, there should be no spaces in the string, otherwise the behavior is very strange.
Scanf has a lot of strange behaviors and pits, but it’s of little value to study in-depth things, so as long as you know the conventional usage.

(2) Arrays and pointers

Array is essentially a continuous memory space, each element of the array corresponds to an independent memory space, and they all have corresponding addresses. Therefore, since pointer variables can point to variables, they can also point to array elements.

1. First knowledge of array element address

1、 Array element address

In C language, array can be regarded as a set of variables of the same type. Generally speaking, each element in an array has the same type. For example:
Char ch [10] / / the array ch can be regarded as composed of 10 char variables
Int a [10] / / array a can be regarded as composed of 10 int variables
Float f [10] / / array f can be regarded as composed of 10 float variables

Array is essentially a continuous memory space, and array elements can be regarded as a separate memory space. Array is like a row of rooms, and array elements are a separate room. Therefore, each array element also has its own memory address, referred to as the array element address.

You can use pointer variables to save the array element address, for example:
int a[5]={1,2,3,4,5}; // Defines an int array of length 5
int* p_ a; // Defines the pointer variable p to the int variable_ a
p_ A = & A [0] / / assign the address of the 0 th element of a array to the pointer variable P_ a。 It is equivalent to (a [0])
p_ The address of the 0th element of array A is saved in a, which can be considered as pointer variable P_ A points to the 0th element of array a,
As shown in the figure:

2、 Refers to a pointer variable to an array element

Because an array element can be regarded as a separate variable in essence, the way of referring to a pointer variable pointing to an array element is the same as that of referring to a pointer variable pointing to a variable. Just use the * pointer variable name directly.

#include
int main(void)
{
    int i[5]={1,2,3,4,5};
    int*p_i;
    p_i=&i[0];
    printf("i[0]=%d *p_i=%d\n",i[0],*p_i);
    p_i=&i[1];
    printf("i[1]=%d *p_i=%d\n",i[1],*p_i);
    getchar();
    return 0;
}

Similar to the way of accessing variables, the way of accessing elements by array name can be called “direct access”, and the way of accessing elements by array element address can be called “indirect access”.

2. In depth analysis of array element address

In a computer, the smallest unit of memory is bytes, and each byte corresponds to an address. If a variable occupies more than one byte, it will occupy more than one memory address. For example: char type variable with 1 byte corresponds to 1 address, short type variable with 2 bytes corresponds to 2 addresses, int type variable with 4 bytes corresponds to 4 addresses, and so on. Similarly, different types of array elements occupy different memory addresses.

#include
int main(void)
{
    char c[5];
    short s[5];
    int i;
    for (i=0;i<5;i++)
    {
        printf("&c[%d]=%p ", i , &c[i]);
        printf("&s[%d]=%p \n", i ,&s[i]);
    }
    getchar();
    return 0;
}

The running results are shown in the figure

3. Array name and first element address

In C language, the name of array is equivalent to the address of the first element of array.

#include
int main(void)
{
    int num[5];
    printf("%p\n",num); // Output array name
    printf("%p\n",&num[0]); // Output array first element address
    getchar();
    return 0;
}

The running results are shown in the figure

4. Pointer addition and subtraction

A pointer is essentially a memory address. In a 32-bit operating system, a memory address is only a 4-byte integer. Since it is an integer, it can carry out arithmetic operations such as addition, subtraction, multiplication, division, etc. However, it should be noted that in C language, only pointer addition and subtraction are discussed, while multiplication, division and other arithmetic operations are meaningless.

In actual development, pointer addition and subtraction are used for arrays (or continuous memory space). When the pointer variable p points to an array element, P + 1 points to the next array element and P-1 points to the previous array element. Note that the addition and subtraction operations are not “move a byte”, but move a “unit”. For int, a unit is 4 bytes.

#include
int main(void)
{
    int a[3]={1,2,3};
    int* p=&a[0]; // P points to a [0]
    printf("%p %d\n",p,*p); // Output P, the element that P points to
    p=p+1; // P Plus 1
    printf("%p %d\n",p,*p); // Output P, the element that P points to
    getchar();
    return 0;
}

The running results are shown in the figure

The addition and subtraction of pointer is meaningful only by pointer and ordinary integer operation, but the addition of two pointers is meaningless: P = P + n means P points down to N units, P = P-1 means P points up to N units.

Let’s look at pointer subtraction with an example.

#include
int main(void)
{ 
    int a[3]={1,2,3};
    int* p=&a[1]; // P points to a [1]
    printf("%p %d\n",p,*p); // Output P, the element that P points to
    p=p-1; // P minus 1
    printf("%p %d\n",p,*p); // Output P, the element that P points to
    getchar();
    return 0;
}

The running results are shown in the figure

When the pointer variable p points to the array element, P + 1 and P-1 point to the next and previous array element respectively. By analogy, P + I and P-I point to the next I elements and the last I elements respectively.
P + I cannot exceed the last element of the array, and P-I cannot be less than the first element of the array. Otherwise, array out of bounds will occur.

The addition of two pointers is meaningless, and the subtraction of two pointers represents the number of cells with phase difference.
It is also often used to subtract two pointers, such as p2-p1.
P2-p1 makes sense when P1 and P2 both point to elements in the same array. Take the array int a [5] as an example: suppose P2 points to element a [2] and P1 points to element a [0]. When p2-p1 is executed, it does not mean how many bytes are separated, but how many elements are separated between the element pointed by P2 and the element pointed by P1.

Here is an example to understand the subtraction of two pointers.

#include
int main(void)
{
    int a[5]={1,2,3,4,5};
    int* p1=&a[0]; // P1 points to element a [0]
    int* p2=&a[2]; // P2 points to element a [2]
    printf("p1=%p\n",p1); // Output P1
    printf("p2=%p\n",p2); // Output P2
    printf("%d\n",p2-p1); // Output p2-p1
    getchar();
    return 0;
}

The running results are shown in the figure

Conclusion:

  1. The subtraction between two pointers indicates the number of cells with phase difference.
  2. The addition between two pointers is meaningless;
  3. Pointer + ordinary integer indicates that the pointer moves to N units; Pointer – an ordinary integer indicates that the pointer is moved by N units;

5. Array as function parameter

A function parameter can be not only a variable, but also an array. Its function is to pass the address of the first element of the array to the function parameter.

[description]
In C language, when array is used as function parameter, there is no copy mechanism, only address can be passed. It can also be considered that when an array is used as a function parameter, it will degenerate into a pointer.

The following is an example to understand that when an array is a formal parameter, it degenerates into a pointer.

#include
void getSize(int nums[5])//(int *nums)
{
    int size=sizeof(nums);
    printf("size=%d\n",size);
}
int main(void)
{
    int nums[5]={1,2,3,4,5};
    int size=sizeof(nums); // Calculates the total number of bytes in the array nums
    printf("size=%d\n",size);
    getSize(nums);
    getchar();
    return 0;
}

The running results are shown in the figure

It can be seen that the output results of the two times are different. This is because when an array is a function parameter, it degenerates into a pointer.
void getSize(int nums[5])
It degenerates into:
void getSize(int *nums)
In 32-bit system, all pointer variables occupy 4 bytes, so the output of line 5 is 4.

When an array is used as a function parameter, it will degenerate into a pointer, so it is impossible to calculate the size and length of the incoming array in the called function. In order to solve this problem, when an array is specified as a function parameter, the length of the array must be passed in
void getSize(int *nums,int length);
The formal parameter length represents the length of the array nums.

#include
Void show (int * nums, int length) // define the function show
{
    int i;
    for (i=0;i

Conclusion:

  1. Only in the function declared by the array can the number of bytes of the array be calculated by sizeof (array name);
  2. int nums[]={1,5,8,9,666}; int *p=nums; In this case, sizeof (P) = 4, because P is a pointer, why sizeof (nums) can calculate 20, because the compiler treats it specially.
  3. Because the C compiler is relatively low-level, even if the array type void Dy (int data [] is used in the function parameter declaration, it will be degenerated into the pointer type void Dy (int * data). Therefore, when passing the array to the function, the name of the array should be passed, and the number of array elements should be calculated through sizeof in the function declaring the array, Function can’t calculate how many elements there are in the array.

6. * (a + I) is equivalent to a [i]

In C language, the array name is equivalent to the address of the first element of the array. For example: int a [5], a and & A [0] are completely equivalent. It can be considered that a + I is equivalent to & A [i], a + I points to a [i], then * (a + I) is the array element a [i] pointed by a + I. Therefore*(a + I) is equivalent to a [i].

#include
int main(void)
{
    int a[5]={1,2,3,4,5};
    int i;
    int len=sizeof(a)/sizeof(int);
    for (i=0;i

No matter for array name or pointer: * (a + I) is equivalent to a [i]
Except for the difference between sizeof (array name) and sizeof (pointer variable name) when declaring an array, the usage of “array name” and “pointer variable name” is the same.

(3) String and pointer

In C language, string is stored in character array. As mentioned earlier, pointers can point to array elements of numeric type, that is, to array elements of character type. This section describes pointers to elements of a character array.

1. Memory of string

In C language, strings are stored in character arrays. There are two ways to refer to strings

  1. Use character array to store string, refer to string by array name, and refer to character in string by subscript
  2. The character pointer variable is used to point to the string, and the character in the string is referenced by the character pointer variable.

The following code is simple:

#include
int main(void)
{
    char str[]="hello"; // Define character array str
    printf("%s\n",str); // Output STR in% s format
    printf("%c",str[2]); // Output one character in% C format
    getchar();
    return 0;
}

Of course, it can also be used in this way:

#include
int main(void)
{
    char *str="hello";
    printf("%s\n",str);
    printf("%c",str[2]); //*(str+i)
    getchar();
    return 0;
}

Are the two sizeofs the same?

char s1[]="hello";
char *s2="hello";
printf("%d,%d\n",sizeof(s1),sizeof(s2));
//6,4

[description]
It is important to note that a string is referenced either through a character array or through a character pointer. The compiler will automatically add 0 at the end of the string. Next, use the memory tool to see how the string is stored in memory.

Step 1 write the test program

#include
int main(void)
{
    char *str="hello";
    printf("%p\n",str); // Output string address
    getchar();
    return 0;
}

Step 2: add breakpoints in getchar.

Step 3 run the program and record STR pointing to string address.

Step 4: input the string address in [memory 1], and then press enter, as shown in the figure:

[description]
If the effect as shown in the figure is not displayed, you can refer to the following steps to configure and view the memory mode.
Right click any position in the window and select [1 byte integer], [display without symbol], [ANSI text].

You can see that the string is stored in memory according to the ASCII code of the character, and the last bit is 0 as the string end flag.

(4) String handler

String is a very important concept in C language. String processing function is a series of functions that operate on string. Mainly included in the header file, this section will introduce the commonly used string processing functions.

1.strcpy

str:string
cpy:copy
Function prototype:
char *strcpy(char* dest, char *src);
Header file:
#include
Parameter list:
Dest: target character array.
SRC: source string.
Function:
Copy the string pointed to by SRC to the character array pointed to by dest.
Return value:
Returns the memory address that dest points to.
Using strcpy to copy string
#include
#include 
int main(void)
{
    char *src="hello";
    char dest[10]={0};
    strcpy(dest,src);
    printf("%s\n",src);
    printf("%s\n",dest);
    getchar();
    return 0;
}

2.memcpy

mem:memory,cpy:copy
Function prototype:
void *memcpy(void*dest, const void *src, int size);
Header file: # include
Parameter list:
Dest: destination address space
SRC: source address space
Size: number of bytes to copy
Function:
From the start of memory space pointed to by SRC, copy size bytes to memory space pointed to by dest.
Return value:
Returns the destination address that dest points to.
#include
#include 
int main(void)
{
    char* src="helloworld";
    char dest[7]={0};
    memcpy(dest,src,6);
    printf("%s",dest);
    getchar();
    return 0;
}

The difference between strcpy and memcpy: strcpy looks at both the source and the target as string types, so it will encounter a stop of ‘\ 0’; Memcpy will copy as is.

3.strcmp

string compare
For pointer variables, = = compares whether they are the same address.
Function prototype:
int strcmp(char*str1,char*str2);
Header file:
#include
Parameter list:
STR1: String 1
STR2: String 2
Function:
Starting from the first character of STR1 and STR2, compare them one by one (compare the ASCII code of the characters) until different characters or characters appear
Until '\ 0'.
Return value:
(1) The string STR1 is less than STR2 and the return value is negative.
(2) The string STR1 is equal to STR2 and the return value is 0.
(3) The string STR1 is greater than STR2, and the return value is a positive number.

According to ANSI standard, the return value is positive, negative and 0. The exact value depends on different C implementations. For example, some platforms return 1, – 1, and 0.

[description]
String comparison size. Arithmetic operators cannot be used for comparison, for example:
str1>str2、str1==str2、str1

The arithmetic operator is used to compare the address of the first element of the string, not the content of the string.

#include
#include
int main(void)
{
    char *str1="hello";
    char *str2="HELLO";
    int result=strcmp(str1,str2);
    if (result>0)
    {
        Printf ("STR1 is greater than STR2");
    }
    else if(0==result)
    {
        Printf ("STR1 equals STR2");
    }
    else
    {
        Printf ("STR1 is less than STR2");
    }
    getchar();
    return 0;
}

4.stricmp

i: Ignore case, ignore case.
stricmp:string ignore case compare
Function prototype:
int stricmp(char*str1,char*str2);
Header file:
#include
The usage of StrCmp is basically the same as that of stricmp, but the case is ignored for comparison.
#include
#include
int main(void)
{
    char *str1="hello";
    char *str2="Hello";
    int result=stricmp(str1,str2);
    if (result>0)
    {
        Printf ("STR1 is greater than STR2");
    }
    else if(0==result)
    {
        Printf ("STR1 equals STR2");
    }
    else
    {
        Printf ("STR1 is less than STR2");
    }
    getchar();
    return 0;
}