<C Language> Pointer (Part 1)

1. What is a pointer?

A pointer (Pointer) is a special variable type that stores a memory address. A pointer can be thought of as a variable that stores the address of another variable. Through pointers, data in memory can be directly accessed and modified.

Pointers provide a way to access memory indirectly, so that memory resources can be effectively manipulated and managed in programs.

  1. A pointer is the number of the smallest unit in memory, that is, the address
  2. The pointer in the spoken language usually refers to the pointer variable, which is a variable used to store the memory address

We can use & (address operator) to take out the actual address of the variable's memory, and store the address in a variable, which is a pointer variable

#include <stdio.h>

int main() {
    
    
    int a = 10;  //在内存中开辟一块空间
    int *pa = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。
                 //a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在pa变中,pa就是一个之指针变量。
    *pa = 20;    //解引用操作符(间接访问操作符)
    printf("%d\n", a);   //20
    //char * pc = &ch;

    //printf("%d\n", sizeof(pa));
    //printf("%d\n", sizeof(pc));

    //printf("%p\n",  &a);
    return 0;
}

Summarize:

A pointer variable is a variable used to store an address. (The value stored in the pointer is treated as an address).

The question here is:

  • How big is a small unit?
  • (1 byte) How is it addressed?

After careful calculation and weighing, we found that it is more appropriate to assign a byte to a corresponding address.

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-Pe2fQr6z-1688483690225) (C:\Users\TaeYeon\AppData\Roaming\Typora\typora-user-images\ image-20230630220338283.png)]

For a 32-bit machine, assuming that there are 32 address lines, then assuming that each address line generates a high level (high voltage) and a low level (low voltage) when addressing is (1 or 0); then 32 The address generated by the address line will then be:

00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000001

11111111 11111111 11111111 11111111

There are 2 to 32 addresses here.

Each address identifies a byte, then we can give (2^32Byte == 2^32/1024KB == 2 32/1024/1024MB == 2 32/1024/1024/1024GB == 4GB) 4G space for addressing.

Here we understand:

  • On a 32-bit machine, the address is a binary sequence composed of 32 0s or 1s, and the address must be stored in 4 bytes, so the size of a pointer variable should be 4 bytes.
  • Then if on a 64-bit machine, if there are 64 address lines, the size of a pointer variable is 8 bytes to store an address.

Summarize:

Pointer variables are used to store addresses, which uniquely identify a memory unit .

The pointer size is 4 bytes on 32-bit platforms and 8 bytes on 64-bit platforms.

int main()
{
    
    
	int* pa;
	char* pc;
	float* pf;

	printf("%d\n", sizeof(pa));  //4/8
	printf("%d\n", sizeof(pc));  //4/8
	printf("%d\n", sizeof(pf));  //4/8

	return 0;
}

2. Pointers and pointer types

Here we are discussing: the type of pointer

We all know that variables have different types, integer, floating point, etc. Does the pointer have a type? To be precise: yes.

When there is code like this:

int num = 10;
p = &num;

To &numsave (the address of num) into p, we know that p is a pointer variable, so what is its type? We give the corresponding type to the pointer variable.

char  *pc = NULL;
int   *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL;

As you can see here, the definition of the pointer is: type + *.

actually:

char*The type pointer is to store charthe address of the type variable.

short*The type pointer is to store shortthe address of the type variable.

int*The type pointer is to store intthe address of the type variable.

What is the meaning of the pointer type?

2.1 pointer ± integer

Addition and subtraction operations can be performed on pointers to move the location of the pointer in memory. This operation of pointers and integers is called pointer arithmetic.

When a pointer is added to an integer, the pointer is offset by the specified integer value. The offset is calculated by multiplying the integer value by the size of the type pointed to by the pointer.

#include <stdio.h>
int main() {
    
    
    int a = 0x11223344;
    int *pa = &a;
    char *pc = (char *) &a;

    printf("pa=%p\n", pa);//pa=000000000061FE0C
    printf("pc=%p\n", pc);//pc=000000000061FE0C

    printf("pa+1=%p\n", pa - 1);//pa+1=000000000061FE08 地址从0C到08 -4
    printf("pc+1=%p\n", pc - 1);//pc+1=000000000061FE0B 地址从0C到0B -1

    return 0;
}

Summary : The type of pointer determines how much (distance) the pointer takes one step forward or backward.

2.2 Dereferencing of pointers

Dereferencing a pointer is to access the value stored in the memory location it points to through the pointer variable. Dereference operations are implemented using the asterisk (*) operator.

When dereferencing a pointer, you can access the value at the memory location pointed to by the pointer by placing an asterisk (*) in front of the pointer variable.

#include <stdio.h>
int main() {
    
    
    int arr[10] = {
    
    0};
    int *p = arr;//数组名就是数组首元素的地址arr->&arr[0];

    int i = 0;
    for (i = 0; i < 10; i++) {
    
    
        *(p + i) = i + 1;
    }

    for (i = 0; i < 10; i++) {
    
    
        printf("%d ", *(p + i));//1 2 3 4 5 6 7 8 9 10
    }


    for (i = 0; i < 10; i++) {
    
    
        //*(p + i) = i + 1等价于以下两行
        *p = i + 1;
        p++;
    }

    return 0;
}

Summarize:

The type of the pointer determines how much authority (how many bytes can be manipulated) when dereferencing the pointer.

For example: char*the dereference of the pointer of can only access one byte, and the int*dereference of the pointer of can access four bytes.

3. Wild Pointer

A wild pointer is a pointer to a memory location that has been released or is invalid. When the memory pointed to by the pointer is freed or invalidated, the pointer still retains the original address, but accessing the pointer at this time may cause undefined behavior.

The wild pointer is the position pointed by the pointer is unknown (random, incorrect, not clearly limited)

3.1 Causes of wild pointers

1. The pointer is not initialized

#include <stdio.h>
int main() {
    
    
    int *p;//局部变量指针未初始化,默认为随机值
    *p = 20;
    return 0;
}

2. Pointer out-of-bounds access

#include <stdio.h>
int main() {
    
    
    int arr[10] = {
    
    0};
    int *p = arr;
    int i = 0;
    for (i = 0; i <= 11; i++) {
    
    
        //当指针指向的范围超出数组arr的范围时,p就是野指针
        *(p++) = i;
    }
    return 0;
}

3. Release the space pointed to by the pointer

After freeing freememory using a dynamic memory allocation function such asfree

3.2 How to avoid wild pointers

#include <stdio.h>
int main() {
    
    
    int a = 10;
    int *pa = &a;//明确初始化

    //NULL - 0,就是初始化指针的
    int *p = NULL;


    return 0;
}

1. Pointer initialization

2. Beware of pointer out of bounds

3. The pointer points to the space to release, and set NULL in time

//返回局部变量指针
#include <stdio.h>
int *test() {
    
    
    int num = 100;
    return &num;
}

int main() {
    
    
    int *p = test();
    *p = 200;

    return 0;
}

There is a problem in this code that returns a pointer to a local variable &num. This will cause the memory space occupied by the variable to be released test()after the function is executed , but the pointer pointing to it still retains the address, thus forming a wild pointer.nump

4. Avoid returning the address of a local variable

#include <stdio.h>
int main() {
    
    
    int a = 10;
    int *p = NULL;
    //检查有效性
    if (p != NULL) {
    
    
        printf("%d\n", *p);
    }

    return 0;
}

5. Check the validity of the pointer before using it

4. Pointer arithmetic

4.1 Pointer ± Integer

When a pointer is added to an integer, the pointer is shifted back by the number of bytes moved by the size of the type pointed to by the pointer . For example, if the pointer points to a intvariable of type, adding 1 will move the pointer backwards sizeof(int) bytes.

Likewise, when a pointer is subtracted from an integer, the pointer is offset forward. The subtraction operation advances the pointer by the specified number of elements, the number of bytes determined by the size of the type pointed to by the pointer.

Example:

#include <stdio.h>

int main() {
    
    
    int numbers[] = {
    
    1, 2, 3, 4, 5};
    int *ptr = numbers;  // 指向数组的第一个元素

    printf("初始指针位置: %p\n", ptr);

    ptr = ptr + 2;  // 向后移动2个int大小的元素
    printf("移动后的指针位置: %p\n", ptr);

    ptr = ptr - 1;  // 向前移动1个int大小的元素
    printf("移动后的指针位置: %p\n", ptr);

    return 0;
}

Output result:

初始指针位置: 000000000061FE00
移动后的指针位置: 000000000061FE08
移动后的指针位置: 000000000061FE04

Notice:

Arithmetic operations on pointers must be performed on the same array, or point to objects of the same type. Otherwise, the result will be undefined.

4.2 Pointer-Pointer

The result of pointer subtraction is the number of elements between the two pointers, not the number of bytes. Specifically, the result of subtracting two pointers will be an integer representing the number of elements between the two pointers, where the size of each element is determined by the size of the type pointed to by the pointer.

Example:

#include <stdio.h>

int main() {
    
    
    int numbers[] = {
    
    1, 2, 3, 4, 5};
    int *ptr1 = &numbers[0];// 指向数组的第一个元素
    int *ptr2 = &numbers[3];// 指向数组的第四个元素

    printf("指针1的位置: %p\n", ptr1);
    printf("指针2的位置: %p\n", ptr2);

    ptrdiff_t diff = ptr2 - ptr1;// 计算指针之间的偏移量
    printf("指针1和指针2之间的偏移量: %td\n", diff);

    return 0;
}

Output result:

指针1的位置: 0x7ffeeef0d030
指针2的位置: 0x7ffeeef0d03c
指针1和指针2之间的偏移量: 3

Notice:

The subtraction operation of two pointers must point to the same array or object of the same type. Otherwise, the result will be undefined. Also, doing a subtraction is pointless if there is no direct or indirect relationship between the two pointers.

int main() {
    
    
    //两个指针相减的前提是:指针指向的同一个数组(同一块连续的空间)
    int arr[10] = {
    
    0};
    printf("%d\n", &arr[9] - &arr[0]);
    printf("%d\n", &arr[0] - &arr[9]);

    int a = 10;
    char c = 'w';
    printf("%d\n", &a - &c); //err 报错

    return 0;
}

4.3 Relational operations on pointers

Relational operations can be performed on pointers to compare the size relationship of pointers.

  • <(less than): The result is true if the address pointed to by the left operand occurs before the address pointed to by the right operand in memory.
  • >(greater than): The result is true if the address pointed to by the left operand occurs in memory after the address pointed to by the right operand.
  • <=(less than or equal to): The result is true if the address pointed to by the left operand occurs in memory before or equal to the address pointed to by the right operand.
  • >=(greater than or equal to): The result is true if the address pointed to by the left operand occurs in memory after or equal to the address pointed to by the right operand.
  • ==(equal): The result is true if both operands point to the same address.
  • !=(not equal): The result is true if the two operands point to different addresses.

These relational operators are generally used to compare the relative positions between pointers, rather than comparing the specific values ​​they point to.

Example:

for (vp = &values[N_VALUES]; vp > &values[0];) {
    
    
    *--vp = 0;
}

Code simplification, this modifies the code as follows:

for (vp = &values[N_VALUES - 1]; vp >= &values[0]; vp--) {
    
    
    *vp = 0;
}

In fact, the task can be successfully completed on most compilers, but we should still avoid writing this way, because the standard does not guarantee that it will work.

standard regulation:

A pointer to an array element is allowed to be compared with a pointer to a memory location after the last element of the array, but not with a pointer to a memory location before the first element.

5. Pointers and arrays

Let's look at an example:

#include <stdio.h>
int main() {
    
    
    int arr[10] = {
    
    1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
    printf("%p\n", arr);
    printf("%p\n", &arr[0]);
    return 0;
}

Output result:

000000000061FDF0
000000000061FDF0

It can be seen that the array name is the same as the address of the first element of the array.

Conclusion: The array name represents the address of the first element of the array.

Then it is possible to write code like this:

int arr[10] = {
    
    1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
int *p = arr;//p存放的是数组首元素的地址

Since the array name can be stored as an address in a pointer, it becomes possible for us to use a pointer to access one.

For example:

#include <stdio.h>
int main() {
    
    
    int arr[] = {
    
    1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
    int *p = arr;//指针存放数组首元素的地址
    int sz = sizeof(arr) / sizeof(arr[0]);
    for (int i = 0; i < sz; i++) {
    
    
        printf("&arr[%d] = %p   <====> p+%d = %p\n", i, &arr[i], i, p + i);
    }
    return 0;
}

Output result:

&arr[0] = 000000000061FDE0   <====> p+0 = 000000000061FDE0
&arr[1] = 000000000061FDE4   <====> p+1 = 000000000061FDE4
&arr[2] = 000000000061FDE8   <====> p+2 = 000000000061FDE8
&arr[3] = 000000000061FDEC   <====> p+3 = 000000000061FDEC
&arr[4] = 000000000061FDF0   <====> p+4 = 000000000061FDF0
&arr[5] = 000000000061FDF4   <====> p+5 = 000000000061FDF4
&arr[6] = 000000000061FDF8   <====> p+6 = 000000000061FDF8
&arr[7] = 000000000061FDFC   <====> p+7 = 000000000061FDFC
&arr[8] = 000000000061FE00   <====> p+8 = 000000000061FE00
&arr[9] = 000000000061FE04   <====> p+9 = 000000000061FE04

So p+iin fact, the calculation is the address arrof the subscript of the array i.

Then we can access the array directly through the pointer.

#include<stdio.h>
int main() {
    
    
    int arr[] = {
    
    1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
    int *p = arr;//指针存放数组首元素的地址
    int sz = sizeof(arr) / sizeof(arr[0]);
    int i = 0;
    for (i = 0; i < sz; i++) {
    
    
        printf("%d ", *(p + i));  //1 2 3 4 5 6 7 8 9 0 
    }
    return 0;
}

Summarize:

  1. Array names as pointers:
    • An array name can be viewed as a pointer to the first element of the array.
    • When an array name is used as a pointer, pointer arithmetic can be performed.
  2. Access array elements using pointers:
    • Array elements can be accessed and manipulated using pointers.
    • A common way to access array elements using pointers is to use the pointer offset operators *and [].
  3. The relationship between pointers and arrays:
    • Array names can be used as pointer constants and cannot be assigned or modified.
    • You can create a pointer variable pointing to an array, and manipulate array elements through the pointer variable.
  4. Passing of pointers and arrays:
    • In a function, an array can be passed through a pointer parameter, so that the contents of the array can be modified inside the function.
    • When an array is passed as a function parameter, what is actually passed is the address of the first element of the array. Formal parameters in a function can be declared as pointer type or array type, both are equivalent.

6. Secondary pointer

Secondary pointers are pointers to pointers . Also known as a pointer to a pointer, it provides indirect access to a pointer.

A pointer variable is also a variable, and a variable has an address. Where is the address of the pointer variable stored? This is the secondary pointer.

insert image description here

For example:

#include <stdio.h>
int main() {
    
    
    int a = 10;   
    int *p = &a;  //p就是指针变量,一级指针变量
    int **pp = &p;//pp就二级指针

    
    **pp = 200;    //*(*pp) = 200;  *pp表示a的地址 再来一个*表示对a地址解引用
    //*p = 20;
    printf("%d\n", a);  //200
 
    return 0;
}

multilevel pointer

The concept of secondary pointers can be extended to multi-level pointers. Multilevel pointers are pointers to pointers to pointers, and so on. For example, a tertiary pointer is a pointer to a secondary pointer.

For example:

#include <stdio.h>
int main() {
    
    
    int a = 10;   
    int *p = &a;  //p就是指针变量,一级指针变量,指向一个变量,是一个变量的地址
    int **pp = &p;  //pp是二级指针,是一个一级指针的地址
    int ***ppp = &pp;  //ppp是一个三级指针,是一个二级指针的地址
    int ****pppp = &ppp;  //pppp是一个四级指针,是一个三级指针的地址
 
    return 0;
}

7. Array of pointers

In the C language, an array of pointers refers to an array whose elements are variables of pointer type. An array of pointers can store pointers to objects of different types.

So is an array of pointers a pointer or an array?

is an array. is an array of pointers.

For example:

int main() {
    
    
    //整型数组-存放整型的数组
    int arr[10];
    //字符数组-存放字符的数组
    char arr2[5];
    //指针数组-存放指针的数组
    int *arr3[5]; //存放整型指针的数组
    char *arr4[6];//存放字符指针的数组

    return 0;
}

For example:

#include <stdio.h>
int main() {
    
    
    int a = 10;
    int b = 20;
    int c = 30;
    int d = 40;
    int e = 50;

    int *arr3[5] = {
    
    &a, &b, &c, &d, &e};//存放整型指针的数组
    int i = 0;
    for (i = 0; i < 5; i++) {
    
    
        printf("%d ", *(arr3[i]));
    }

    return 0;
}

Pointer array usage scenario: use a one-dimensional array to simulate a two-dimensional array

#include<stdio.h>
int main() {
    
    
    //用一维数组模拟一个二维数组
    int arr1[] = {
    
    1, 2, 3, 4, 5};
    int arr2[] = {
    
    2, 3, 4, 5, 6};
    int arr3[] = {
    
    3, 4, 5, 6, 7};
    int arr4[] = {
    
    4, 5, 6, 7, 8};

    int *arr[4] = {
    
    arr1, arr2, arr3, arr4};
    int i = 0;
    for (i = 0; i < 4; i++) {
    
    
        int j = 0;
        for (j = 0; j < 5; j++) {
    
    
            printf("%d ", *(*(arr + i) + j));
        }
        printf("\n");
    }

    //int i = 0;
    //for (i = 0; i < 4; i++)
    //{
    
    
    //	int j = 0;
    //	for (j = 0; j < 5; j++)
    //	{
    
    
    //		printf("%d ", arr[i][j]);
    //	}
    //	printf("\n");
    //}

    return 0;
}

Output result:

1 2 3 4 5 
2 3 4 5 6 
3 4 5 6 7 
4 5 6 7 8 

Supongo que te gusta

Origin blog.csdn.net/ikun66666/article/details/131545270
Recomendado
Clasificación