07- c language pointer (C language)

introduction of a pointer

1. Generally, a byte in memory is called a memory unit.
2. In order to access these memory units correctly, each memory unit must be numbered. According to the serial number of a memory unit, the memory unit can be accurately found. The number of a memory unit is also called an address , and this address is usually called a pointer .
3. If a variable is defined in the program, when the program is compiled or run, the system will allocate a memory unit to the variable and determine its memory address (number).
4. The address of the variable is the pointer of the variable, and the variable storing the address of the variable is a pointer variable .
5. The pointer of the memory unit and the content of the memory unit are two different concepts. A popular example can be used to illustrate the relationship between them. When we go to the bank to deposit and withdraw, the bank staff will find our deposit slip according to our account number, and after finding it, write the amount of deposit and withdrawal on the deposit slip. Here, the account number is the pointer of the certificate of deposit, and the deposit amount is the content of the certificate of deposit. For a memory unit, the address of the unit is the pointer, and the data stored in it is the content of the unit.

Definition and use of two pointer variables

2.1 Pointer variable definition syntax

Data type  *pointer variable name , note: 1. The data type is all data types
supported by C language . 2. The pointer variable name follows the naming rules of C language variables .

Example:

int *p; //定义了一个指针变量p,简称指针p,p是变量, int *是类型
char* p2;

We also consider pointers to be a data type .

2.2 Assignment of pointer variables

1) The value of the pointer variable means that the pointer points to the memory space whose first address is this value .

2) Pointer variable assignment is the address of other variables: &: take address operator .

//指针变量 = &变量名;
&:取地址运算符
int a = 10;
int *p = &a;

3) The memory space pointed to by the pointer variable operation
can be accessed and modified through the pointer variable in the pointed memory space .

*:指针运算符(或称“间接访问” 运算)。
int a = 10;
int *p;
p = &a;
printf("*p: %d\n", *p);
*p = 100;
printf("*p: %d\n", *p);

4) The pointer variable is the same as the ordinary variable, if it is not initialized after definition, the value of the pointer variable is uncertain .

5) Wild pointer
Because the value of the pointer variable is uncertain, we call this pointer "wild pointer".
Harm of wild pointers: Because the space pointed to by the pointer is uncertain, the pointer may operate to an illegal memory space, causing the program to crash. 

int a = 100;
int *p;
*p = 1000;
/*因为p没有初始化/赋值,所以p的值是不确定的,如果此时p的值恰好等于a的地址(p == &a), 那么*p=1000将a的值修改为如果p的值恰好是内存上一块只读的内存空间,*p = 1000将导致程序异常退出,你可能会看到程序运行报错(段错误/核心内容*/

6) Null pointer
In order to mark that the pointer variable does not point to any variable (free and available), in C language, NULL can be assigned to this pointer, thus marking this pointer as a null pointer.

int *p = NULL;

NULL is a macro constant with value 0:

#define NULL ((void *)0)

Note: The role of the null pointer is to prevent the pointer variable from becoming a wild pointer . If you use * to access the memory space pointed to by the null pointer, the program will also report an error.

7) Written test questions: Embedded systems are often characterized by requiring programmers to access a specific memory location . In a project, it is required to set the value of an integer variable whose absolute address is 0x67a9 to 0xaa66

//方法1:
int *ptr;
ptr = (int *)0x67a9; //在内存地址编号的前面加上(int *)将地址编号这个无符号整型数据强制转换为
//(int*)指针类型,这样赋值符号左值和右值的数据类型一致
*ptr = 0xaa66;
//方法2:
*(int *)(0x67a9) = 0xaa55;

Note: In actual work, we generally rarely assign a certain memory address to a pointer variable , because programmers generally do not know which memory address is available! ! !

2.3 Differences between different types of pointer variables

1. What are the similarities between int *p1 and char *p2?

int x = 100;
int *p1 = &x;
char y = 'A';
char *p2 = &y;

Same point:

  • are pointer variables
  • are used to store a memory address number
  • The memory space occupied is the same
int *p1;
char *p2;
printf("%d %d\n", sizeof(p1), sizeof(p2));

We found that the memory space occupied by p1 and p2 is 4/8, the result is 4 on the 32-bit machine, and the result is 8 on the 64-bit machine.
think:

Why is the memory space occupied by pointer variables 4 or 8 bytes?
Because the pointer variable holds the number of a memory address!
The maximum value of the memory address number of a 32-bit machine is 2^32-1, which can be stored in a 4-byte variable.
The maximum memory address number of a 64-bit machine is 2^64-1, which can be stored in an 8-byte variable.

2. What is the difference between int *p1 and char *p2?
First of all, we should know: what is stored in memory is only binary.
The reason why there are data types such as int float char is that programmers hope to treat the binary stored in memory as a certain data type.

int x = 65;
printf("%c\n", x);
  • The function of int *p1 is that the pointer variable p1 treats the binary in the memory space it points to as an int type .
  • The function of char *p2 is that the pointer variable p2 treats the binary in the memory space it points to as a char type .

3. The difference between p1++ and p2++

#include <iostream>

int main() {
    int x = 10;
    int *p1 = &x;
    char y = 'A';
    char *p2 = &y;
    printf("p1: %p, p2: %p\n", p1, p2);
    p1++;
    p2++;
    printf("p1: %p, p2: %p\n", p1, p2);
    return 0;
}

The difference between the value of p1 after self-increment and before self-increment is 4 .
The difference between the value of p2 after self-increment and before self-increment is 1 .
Pointer variable + n means that the pointer is not offset by n bytes, but the pointer variable is offset by n data types, for example: p1+3, which
means that the pointer p1 is offset by 3 int type data, and the pointer The value of variable p1 +12 ( 3*sizeof(int) ).

Three Pointers and Arrays

3.1 Array Pointers

1. A variable has an address, and an array contains several elements. Each array element occupies a storage unit in memory, and they all have corresponding addresses. The so-called array pointer refers to the starting address of the array .
2. The array name indicates the first address of the array, so the array name is also a pointer .
3. Access the elements in the array through the array name.

int ch[] = {1,2,3,4};
//假如我们想访问ch中的第3个元素:ch[3] == 4
//我们也可以通过指针法引用数组中的元素:比如 *(ch + 3)
//那么,如果想访问第n个元素呢?
*(ch + n) 注意:n<=sizeof(ch)/sizeof(ch[0])-1

4. Exercise: If there is an array int a[4], write code to achieve the following functions:

  • Assign a value to each element of the array a by entering a number from the keyboard
  • Print out the address of each element in the array a
  • Print the value of each element in the array a by pointer method
#include <iostream>

int main() {
    int a[4];
    int i;
    for (i = 0; i < 4; i++)
        scanf("%d", &a[i]);
    for (i = 0; i < 4; i++) {
        printf("%p %d\\n", &a[i], *(a+i));
    }
    }

5. Indirect access to arrays through pointer variables

#include <iostream>

int main() {
    int a[4] = {1,2,3,4};
    int *p;
    p = a;
    *(p + 2) = 100;
    char ch[] = {'a', 'b', 'c'};
    char *p2;
    p2 = ch;
    *(p2+1) = 'A';
    }
#include <iostream>

int main() {
    int ch[] = {1, 2, 3, 4};
    printf("%d\n", ch[4]);
    printf("%p %p\n", &ch[3], &ch[4]);
    //数组名:数组的首地址
    printf("ch: %p\n", ch);
    //数组中的第0个元素的地址:数组的首地址
    printf("&ch[0]: %p\n", &ch[0]);
    printf("%d %d\n", ch[3], *(ch+3));
    int a[4];
    int i;
    for (i = 0; i < 4; i++)
    {
        scanf("%d", &a[i]); //a+i
        getchar();
    }
    //打印数组中每个元素的地址
    for (i = 0; i < 4; i++)
        printf("%p\n", &a[i]);
    //通过指针法将数组a中的每一个元素的值打印出来
    for (i = 0; i < 4; i++)
        printf("%d\n", *(a+i));
    int *p;
    p = a; //指针p指向了数组a

    //指针指向了一个数组,可以将指针当数组看待
    for (i = 0; i < 4; i++)
        printf("%d\n", p[i]); //通过下标发访问数组中的元素
        // printf("%d\n", *(p+i));
    }

6. Array pointer out of bounds

#include <iostream>

int main() {
    int b[4] = {10, 20, 30, 40};
    int a[4];
    a[4] = 100;
    printf("a[4]: %d\n", a[4]);
    printf("b[0]: %d\n", b[0]);
    printf("a: %u, b: %u\n", &a, &b); //打印数组a和b的首地址
    }

3.2 Array of Pointers

1. As the name implies, the pointer array is: an array storing pointers, which is essentially an array, and each element in the array is a pointer 

#include <stdio.h>

int main()
{
    int a = 10, b = 20, c = 30;
    int *p[3];
    p[0] = &a;
    p[1] = &b;
    p[2] = &c;
    return 0;
}

2. Note: int *p[3]; is equivalent to (int *) p[3]; because [] has a higher priority than * and matches p first.
3. Thinking: How to store the names of 10 people in an array?
char *name[10] = {"zhangsan", "lisi", "wangwu", "zhaoliu, "tianqi"}; The first addresses
of 10 string constants are saved in the name array (note: the string constants are not saved but is the first address of the constant).

3.3 The address of the pointer variable

1. When we define a pointer variable , the compiler will allocate a space to store the value of the pointer variable. The allocated memory space must have an address code, so the address code must be the address of the pointer variable. .

#include <stdio.h>

int main()
{
    int a = 10;
    int *p;
    p = &a;
    //将指针变量p的值以及变量a的地址打印出来(结果应该是两者相等)
    printf("p: %p, &a: %p\n", p, &a);
    //打印指针变量p的地址(存储指针变量p的内存空间的首地址)
    printf("&p: %p\n", &p);
    return 0;
}

2. Emphasis: the value of the pointer variable p saves the address 0x300800 of another variable a, and the address of the pointer variable is the first address of the memory space that stores the value of the pointer variable p: 0x3007F8, the value saved in this space is 0x300800 

3.4 Level-1 pointers as formal parameters of functions

1. The formal parameter of the function is an array
If the formal parameter of the function is an array, the definition method of the formal parameter is as follows:

void func(int a[], int n)
{}

We can also define formal parameters as pointer types :
 

void func(int *a, int n)
{}

In actual work we usually use the second method!

2. When calling a function, you need to pass a string, you can design the formal parameter as a char * type

#include <stdio.h>

void func(char *p) //调用函数时将字符串的地址赋值给指针变量p
{
    printf("%c\n", p[0]);   //返回值为 'h'
}
int main()
{
    func("hello");
    return 0;
}

3. When the formal parameter is an array, how to get the length of the array? //sizeof( )

Why are the values ​​of sizeof(a) and sizeof(b) both 8 ? Reason: The compiler treats a and b as pointers
during compilation ! !

4. Note: If the formal parameter of the function is a pointer , the value of the pointer is generally judged first in the function body to determine whether the value of the pointer is NULL

3.5 Secondary pointer

1. Use a pointer variable to save the address of a first-level pointer variable . We call this pointer a second-level pointer
. 2. The definition of a second-level pointer:

  • data type **variable name ;

3. Application of secondary pointer 

void func_1(){
    //二级指针的使用
    int a = 10;
    int *p = &a;
    int **p2 = &p; //二级指针p2保存了一级指针p的地址(p2指向了p )
    int ***p3 = &p2; //三级指针
    //*p2 == p == &a
    printf("%p %p %p\n", *p2, p, &a);  //000000000061FDE4 000000000061FDE4 
    //**p2 == *p == *(&a) == a
    printf("%d %d %d %d\n", **p2, *p, *(&a), a);   //10 10 10 10

    **p2 = 100;
    printf("%d %d %d %d\n", **p2, *p, *(&a), a);  //100 100 100 100
    //*p3 == p2 = &p
    //**p3 == *p2 == p == &a
    //***p3 == **p2 == *p == *(&a) == a
    printf("***p3: %d\n", ***p3);   //***p3: 100
}

3.6 Memory Allocation

1. In actual work, if we need to store multiple data, many students first think of using arrays, but because the length of the array is fixed after definition, it is often not flexible enough .
2. We can first define a pointer variable according to the type of data to be stored , for example: int *p; and then use
the malloc function
to allocate space according to actual needs.

3. malloc function :

#include <stdlib.h>
void *malloc(size_t size);

Function: The malloc function applies for a memory space of size bytes like the system, and returns a pointer, which points to the first address of the allocated memory space, and the requested memory space is on the "heap". The space on the heap needs to be manually applied and released manually ! ! Otherwise it will cause a memory leak.

int *p;
//假如我们需要存储10个int类型的数据
p = (int *)malloc(10*sizeof(int));

Note: The allocated space is 10*sizeof(int), because the space allocated by malloc is in bytes.

int *p;
//通过指针变量p操作一块空间,可以存储4个int数据
//向系统申请 4*sizeof(int)字节的内存空间
p = (int *)malloc(4*sizeof(int)); //在堆上申请了4*sizeof(int)字节的内存空间
//p的值:申请到的堆上的内存空间的首地址 (指针p指向申请到的堆上的空间)
printf("p: %p\n", p);
//通过指针变量p 来操作申请到的堆空间
p[0] = 100;
p[1] = 200;
*(p+2) = 300;
*(p+3) = 400;

4. Memory release: free function 

#include <stdlib.h>
void free(void *ptr);

Function: Release the memory space pointed to by ptr

Note:
The free function does not modify the value of the pointer variable! But after the execution of free is completed, the contents of the original address space pointed to by the pointer are uncertain! !
Question: What exactly does
freeing up space do?
The most important thing is: tell the system that this memory space can be used by others ! ! !

  • The source file where malloc is located: #include <stdlib.h>
  • The source file where strcpy is located: #include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]){
    char *p;
    //malloc分配的空间是在堆上的,需要手动释放
    p = (char *)malloc(10);
    strcpy(p, "hello");
    printf("p所指向的空间的内容: %s\n", p); //结果是hello

    //将p所指向的地址空间的首地址打印出来(就是将指针变量p的值打印出来)
    printf("p的值: %p\n", p);
    free(p);
    //将p所指向的地址空间的首地址打印出来
    printf("p的值: %p\n", p);

    //仔细观察,下面这条打印语句的结果
    printf("p所指向的空间的内容: %s\n", p);  //结果不是hello

    strcpy(p, "world");
    //再仔细观察,下面这条打印语句的结果
    printf("p所指向的空间的内容: %s\n", p);  //结果是world

    return 0;
}

Use skills after the free function is called: 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]){
    char *p;
    //malloc分配的空间是在堆上的,需要手动释放
    p = (char *)malloc(10);
    strcpy(p, "hello");
    
    //释放申请的内容
    free(p);
    p = NULL;
    return 0;
}

5. What if the previously allocated space is not enough?
We can use the realloc function

#include <stdlib.h>
void *realloc(void *ptr, size_t size);

Function: Allocate a new memory space specified by size on the heap, the space size unit is byte, and also copy the content in the space pointed to by ptr to the new memory space, and finally return the new memory space Forehead address .
Sample code: 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char *p;
    p = (char *)malloc(10);
    strcpy(p, "hello"); //向分配的空间中拷贝字符串
    printf("p所指向空间的首地址: %p\n", p);
    printf("p所指向空间的内容: %s\n", p);
    p = (char *)realloc(p, 20); //重新分配新的空间
    printf("p所指向新的空间的首地址: %p\n", p);
    printf("p所指向新的空间的内容: %s\n", p);
    //注意:分配的新的空间的首地址有可能有之前分配的空间首地址一样,也有可能不一样
    strcat(p, " world"); //追加字符串
    printf("p所指向新的空间的内容: %s\n", p);
    return 0;
}

6. Think about a scenario, char *dest, *src; Copy the contents of the address space pointed to by src to the address space pointed to by dest through a function, but suppose we do not know the length of src before calling the function , at this time we need to design the formal parameter of the function as a secondary pointer !

void test2(char **dest, char *src){
    //通过二级指针dest给形参一级指针dest分配内存空间!
    *dest = (char *)malloc(strlen(src) + 1);
    if (NULL == *dest || NULL == src)
        return ;
    strcpy(*dest, src);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void func4(char **dst)
{
    //*dst == p
    *dst = (char *)malloc(10); //在堆上申请了10个字节
    strcpy(*dst, "hello");
}

int main()
{
    char *p; //指针指向某个函数调用结束后 在函数体中申请的堆空间的首地址
    /*
    * 既然我希望让p指向一块堆空间,其实就是希望对p进行赋值,赋值为在函数中申请的堆空间的首地址
    * 如何在函数中对p进行赋值呢?必须在调用函数的时候传递p的地址!!!!
    * */
    func4(&p);
    printf("%s\n", p);
    free(p);
    return 0;
}

Guess you like

Origin blog.csdn.net/March_A/article/details/131333982