C pointer special exercise

Keywords: C pointer


This chapter mainly explains 13 classic exercises about pointers.

Meaning of array name

First, review the knowledge about array names:

1. Sizeof (array name): here, the array name represents the whole array;
2. & array name: here, the array name represents the whole array;
3. In other cases, the array name represents the address of the first element of the array

strlen library function: find string length
sizeof operator: find the space occupied by variables or variables created by types (unit: bytes)

practice

Question 1

//Code 1
int main()
{
	//One dimensional array
	int a[] = { 1,2,3,4 };
	
	//sizeof(a) - represents the entire array
	printf("%d\n", sizeof(a));//16
	
	//a+0 indicates the address of the first element
	printf("%d\n", sizeof(a + 0));// 4/8
	
	//*a represents the first element
	printf("%d\n", sizeof(*a));//4

	//a+1 indicates the address of the second element
	printf("%d\n", sizeof(a + 1));// 4/8
	
	//a[1] is the second element
	printf("%d\n", sizeof(a[1]));//4

	//&A represents the address of the entire array
	printf("%d\n", sizeof(&a));// 4/8

	//&A represents the address of the array. Dereference the array address to get the array
	printf("%d\n", sizeof(*&a));//16

	//&A + 1 represents the address across the entire array
	printf("%d\n", sizeof(&a + 1));// 4/8

	//&A [0] indicates the address of the first element
	printf("%d\n", sizeof(&a[0]));//  4/8
	
	//&A [0] + 1 indicates the address of the second element
	printf("%d\n", sizeof(&a[0] + 1));// 4/8
	return 0;
}

Resolution:
(1) sizeof(a): put the array name in sizeof to represent the whole array. Calculate the size of the whole array, 16 bytes;

(2) sizeof(a+0): the array name here is not directly placed in sizeof, so the array name here shows the address of the first element of the array, and a+0 still represents the address of the first element. Therefore, sizeof(a+0) is the size of the calculated address, which is 4 bytes on 32-bit platform and 8 bytes on 64 bit platform;

(3) sizeof(*a): here a represents the address of the first element of the array, * a dereferences the address of the first element to get the first element of type 1, int, so it is 4 bytes;

(4) Sizeof (a+1): here a represents the address of the first element, a+1 represents the address of the second element, and the pointer is 4 bytes or 8 bytes;

(5) sizeof(a[1]): a[1] represents the second element, that is, 2, int type, 4 bytes

(6) Sizeof & A: & A represents the address of the array, and the size of the pointer is 4 bytes or 8 bytes;

(7) sizeof(* & A): & A gets the address of the array, dereference the address of the array to get the array, that is, the array name, * & A is equivalent to a, so sizeof (array name) calculates the size of the entire array, 16 bytes;

(8) Sizeof & A + 1): & A gets the address of the array. The address after & A + 1 crosses an array. The address size is 4 bytes or 8 bytes;

(9) Sizeof (& a[0]): a[0] represents the first element, & a[0] represents the address of the first element. The address size is 4 bytes or 8 bytes;

(10) Sizeof (& A [0] + 1): & A [0] + 1 represents the address of the second element. The address size is 4 bytes or 8 bytes;

Question 2

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", sizeof(arr));//6
	printf("%d\n", sizeof(arr + 0));//4/8
	printf("%d\n", sizeof(*arr));//1
	printf("%d\n", sizeof(arr[1]));//1
	printf("%d\n", sizeof(&arr));//4/8
	printf("%d\n", sizeof(&arr + 1));//4/8
	printf("%d\n", sizeof(&arr[0] + 1));//4/8

	printf("%d\n", strlen(arr));//For cross-border access, only the access value is not changed, but there are some problems, such as random value
	printf("%d\n", strlen(arr + 0));//Random value

	//strlen thought the ascii code value 97 of 'a' passed in was the address
	printf("%d\n", strlen(*arr));//Error 'a'-97 is reported. 97 is used as the address to start the number, string length, wild pointer, illegal access to memory
	
	printf("%d\n", strlen(arr[1]));//'b'-98 error

	//The parameter of strlen is const char*
	printf("%d\n", strlen(&arr));//&Arr is the address of the array. The type does not match, but it does not affect

	printf("%d\n", strlen(&arr + 1));//Random value

	printf("%d\n", strlen(&arr[0] + 1));//Random value

	return 0;
}

Resolution:
(1) sizeof(arr): put the array name in sizeof to represent the whole array. Here is the size of the array, 6 bytes;

(2) sizeof(arr + 0): arr is not directly placed in sizeof. It represents the address of the first element of the array. a+0 still represents the address of the first element. The address size is 4 bytes or 8 bytes;

(3) sizeof(*arr): * arr means to dereference the address of the first element of the array to obtain the first element, that is, the character 'a', 1 byte;

(4) sizeof(arr[1]): arr[1] represents the second element, character 'b', 1 byte;

(5) Sizeof (& ARR): & arr represents the address of the array. The address is 4 bytes or 8 bytes;

(6) Sizeof (& arr + 1): & arr represents the array address, & arr + 1 represents the address across the entire array, 4 bytes or 8 bytes;

(7) Sizeof (& arr [0] + 1): & arr [0] represents the address of the first element, & arr [0] + 1 represents the address of the second element, 4 bytes or 8 bytes;

(8) strlen(arr): the array name indicates the address of the first element. Here, the strlen function is to find the length of the string. It stops when it encounters' \ 0 ', and' \ 0 'is not counted as the length of the string. Only 6 characters are stored in the character array arr, and' \ 0 'is not stored. Therefore, it is not clear when it will encounter' \ 0 '. It will be accessed beyond the boundary, but the value will not be changed, However, there are some problems, the result is random value;

(9) strlen(arr + 0): the same as (8), the result is a random value;

(10) strlen(*arr): the formal parameter of the strlen function is a const char * pointer. Here, * arr gets the first element, the character 'a', and the corresponding ASCII code is 97. Therefore, the strlen function will regard 97 as an address and then access the address space. Due to the unknown pointer and wild pointer, it will illegally access memory and report an error;

(11) strlen(arr[1]): the interpretation is the same as (10). The ASCII code value 98 of the character 'b' is regarded as the address and illegally accesses the memory;

(12) Strlen & arr: & arr is the address of the array, and the type is char (*)[6]. The formal parameter of strlen function is const char * type. If the type does not match, a warning will be given, but it will not affect. The result is a random value, but the result is the same as (8) and (9);

(13) Strlen (& arr + 1): & arr represents the address of the array. After & arr + 1 crosses the address of the array, it is accessed beyond the boundary, but the value is not changed. The result is a random value, but the result is 6 smaller than (12);

(14) Strlen (& arr [0] + 1): & arr [0] + 1 indicates the address of the second element, and the result is 1 less than (8);

Question 3

int main()
{
	char arr[] = "abcdef";
	printf("%d\n", sizeof(arr));//7
	printf("%d\n", sizeof(arr + 0));//4/8
	printf("%d\n", sizeof(*arr));//1
	printf("%d\n", sizeof(arr[1]));//1
	printf("%d\n", sizeof(&arr));//4/8
	printf("%d\n", sizeof(&arr + 1));//4/8
	printf("%d\n", sizeof(&arr[0] + 1));//4/8

	printf("%d\n", strlen(arr));//6
	printf("%d\n", strlen(arr + 0));//6
	printf("%d\n", strlen(*arr));//'a'-97 as an address field pointer, illegal access to memory
	printf("%d\n", strlen(arr[1]));//'b'-98 as an address field pointer, illegal access to memory
	printf("%d\n", strlen(&arr));//6
	printf("%d\n", strlen(&arr + 1));//Random value
	printf("%d\n", strlen(&arr[0] + 1));//5

	return 0;
}

Resolution:
(1) sizeof(arr): the array name is directly placed in sizeof to represent the whole array, so the result is 7

(2) Sizeof (arr+0): here, the array name represents the address of the first element. arr+0 still represents the address of the first element. The address is a pointer, so the result is 4 / 8

(3) sizeof(*arr): this array name represents the address of the first element. Dereference arr to get the first element, so the result is 1

(4) sizeof(arr[1]): arr[1] = * (arr+1), get the second element, and the result is 1

(5) Sizeof (& ARR): here, arr represents the entire element, & arr represents the address of the array. It is a pointer, so the result is 4 / 8

(6) Sizeof (& arr + 1): & arr + 1 crosses this array, so the result is 4 / 8

(7) Sizeof (& arr [0] + 1): & arr [0] gets the address of the first element, & arr [0] + 1 represents the address of the second element, and the result is 4 / 8

(8) strlen(arr): srr represents the address of the first element. Here, the length of the string is calculated from the address of the first element of the array to the end of the first '\ 0'. '\ 0' is not counted as the length of the string, and the result is 6

(9) strlen(arr + 0): the result is the same as above

(10) strlen(*arr): * arr gets the first element of the array. Here, take the ASCII code value 97 corresponding to character 'a' as the first address, and look back for the first '\ 0', because the space with address 97 points to unknown, resulting in wild pointer, illegal access to memory and program crash

(11) strlen(arr[1]): arr[1] represents the second element of the array. Here, the ASCII code value 98 corresponding to the second element 'b' is used as the address to calculate the string length. Because the space with address 98 points to an unknown point, it causes a wild pointer, illegal access to memory and program crash

(12) Strlen & arr: & arr is the address of the array. The calculated string length is 6

(13) Strlen (& arr + 1): & arr + 1 is a pointer that spans the entire array. The result is a random number because the position of '\ 0' is ambiguous

(14) Strlen (& arr [0] + 1): & arr [0] + 1, the result is the address of the second element of the array, the length of the string is calculated, and the result is 5

Question 4

int main()
{
	char* p = "abcdef";	
	printf("%d\n", sizeof(p));//4/8
	printf("%d\n", sizeof(p + 1));//4/8
	printf("%d\n", sizeof(*p));//1
	printf("%d\n", sizeof(p[0]));//1
	printf("%d\n", sizeof(&p));//4/8
	printf("%d\n", sizeof(&p + 1));//4/8
	printf("%d\n", sizeof(&p[0] + 1));//4/8

	printf("%d\n", strlen(p));//6
	printf("%d\n", strlen(p + 1));//5
	printf("%d\n", strlen(*p));//'a'-97 as address, illegal access to memory
	printf("%d\n", strlen(p[0]));//'a'-97 as address, illegal access to memory
	printf("%d\n", strlen(&p));//Random value
	printf("%d\n", strlen(&p + 1));//Random value
	printf("%d\n", strlen(&p[0] + 1));//5
	return 0;
}

Resolution:
(1) sizeof §: p is the pointer and the result is 4 / 8

(2) Sizeof (p+1): p+1 is still a pointer, and the result is 4 / 8

(3) sizeof(*p): * p gets the character 'a', and the result is 1

(4) sizeof(p[0]): p[0] = * (p+0), which is the character 'a', and the result is 1

(5) Sizeof & p: & p gets the address of pointer p, that is, the secondary pointer, and the result is 4 / 8

(6) Sizeof (& p + 1): & p get the address of pointer p, the secondary pointer, the type is char * *, the result is 4 / 8, and the number of bytes crossed by pointer + 1 is equal to the size of the type pointed to by the pointer


(7) Sizeof (& P [0] + 1): & P [0] + 1 = & * (p+0) + 1 = p+0+1, still a pointer, the result is 4 / 8

(8) strlen §: calculate the string length and the result is 6

(9) Strlen (p+1): p+1 points to the character 'b', and the result is 5

(10) strlen(*p): * p obtains the character 'a', takes the ASCII code value 97 corresponding to the character 'a' as the address, and calculates the length of the string. The pointer points to an unknown, which is a wild pointer, resulting in illegal access to memory and program crash

(11) strlen(p[0]): the result is the same as above

(12) Strlen & P: & P get the pointer of the pointer, that is, the secondary pointer, as shown in the following figure

The formal parameter of strlen function is const char *
Take & P as the first address and calculate the string length. The type of & P is char * *. If it is put into the strlen function, a warning will be reported, as follows


However, it will still be calculated as a char * pointer. Here, the result is a random number, because the content of p is uncertain and we don't know where the first '\ 0' is

(13) Strlen (& P + 1)): & P is a secondary pointer, as shown in the figure below. The result is a random value because the position of \ 0 is ambiguous

(14) Strlen (& P [0] + 1): & * (p+0) + 1 = p+0+1, the result is 5

Question 5

int main()
{
	//Two dimensional array
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//48
	printf("%d\n", sizeof(a[0][0]));//4

	//a[0] = *(a+0),a is the first element address, a+0 is also the first element address, and * (a+0) is the first element, that is, the first one-dimensional array,
	//Sizeof (array name): the size of the entire array
	printf("%d\n", sizeof(a[0]));//16

	//a[0] is the array name of the first row array - the address of the first element of the array,
	//a[0]+1 is the address of the second element in the first line
	printf("%d\n", sizeof(a[0] + 1));//4/8
	
	//First line, second element
	printf("%d\n", sizeof(*(a[0] + 1)));//4


	//The array name of a two-dimensional array, indicating the address of the first element and the address of the first line
	//Address of the second one-dimensional array
	//The array name a is not separately placed in sizeof, nor is it addressed, so a represents the address of the first element of the array
	printf("%d\n", sizeof(a + 1));//4/8

	printf("%d\n", sizeof(*(a + 1)));//16

	//a[0] is the array name in the first row
	//&A [0] is the address of the first line
	//&A [0] + 1 gets the address of the second line
	printf("%d\n", sizeof(&a[0] + 1));//4/8

	//*(&a [0] + 1)) get the array name of the second row
	printf("%d\n", sizeof(*(&a[0] + 1)));//16

	//*a gets the array name of the first row
	printf("%d\n", sizeof(*a));//16

	//a[3] is equivalent to the array name in the fourth line, but sizeof does not perform internal operations and will not really cross-border access
	printf("%d\n", sizeof(a[3]));//16


	//*&Arr: get arr, that is, the array name. Whether arr is the address of the whole array or the first element of the array depends on where it is placed

	//Dereference the address of one-dimensional array to obtain the array name of one-dimensional array
	return 0;
}

(1) sizeof(a): the array list is placed inside sizeof, representing the entire array

(2) sizeof(a[0][0]): here, the array name represents the address of the first element, a[0][0] = * (*(a+0)+0), a[0][0]=0, and the result is 4

(3) sizeof(a[0]): a[0] represents the first element. Here, it represents the array name of the first one-dimensional array. The array list is placed inside sizeof alone, representing the whole array

(4) Sizeof (a[0]+1): a[0] represents the first element, here represents the name of the first one-dimensional array, here the array name represents the address of the first element, a[0]+1 represents the address of the second element in the first one-dimensional array, and the result is 4 / 8

(5) Sizeof (* (a[0]+1)): a[0] represents the array name of a one-dimensional array, a[0]+1 represents the address of the second element of the first one-dimensional array, and * (a[0]+1) represents the second element of the first line, and the result is 4

(6) Sizeof (a+1): a+1 indicates the address of the second element of the array, and the result is 4 / 8

(7) Sizeof (* (a+1)): * (a+1) represents the second one-dimensional array, and the result is 16

(8) Sizeof (& A [0] + 1): & A [0] represents the address of the first element, & A [0] + 1 represents the address of the second element, and the result is 4 / 8

(9) Sizeof (* (& A [0] + 1)): & A [0] + 1 represents the address of the second element, * (& A [0] + 1) represents the second element, here represents the second one-dimensional array, and the result is 16

(10) sizeof(*a): * a represents the array name of the first element, that is, the first one-dimensional array, and the result is 16

(11) sizeof(a[3]): a[3] indicates the fourth element, and the result is 16. Although the access is out of bounds, the data in memory has not been changed, so it doesn't matter.

Question 6

int main()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int* ptr = (int*)(&a + 1);
	printf("%d,%d", *(a + 1), *(ptr - 1));//2,5
	return 0;
}

Question 7

struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;

int main()
{
	p = (struct Test*)0x100000;

	//p is the structure type pointer. p+0x1 belongs to pointer + 1. It crosses a pointer to the element type, where it crosses 20 bytes
	printf("%p\n", p + 0x1);//0x100014

	//p is cast to unsigned long, integer + 1 
	printf("%p\n", (unsigned long)p + 0x1);//0x100001

	//p is cast to an unsigned int * pointer, pointer + 1
	printf("%p\n", (unsigned int*)p + 0x1);//0x100004
	return 0;
}

If the address 0x100000 is cast to struct Test * type, the number of bytes crossed by the pointer p+1 is 20, and the hexadecimal representation is 14, so p+0x1 = 0x100014

(unsigned long)p + 0x1 converts the mandatory type of P to unsigned long, so p is an unsigned integer. Integer + 1 simply adds 1, and the result is 0x100001

(unsigned int*)p + 0x1 converts p cast type to unsigned int type. p+1 spans 4 bytes, so the result is 0x100004

Note:% p is the print address and the address is an unsigned number.

Question 8

int main()
{
	int a[4] = { 1, 2, 3, 4 };
	int *ptr1 = (int *)(&a + 1);
	int *ptr2 = (int *)((int)a + 1);
	printf( "%x,%x", ptr1[-1], *ptr2);
	return 0;
}


be careful:
1. Large and small end problem. For a data (greater than one byte), there are two storage methods, large end storage and small end storage;
2. For an array, the address becomes larger as the subscript of the array element increases.

Computers generally store at the small end, so as shown in the figure, each element of the array is stored in the small end byte order. In (int)a, a is the address of the first element of the array. The forced type of a is converted to int type, integer + 1, and then forced type is converted to int * pointer. Therefore, the pointing of ptr2 is shown in the figure. When fetching data from memory, it also fetches data according to the small end storage mode, placing the data with low address in the low byte and the data with high address in the high byte.

Question 9

#include <stdio.h>
int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	int *p;
	p = a[0];
	printf( "%d", p[0]);
	return 0;
}

a[0] = *(a+0): A is the address of the first element of the array, and each element of a is a one-dimensional array, so a is the address of the first one-dimensional array, * (a+0) gets the first one-dimensional array, that is, the array name of the first one-dimensional array (except in two cases, the array name represents the address of the first element of the array), So the pointer P represents the address of the first element of the first one-dimensional array, then p[0] gets the first element of the first one-dimensional array, and the result is 1.

Question 10

int main()
{
	int a[5][5];
	int(*p)[4];
	p = a;
	printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
	return 0;
}

Array name a is the address of the first element, that is, the address of the first one-dimensional array. The type is int(*)[5]. Assign this address to P, but the type of P is int(*)[4] (a warning will be given)& p[4][2] = &*( *(p+4)+ 2) = (p+4)+2
Because p is an int(*)[4] type pointer and p+1 crosses an array with 4 int elements, (p+4) gets the array (array name) in the blue box in the figure below. The array name is the address of the first element, so * (p+4)+2 gets the address of the third element of the array. Similarly &a [4] [2] position is shown in the figure below. The absolute value of (pointer pointer) is the number of elements between pointers, There are four elements.

&p[4][2] < &a[4][2],&p[4][2] - &a[4][2] = -4

Original code:

//-4
//Original code
10000000 00000000 00000000 00000100
//Inverse code
11111111 11111111 11111111 11111011
//Complement
11111111 11111111 11111111 11111100

%p: Print the address. The address is an unsigned number and cannot be less than 0. Therefore, the complement of - 4 in memory is taken as an unsigned number and printed, that is, FF FC

%d: Print numbers in signed, hexadecimal form, i.e. - 4

Question 11

int main()
{
	int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int *ptr1 = (int *)(&aa + 1);
	int *ptr2 = (int *)(*(aa + 1));
	printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
	return 0;
}

&AA is the address of the entire array, and & AA + 1 spans the entire array,
aa is the address of the first element, aa+1 is the address of the second one-dimensional array, and * (aa+1) gets the second one-dimensional array, that is, the array name - the address of the first element, which is forcibly converted to int * type, as shown in the following figure

*(ptr1 - 1) = 10
*(ptr2 - 1) = 5

Question 12

#include <stdio.h>
int main()
{
	char *a[] = {"work","at","alibaba"};
	char**pa = a;
	pa++;
	printf("%s\n", *pa);
	return 0;
} 

The array name a is the address of the first element, so a is a pointer of char * * type, and the type of pa is also char * *. The data type pointed to is char *. Assign the value of a to pa, pa + + (pointer + 1, the number of bytes crossed is the byte of the type size of the element it points to), and span 4 bytes (because char * accounts for 4 bytes). At this time, pa points to the second element of array a, *pa obtains the second element of array a, which is a pointer to the first character 'a' of the constant string "at", so the string is printed in the form of% s and the result is at.

Question 13

int main()
{
	char *c[] = {"ENTER","NEW","POINT","FIRST"};
	char**cp[] = {c+3,c+2,c+1,c};
	char***cpp = cp;
	printf("%s\n", **++cpp);
	printf("%s\n", *--*++cpp+3);
	printf("%s\n", *cpp[-2]+3);
	printf("%s\n", cpp[-1][-1]+1);
	return 0;
}

Let's analyze them one by one:

(1) **++cpp:
The number of bytes crossed by the pointer cpp+1 is the size of the element pointed to by cpp, that is, 4 bytes (the number of bytes crossed by the pointer + 1 is determined by the pointer type). At this time, the direction of cpp is shown in the following figure:

**cpp = *(c+2) is the address of the character 'P', so "POINT" is printed in the form of% s

(2) –++cpp+3:
Priority of leading + + is greater than+
++The direction of cpp after cpp is shown in the following figure

*The priority of is greater than +, + cpp gets c+1. At this time, the expression is – (c+1) + 3, and the priority of the preceding – is greater than +. Therefore, the expression becomes * c+3, and the address of the character 'E' is obtained. The print result is "ER" in the form of% s


(3) *cpp[-2]+3
At this time, the direction of cpp is still as shown in the above figure, * cpp[-2]+3 = * (* (cpp - 2)) + 3
The direction of cpp - 2 is shown in the figure below. The priority of * is higher than + and * (* (cpp-2)) gets * (c+3), that is, the address of the character'S', and the result is "ST"

(4)cpp[-1][-1]+1
At this time, the direction of cpp is still as shown in the above figure. cpp[-1][-1] +1 = *(*(cpp -1) - 1) + 1 = *((c + 2) - 1)+1 =\ *(c+1)+1 is the address of the character 'E', so the result is "EW"

Posted by rocketsprocket on Mon, 13 Sep 2021 20:13:59 -0700