[C language in-depth analysis] pointers and arrays (full)


foreword

basic goal

  • Why have pointers?
  • What is the difference between a pointer and a pointer variable?
  • Difference between pointer and array?

1. Pointer

1. Understanding of pointers

  1. Imagine you are in a room in a building like this
    insert image description here
  2. prerequisite
  • All houses have no house number
  • You don't know where you are - the floor
  • The building is airtight and soundproofed
  • You can only stay in the house and cannot move.
  1. Send a message to your X friends - come and play with me!

Question: How did your X friend find you? 1

into computer memory

  1. As a programmer you want to modify a variable.
  2. If: the computer does not know where this variable is?
  3. The computer can only iterate through the search - extremely inefficient!

Therefore: the house number of a building is like the identification of a memory variable—the address, and the address (house number) can greatly improve the efficiency of finding variables (houses)!

Replenish

  • The smallest storage unit generally used by computers - byte
  1. 4GB=212MB=222KB=232 byte
  2. 8bit = 1byte, 1bit stores 0/1
  3. Therefore: to distinguish each byte of 4GB requires at least 32 digits (binary) - 32bit to store, that is, 4 bytes.

Question: Do the addresses have to be stored? 2 Simple understanding: Special processing
insert image description here
is done in the CPU . When the variable in the specified location of the memory transmits information (electrical signal) to the CPU, the CPU will convert the electrical signal into a digital signal (this The address of the variable), and then return to the memory through the address bus .

  • Why have pointers?

2. Pointers and pointer variables

Dimensions of value inquiry

  • Value attribute: the content stored in the variable
  • class attribute: the type of the value
  • Space attribute: whether there is space for storage

Constants and Variables

  • Constants only have value attributes , not space attributes .
  • Variables have value attributes and also have space attributes .

Substitution: The pointer is a constant, the pointer variable is a variable, and the value stored in it is a pointer .
example:

#include<stdio.h>
int main()
{
    
    
	int a = 10;
	int* p = &a;
	
	*p = 9;
	 p = NULL;
	printf("%d\n", a);
	
	*&a = 12;
	//相当于a = 12;
	int b = *p;
	//等于int b = a;
	
	printf("%d\n", a);
	return 0;
}

Code Analysis Diagram:
insert image description here
Therefore:

  • Pointer variables are not exactly equivalent to pointers
  • Pointers are addresses - values
  • Pointer variables are used to store addresses
  • Dereferencing a pointer variable uses its content - address/pointer
  • When a pointer variable (alone) is an lvalue, it uses the space of the pointer variable.
  • Difference between pointer and pointer variable

3. Forced transfer of the pointer

Let's look at an interesting piece of code:

int main()
{
    
    
	int* p = NULL;
	p = (int*)&p;
	*p = (int)p;
	printf("%p %p", (int*)*p, p);
	return 0;
}
  • (int*)&p, take out the address of p (second-level pointer), and force it into a first-level pointer, so that the types on both sides are the same.
  • *p = (int)p, convert the type of p to an integer, and assign it to *p—the type is int, and the types on both sides are the same.
  • %p can only print the value of the pointer type, otherwise a warning will be reported!

Look at the same piece of code again:

#include<stddef.h>
int main()
{
    
    

	float* p = NULL;
	p = (float*)&p;
	*p = (float)p;
	printf("%p %p", (float*)*p, p);
	return 0;
}

in conclusion:Report an error!
insert image description here
This is like:You are already in two worlds with you, and you still lie to yourself knowing that it is impossible. But the results do not deceive themselves.
The pointer essentially stores a 32-digit number (integer family), which cannot be converted into a floating-point number (floating-point family). It is impossible to convert between the two worlds!

  • The pointer type cannot be forced to a floating point number!

4. void pointer

  • Used to receive sibling pointers of any type
  • The void pointer cannot be dereferenced (Vs2019)
  • Usually used in conjunction with forced forwarding
  • Mainly used in general type functions - qsort

5. Null pointer

  • NULL is a macro
  • The header file where it is located - stddef.h .
  • NULL is also defined in the header file correct.h included in the header file stdio.h we usually use
  • #define NULL ((void *)0) - cast 0 to void* type
  • The void* type cannot be dereferenced! ——*(NULL) will directly report an error from the syntax
  • Supplement: *((char*)0)=1; will not report a grammatical error , but the code will crash!

Normal exit:
insert image description here
Abnormal exit:
insert image description here

6. Multi-level pointer

  • Pointer variables also have addresses , so pointer variables can also be modified by their higher-level pointers!
  • Modify the lower-level pointer pointed to by the multi-level pointer or the content pointed to by the lower-level pointer

Read the code:
This code cannot be executed normally! We only need to understand the meaning of each code!
Think about each code:

  1. Is the lvalue or rvalue of the variable being used
  2. modified content

int main()
{
    
    
	int a = 10;
	int* p = &a;
	int** pp = &p;
	p = 100; //1
	*p = 100; //2
	pp = 100; //3
	*pp = 100;//4
	**pp = 100;//5
	return 0;
}
  1. Lvalue, the space of a pointer variable
  2. Rvalue, the content pointed to by the first-level pointer variable, and the space of the integer variable .
  3. lvalue, space for secondary variables
  4. Rvalue, the content pointed to by the secondary pointer variable , the space of the primary pointer variable
  5. Rvalue, the content pointed to by the second-level pointer variable , the content of the first-level pointer variable, and the space of the integer variable

7. Array pointer

  • To store pointers to arrays,
    we first need to know what type of array is?
int main()
{
    
    
	int arr[10] = {
    
     1,2,3,4,5,6,7,8,9,10};
	return 0;
}
  1. Remove the variable name is its type - int[10]
  2. &arr takes out the type of the entire element
  3. Pointer description: its type int[10]
  4. The pointer variable name follows the naming of the array
  5. Without knowing the grammar we should write:int *p[10]
  6. But [ ] has a higher priority than * so it should be enclosed in brackets
  7. So the correct way to write it is:int(*p)[10]

8. Function pointer

illustrate:Usually we only call functions, as if we have never touched function pointers.
Let's start with functions!

#include <stdio.h>
void fun()
{
    
    
	printf("hello\n");
}
int main()
{
    
    
	fun();//这是一个简单的调用
	//这一个语句可以拆分成两部分fun和()
	//fun是函数,()是函数调用操作符
	//那fun呢?
	fun;
	//&fun呢?
	&fun;
	return 0;
}
  • The fun here can be understood as a variable
  • fun is a variable, then you can take the address
  • So how to express the type of &fun?

If we want to describe a pointer type, we must first describe its uniqueness.
The uniqueness of the function:

  • function return type
  • function parameters
    so we can write:
//void/*返回类型*/ ()/*参数*/ *p = &fun;//这样写看起来是正确的,但跟语法还差了一点
//void fun ();//如果把fun看成变量的话,那指针变量的位置也应该出现在fun处
//因此:void *p()= &fun;离目标还差一点——优先级:()的优先级高于*,要说明p为指针得
//先把p与*号集合起来
//所以正确且符合语法的规范
void (*p)()=&fun;

Actually:
fun is equivalent to &fun
Therefore: it is also correct to write

void (*p)()=fun;

What about the type of function pointer?
Remove the variable name is the pointer type.
so the type of this function pointer is:

void (*)()

How to understand:
insert image description here
improve:

(*(void(*)())0))() ;//如何理解此代码

insert image description here
Disassembly code:

  1. (void(*)())0
    This is going to0 value cast to function pointer, the function pointer type mentioned above
  2. will (void(*)())0be treated as a function pointer p
  3. Substitute into the code we want to understand:*(*(void(*)())0))()
  4. Problem conversion understanding: (* p )(), obviously this is a function call.
  5. Conclusion: This is to convert the 0 value into a function pointer, then dereference the function pointer, and call the function at the 0 value!
void(*signal(int,void(*)(int)))(int);//如何理解这样一段代码?

To understand such a piece of code, we must first understand how to express the function declaration of the function pointer as the return value ?
suppose

  • A function (fun) takes no arguments
  • The return type of the function is void(*)(int)

Due to function composition:
insert image description here
Following the general idea we might write:

void(*)(int)fun();
//甚至会写出函数指针当做函数声明
void(*fun)();
  • The function body is a whole - the function body of the function declaration does not carry the implementation code
  • Therefore: the function pointer as the return value shouldPut the function body next to the * sign of the function pointer
  • So it should be written like this: void(*fun());

Then we also need to understand how to represent the function declaration with the function pointer as a parameter ?

  • A function (fun2) with parameters: int and void(*)(int)
  • The return type of the function is void
    as we think it should be written like this:void fun2(int,void(*)(int));
    That's right, that's right
    Finally, we change the return type of fun2 here to: void(*)(int)
    according to the idea of ​​fun above: put the function body on the right side of * and it becomes:
    void(*fun2(int,void(*)(int)))(int);
    the last function name is what we need to understand The functions are exactly the same .

9. A pointer to an array of function pointers

void (*((*p)[3]))() = {
    
     NULL };
  1. inside out
  2. P is first combined with * to indicate that it is a pointer
  3. Then combine it with [3] outside to explain: the pointer stores the array
  4. Then combine with void(*)() to explain: the type in the array is a function pointer
  5. The content pointed to by the function pointer is the return value is void, parameter: none

10. Wild Pointer

  • pointers accessed without permission
  • May or may not be accessible
  • The content of the accessed space may or may not be modified.
  • Wild pointers prevent access and modification to the knowledge of the operating system.

Example
cannot access:

#include<stdio.h>
int main()
{
    
    
	int* p = (int*)1;
	printf("%d", *p);
	return 0;
}

result:
insert image description here

Cannot be modified:

#include<stdio.h>
int main()
{
    
    
	int* p = (int*)1;
	*p = 1;
	return 0;
}

result:
insert image description here

11. Pointer operations

  • The number stored in the pointer is essentially an integer-sized data that can be compared.
  • Pointer data is a 32-bit data greater than or equal to 0
  • Adding 1 to the pointer adds the size of the pointed type
  • The pointer minus the pointer refers to the number of its adjacent elements (premise: the same type and in the array )
#include<stdio.h>
int main()
{
    
    

	int arr[10] = {
    
     0 };
	int* p = arr;
	int* p1 = &arr[9];
	printf("%d\n", p1 - p);

	return 0;
}
  1. p stores the address of the first element
  2. p1 stores the address of the 10th element
  3. There are 9 elements between p1 and p
  4. Therefore: p1-p = 9

Illustration:
insert image description here

2. Array

1. Array parameter passing

  • The parameter passed to the array is the pointer to be reduced to its elements —for example: the parameter passed to the two-dimensional array is the address of the one-dimensional array
  • The dimensionality reduction pointer is used for array parameter passing, which improves the utilization rate of space .
  • Dimensionality reduction into pointers makes the use of [ ] and *() equal, reducing the difficulty of language use.
void test(int arr[])//ok
{
    
    }
void test(int arr[10])//ok
{
    
    }
void test(int arr[9])//ok
{
    
    }
void test(int* arr)//ok
{
    
    }
void test2(int* arr[20])//ok
{
    
    }
void test2(int* arr[0])//ok
{
    
    }
void test2(int** arr)//ok
{
    
    }
int main()
{
    
    

	int arr[10] = {
    
     0 };
	test(arr);

	int* arr2[20] = {
    
     0 };
	test2(arr2);
	return 0;
}
  1. The function parameter int arr[] here is essentially int*arr.
    illustrate:The number in [] is not interpreted by the compiler, so it’s okay if you don’t write it! Write an integer greater than 0.
  2. int arr[10]; the element is int and its pointer is int* so the parameter is int*
  3. int *arr[10]: its element type is int*, so pass the pointer of int*——int**

2. Multidimensional array

  • Arrays are allocated contiguously in memory
  • Therefore: multidimensional arrays can be regarded as one-dimensional arrays in memory.
    Two-dimensional arrays prove:
#include<stdio.h>
int main()
{
    
    
	char a[3][4] = {
    
     0 };
	for (int i = 0; i < 3; i++) 
	{
    
    
		for (int j = 0; j < 4; j++) 
		{
    
    
			printf("a[%d][%d] : %p\n", i, j, &a[i][j]);
		}
	} 
	return 0;
}

insert image description here

  • The elements of a two-dimensional array are one-dimensional arrays, so when passing a two-dimensional array, an array pointer must be used to receive parameters .
  • The array name of the two-dimensional array is used as a function parameter , which means the address of the first element of the two-dimensional array, the address of the first row.
  • function parameter writeIn the form of an array, the column label cannot be omitted!

Three-dimensional array proof:

#include<stdio.h>
int main()
{
    
    
	char a[3][4][5] = {
    
     0 };
	for (int i = 0; i < 3; i++) 
	{
    
    
		for (int j = 0; j < 4; j++) 
		{
    
    
			for (int k = 0; k < 5; k++)
			{
    
    
				printf("a[%d][%d][%d] : %p\n", i, j,k, &a[i][j][k]);
			}
		}
	} 
	return 0;
}

insert image description here

  • The elements of a three-dimensional array are two-dimensional arrays, so when passing a three-dimensional array, a pointer to a two-dimensional array must be used to receive it.
  • The array name of the three-dimensional array is used as a function parameter, which represents the first element of the three-dimensional array, that is, the address of the first two-dimensional array of the three-dimensional array.
  • Function parameters are written as an array, the first parameter can be omitted, and the second and third parameters cannot be omitted.

  1. Search through the rooms one by one . ↩︎

  2. No, the memory will automatically generate the address of the variable according to the location of the variable, and then use it. ↩︎

Guess you like

Origin blog.csdn.net/Shun_Hua/article/details/129892489