C language summary pointer (continuously updated)

Posted by jackofalltrades on Mon, 13 Dec 2021 03:07:16 +0100

Latest update time: December 2021 twelve
Environment: vs2019, x86 compilation; 64 bit win10
Source code (including games) uploaded to

11, Pointer

11.1 what is the pointer

A pointer is actually an address. First, learn how memory addresses are numbered. Take a 32-bit machine as an example:
32 bits – 32 address lines – physical lines – power on – 1 / 0
Thus, the conversion from electrical signal to digital signal is completed, and the binary sequence composed of 1 and 0 is obtained:

00000000 00000000 00000000 00000000
......
 11111111  11111111   11111111   11111111
A total of 2 ^ 32 addresses can be represented, that is, so many storage units.
One of the storage units occupies one byte.

	int a = 10;//a 4 bytes need to be allocated in memory.
	printf("a Address of:%p\n", &a);//%p is specifically used to print addresses.
	int *pa = &a;//a is 4 bytes. Take the address as the address of the first byte. This address is low.
	// *Note that pa is a pointer variable, and int indicates that the object pointed to by pa is of type int.
	*pa = 20;// *For dereference, * pa is to find a through the address in pa.
	printf("Modify by pointer a Value of:%d\n", *pa);
	++pa;
	printf("Self added address:%p\n",pa);//Self incrementing 4 bytes

	char ch = 'q';
	char *pc = &ch;
	printf("ch Address of:%p\n", pc);
	printf("ch Next address for:%p\n", ++pc);//Self increment by one byte

	//The size of the pointer is the same: the pointer type is used to store the address. How much space the pointer needs depends on how much space the address needs to be stored
	printf("%d\n", sizeof(char*));
	printf("%d\n", sizeof(short*));
	printf("%d\n", sizeof(int*));
	printf("%d\n", sizeof(long*));
	printf("%d\n", sizeof(long long*));
	printf("%d\n", sizeof(float*));
	printf("%d\n", sizeof(double*));

11.2 pointer and pointer type

Meaning of pointer type:
1. Pointer type determines the permission of pointer dereference.

	int a = 0x11223344;
	char *pc = &a;
	*pc = 0;//Since pc is a char pointer, only one byte can be accessed here. Change it to 0
	int *pa = &a;
	*pa = 0;//Since pa is an int pointer, you can access four bytes here and change it to 0

Observe the changes in memory:



2. The pointer type determines how far the pointer can go in one step, that is, the step size.

	int arr[10] = { 0 };
	int* p = arr;
	char* pc = arr;
	printf("%p\n", p);
	printf("%p\n", p + 1);//int type, 4 bytes
	printf("%p\n", pc);
	printf("%p\n", pc + 1);//char type, 1 byte

	int arr[10] = { 0 };
	//int* p = arr;// Skip 4 bytes, that is, access in elements
	char* p = arr;//Byte by byte change
	for (int i = 0; i < 10; i++)
	{
		*(p + i) = 1;
	}


11.3 field pointer

Wild pointer: the position pointed to by the pointer is unknown (random, incorrect and without explicit permission)
Causes of wild pointer:
1. Pointer not initialized:

	int* p;//p is a local variable. If the local variable is not initialized, the default is a random value
	*p = 20;//Illegal access to memory, because the space pointed to by p is random, and p here is a wild pointer

2. Pointer cross-border access:

	int arr[10] = { 0 };
	int* p = arr;
	for (int i = 0; i <= 10; i++)
	{
		*p = i;
		p++;//When i=10, it is out of bounds to access the elements in arr again
	}

3. Space release pointed by pointer:

int* test()
{
	int a = 10;
	return &a;//After the function call, the space of a is released. If you operate this space again, it is actually illegal.
}
	int* p = test();
	*p = 20;

How to avoid wild pointers:
1. To initialize the pointer:

	int* p = NULL;//When you don't know what address p should initialize at present, it is directly initialized to NULL
	int a = 10;
	int* p = &a;//Clearly know the initialization value

2. Be careful to cross the border. C language itself will not check the cross-border behavior;
3. When the space pointed to by the pointer is released, set the pointer to null;
4. Check the validity of the pointer before use:

	int* p = NULL;
	if(p != NULL)
		*p = 50;

11.4 pointer operation

1. Pointer + - integer:

	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;
	int* pend = arr + 9;//Equivalent to arr[0]
	while (p <= pend)//Pointer relation operation
	{
		printf("%d\n", *p);
		p++;
	}

2. Pointer - pointer, provided that two pointers point to the same space:
Pointer + pointer meaningless

	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%d", &arr[9] - &arr[0]);//Subtract the pointer from the pointer to get the number of elements between the pointers

Analog strlen():

int myStrlen(char* str)
{
	char* start = str;
	while('\0' != str)
	{
		str++;
	} 
	return str - start;
}
size_t myStrlen(const char* str)
{
	assert(str != NULL);
	//assert(str);
	size_t len = 0;
	while (*str++ != '\0')
	{
		len++;
	}
	return len;
}

3. Pointer relation operation
The standard specifies that a pointer to an array element is allowed to be compared with a pointer to the last element of the array and the memory location behind it
However, it is not allowed to compare with a pointer to the memory location before the first element.

#define N_VALUES 5
float values[N_VALUES];
float *vp;
for (vp = &values[0]; vp < &values[N_VALUES];)
{
     *vp++ = 0;
}

11.5 pointers and arrays

	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;//Array name
	//[] is an operator 	 2 and arr are two operands
	printf("%d\n", 2[arr]);	//arr[2] --> *(arr+2) <==> *(2+arr) --> 2[arr]
	printf("%d\n", arr[2]);
	printf("%d\n", p[2]); //p[2] --> *(p+2) <==> *(2+p) --> 2[p]
	//arr[2] <==> *(arr+2) <==> *(p+2) <==> *(2+p) <==> *(2+arr)
	//2[arr] <==> *(2+arr)
	//The [] operator is converted to the understand reference operator * () after being compiled, which is adjusted according to its operands
	//Pointers can also be used as array names, which is very flexible.

11.6 secondary pointer

	int a = 10;
	int* pa = &a;//pa is the pointer variable, the first level pointer
	int* *ppa = &pa;//PA is also a variable, &pa takes the starting address of PA in memory, and ppa is a secondary pointer variable
	int** *pppa = &ppa;

11.7 pointer array

	int arr[10];//Integer array - an array that holds the integer
	char ch[5];//Character array - an array of characters
	//Pointer array - an array of pointers
	int* parr[5];//An array that holds integer pointers
	char* pch[5];//An array of character pointers

11.8 const and pointer

	//const modifies a variable. This variable is called a constant variable and cannot be modified, but it is still a variable in essence.
	const int num = 10;
	int n = 100;
	//num = 20;//err
	int* p = &num;//This allows you to change the value of num through the p pointer
	const int* p = &num;//const, if placed on the left of * and decorated with * p, means that the content pointed to by the pointer cannot be changed by the pointer, but the pointer variable itself can be modified
	*p = 20;//err, modified by const, cannot change the content pointed to by p
	p = &n;//*P cannot be modified, but p can still be modified
	const int num = 10;
	int n = 100;
	num = 20;//err
	int* p = &num;//This allows you to change the value of num
	int* const p = &num;//const, if placed on the right of *, modifies the pointer variable p, indicating that the pointer variable cannot be changed, but the content pointed to by the pointer can be modified
	*p = 20;//*P can be modified, but p cannot be modified.
	p = &n;//err and p are directly modified by const and cannot be changed
	int const* const p = &num;//Neither the pointer itself nor the variable pointed to by the pointer can be changed

11.9 classification and application of pointer

11.9. 1 character pointer

	char ch = 'q';
	char* pc = &ch;
	char* ps = "hello world";//Essentially, the first character address of the string is stored in ps
	*ps = 'w';//err, constant cannot be changed
	char arr[] = "hello world";
	printf("%c\n", *ps);
	printf("%s\n", ps);
	printf("%s\n", arr);

	char str1[] = "hello world.";
	char str2[] = "hello world.";
	const char* str3 = "hello world.";
	const char* str4 = "hello world.";//"hello world." Is a constant string. There is only one copy in memory. Two pointers point to the same space without creating a new space.
	if (str1 == str2)
		printf("str1 and str2 are same\n");
	else
		printf("str1 and str2 are not same\n");
	if (str3 == str4)
		printf("str3 and str4 are same\n");
	else
		printf("str3 and str4 are not same\n");

11.9. 2 pointer array

Pointer array is an array of pointers

	int *arr[3];//An array that holds integer pointers
	int a = 10;
	int b = 20;
	int c = 30;
	int* arr[3] = { &a,&b,&c };
	for (int i = 0; i < 3; i++)
		printf("%d ", *(arr[i]));

	int a[5] = { 1,2,3,4,5 };
	int b[] = { 2,3,4,5,6 };
	int c[] = { 3,4,5,6,7 };

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

11.9. 3 array pointer

Array pointers are pointers to arrays

	int arr[10] = { 1,2,3,4,5 };
	//arr;// Is the address of the first element arr[0]
	int(*parr)[10] = &arr;//parr is an array pointer, where the address of the array is stored
	//If there are no parentheses, parr is combined with [] to become a pointer array.
	double* d[5];
	double* (*pd)[5] = &d;//pd is an array pointer that points to an array with five elements. Each element of the array is double*

	int arr[10] = { 0 };
	printf("%p\n", arr);
	printf("%p\n", &arr);//The values are the same but have different meanings
	int* p1 = arr;
	int(*p2)[10] = &arr;//The address of the array is taken out
	printf("%p\n", p1);
	printf("%p\n", p1 + 1);//p1 points to an integer. Add one to increase the length of an integer by 4
	printf("%p\n", p2);
	printf("%p\n", p2 + 1);//p2 points to an array and increases the length of an array by 40
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int(*pa)[10] = &arr;//[] has higher priority than *. If it is not parenthesized, it indicates the pointer array
	for (int i = 0; i < 10; i++)
		printf("%d ", *(*pa + i));//Array pointers are cumbersome to use in one-dimensional arrays
		//*pa gets the address of the first element of arr, which is of type int, so + i will increase the integer length
		//If pa+i is used directly, the length of i arrays will be increased

	int arr[5]	//arr is an integer array.
	int *parr1[10]	//parr1 is an array of integer pointers.
	int (*parr2)[10]		//parr2 is an array pointer, which points to an array. The array has 10 elements, and each element is of type int.
	int (*parr3[10])[5];		//parr3 is an array with 10 elements. Each element is an array pointer. Each pointer points to an array with 5 elements. Each element is of type int
	//After the array name [] is removed, all that remains is the type of each element of the array
	void ptint2(int (*p)[5], int row, int col)
	{
		for(int i = 0;i < row;i++)
		{
			for(int j = 0;j < col;j++)
				printf("%d ",*(*(p + i) + j));
			printf("\n");
		}
	}
	
	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
	print2(arr, 3, 5);

11.9. 4 array parameter passing and pointer parameter passing

To judge whether the setting of the receiving parameter type meets the requirements, you can see two points:
(1) Look at the parameters passed
(2) Look what kind of this thing is
Meet the above two points

1. One dimensional array parameter transfer

	int arr[10] = { 0 };
	int* arr2[20] = { 0 };
	test(arr);//ok
	test2(arr2);//ok
	//Receive arr
	void test(int arr[]) {}//ok
	void test(int arr[10]) {}//ok
	void test(int* arr) {}//ok
	//Receive arr2
	void test(int* arr[20]) {}//ok
	void test(int** arr) {}//ok

2. Two dimensional array parameter transfer

	int arr[3][5] = { 0 };
	void test(int arr[3][5]) {}//ok
	void test(int arr[][5]) {}//ok
	void test(int arr[][]) {}//err
	void test(int* arr) {}//err, whose first element address receives a pointer array instead of an integer array
	void test(int* arr[5]) {}//err
	void test(int (*arr)[5]) {}//ok
	void test(int** arr) {}//err
	

3. Primary pointer transfer parameter

void test(char* p) {}
void print(int* p, int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%d ", *(p + i));
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	print(p, sz);

	char ch = 'w';
	char* p1 = &ch;
	test(&ch);
	test(p1);
	
	return 0;
}

4. Secondary pointer transfer parameter

void test2(int** p2)
{
	**p2 = 20;
}

int main()
{
	int a = 10;
	int* pa = &a;//pa is the first level pointer
	int* *ppa = &pa;//ppa is a secondary pointer
	//Pass secondary pointer
	test2(ppa);//Pass secondary pointer
	test2(&pa);//Pass the address of the first level pointer variable
	int* arr[10] = { 0 };
	test2(arr);//Pass first level pointer array
	printf("%d", a);
	return 0;
}

11.9. 5 function pointer

A function pointer is a pointer to a function, that is, a pointer that stores the address of the function.
&The function name gets the address of the function.
Array name! =& Array name, function name = = & function name

void test3(char* str){}
int main()
{
	void (*pt)(char*) = &test3;
	printf("%p\n", &Add);
	printf("%p\n", Add);
	int (*pf)(int, int) = &Add;//pf is a function pointer variable
	int (*pf)(int, int) = Add;//Add <==> pf
	printf("%d\n",(****pf)(3, 5));//The function pointer dereference is used to call the function. In fact, * is meaningless. You can write a few 		 one
	printf("%d\n",Add(3, 5));	//		2
	printf("%d\n",pf(3, 5)); //These three lines are equivalent 			 three 			 1 <==> 2 <==> 3
	return 0;
}

See 14.3 for exercises

11.9. 6 function pointer array

Function pointer array is an array of function pointers.

	int (*pf1)(int, int) = Add;
	int (*pf2)(int, int) = Sub;
	int (*pfArr[2])(int, int) = { pf1,Sub };//pfArr is an array of function pointers. pfArr is first combined with square brackets, indicating that it is an array
	//After removing pfArr[2], the remaining int (*)(int,int) indicates that it is a function pointer, pointing to a function with two ints as parameters and an int as return value.

Design simple calculator

int main()
{
	int (*pArr[4])(int , int) = { Add, Sub, Mul, Div };
	int input = 0;
	do
	{
		menu();
		scanf("%d",&input);
		int x = 0;
		int y = 0;
		if (0 <= (input - 1) && 3 >= (input - 1))
		{
			scanf("%d %d", &x, &y);
			printf("%d", pArr[input - 1](x, y));
		}
		else if(input == 0)
			printf("About to exit\n");
		else
			printf("Please enter a valid option\n");
	}while(input);
	
	return 0;
}

11.9. 7 pointer to function pointer array

	int(*p)(int, int);//Function pointer
	int(*pArr[10])(int, int);//Array of function pointers
	int(*(*pa)[10])(int, int);//pa is a pointer to an array of function pointers
	//First, * pa is the pointer. Remove (* pa) to see that it points to an array with 10 elements. Remove (* pa)[10] to see this number
	//Each element of a function is a pointer to a function. The function has even an int parameter and the return value is int

11.9. 8 callback function

1. A callback function is a function called through a function pointer. If you pass the pointer (address) of a function as a parameter to another number, when the pointer is used to call the function it points to, we say it is a callback function. The callback function is not called directly by the implementer of the function, but by another party when a specific event or condition occurs, which is used to respond to the event or condition.

Implement calculator using callback function:

int Cacl(int (*pfun)(int,int))
{
	int x = 0;
	int y = 0;
	printf("Please enter two operands:\n")
	scanf("%d %d",&x,&y);
	return pfun(x, y);
}

int main()
{
	int input = 0;
	do
	{
		menu();
		scanf("%d", &input);
		switch(input)
		{
		case 0:
			printf("About to exit\n");
			break;
		case 1:
			printf("%d\n",Cacl(Add));
			break;
		case 2:
			printf("%d\n",Cacl(Sub));
			break;
		case 3:
			printf("%d\n",Cacl(Mul));
			break;
		case 4:
			printf("%d\n",Cacl(Div));
			break;
		default:
			printf("Please enter a valid option\n");
			break;
		}
	}while(input);
	
	return 0;
}

2.qsort() function
void qsort( void *base, size_t num, size_t width, int (*compare )(const void *elem1, const void *elem2 ) );
void* base: the address of the first element of the data to be sorted.
size_t num: the number and of elements in the data to be sorted.
size_t width: the size of each element in the data to be sorted, in bytes.
Int (* compare) (const void * elem1, const void * elem2): a function that can judge the size of any type of element. Elem1 > elem2 returns 1; Equal return 0; Otherwise, return - 1

Simulate qsort() to realize bubble sorting of any type of data. Take the structure type as an example:

struct Stu
{
	char name[20];
	int age;
};

int cmp_struct(void* ele1,void* ele2)
{
	//When calling bubbleAnyType(), the address of this function is the fourth parameter, which needs to be implemented by yourself
	//First cast the formal parameter to a pointer of the type of data to be compared, and then operate
	return strcmp(((struct Stu*)ele1) -> name,((struct Stu*)ele2) -> name);//Sort by name
	//return (struct Stu*)ele1.age- (struct Stu*)ele2.age;// Sort by age
}

void swap(char* ele1,char* ele2,int width)
{
	//Exchange two elements in bytes, so set the formal parameter to char *
	for(int i = 0; i < width; i++)
	{
		char tmp = *ele1;
		*ele1 = *ele2;
		*ele2 = tmp;
		ele1++;
		ele2++;
	}
}

void bubbleAnyType(void* base,int size,int width,int (*compare)(const void* e1, const void* e2))
{
	for(int i = 0; i < size - 1; i++)
	{
		for(int j = 0; j < size -1 -i; j++)
		{
		//Operates in bytes, because bytes are the smallest storage unit of each type
		//The data to be operated is found by the first address + the size of the data type
			if( compare( (char*)base + j * width, (char*)base + (j + 1) * width) > 0 )
			{//Exchange element
				swap( (char*)base + j * width, (char*)base + (j + 1) * width, width) );
			}
		}	
	}
}

int main()
{
	struct Stu s[3] = { {"zhangsan",30},{"lisi",35},{"wangwu",25} };
	int sz = sizeof(s) / sizeof(s[0]);
	bubbleAnyType(s,sz,sizeof(s[0]),cmp_struct);
	return 0;
}

Before sorting:

After sorting (take sorting by name as an example):

11.9. Analysis of 9 pointer and array interview questions

Sizeof (array name) the array list is placed in parentheses, and the & array name is the size of the entire array and the address to get the entire array, respectively. In addition, all array names are the address of the first element.

	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));			//	16
	printf("%d\n", sizeof(a + 0));		//	four 	 a+0 is the address of the first element
	printf("%d\n", sizeof(*a));			//	four 	 A is the address of 1, * a means 1
	printf("%d\n", sizeof(a + 1));		//	four 	 a+1 is the address of the second element
	printf("%d\n", sizeof(a[1]));		//	4	
	printf("%d\n", sizeof(&a));			//	4
	printf("%d\n", sizeof(*&a));		//	sixteen 	*& Actually, they offset each other
	printf("%d\n", sizeof(&a + 1));		//	four 	 The addresses of the space behind the array are all addresses 	* (& A + 1) can access the size of an array
	printf("%d\n", sizeof(&a[0]));		//	four 	 Wherever it points, it's the address
	printf("%d\n", sizeof(&a[0] + 1));	//	four 	 Wherever it points, it's the address

Topics: C C++