Puntero avanzado de lenguaje C avanzado

Por favor agregue una descripción de la imagen


El tema de los punteros, ya lo hemos tocado en el blog elemental de lenguaje C, conocemos el concepto de punteros:

  1. Un puntero es una variable que se utiliza para almacenar una dirección, que identifica de forma única una parte del espacio de memoria.
  2. El tamaño del puntero se fija en 4/8 bytes (plataforma de 32 bits/plataforma de 64 bits).
  3. El puntero tiene un tipo, y el tipo del puntero determina el tamaño de paso del puntero ± entero, y la autoridad de la operación de desreferencia del puntero.
  4. Aritmética con punteros.
    A continuación, continuamos explorando el tema avanzado de los punteros.

1. Puntero de carácter

En el tipo de puntero, sabemos que hay un tipo de puntero que es un carácter puntero char*;
generalmente se usa:

int main()
{
    
    
 	char ch = 'a';
 	char *pc = &ch;
 	*pc = 'a';
 	return 0;
}

Otra forma de usarlo es la siguiente:

int main()
{
    
    
 	const char* pstr = "hello C.";
 	printf("%s\n", pstr);
 	return 0;
}

Entonces, ¿se coloca una cadena en la variable de puntero pstr aquí?
De hecho, no lo es, aquí se almacena la dirección del primer carácter de la cadena, es decir, h, en la variable de puntero pstr.

Echemos un vistazo a la siguiente pregunta de la entrevista sobre los punteros de caracteres.

#include <stdio.h>
int main()
{
    
    
	char str1[] = "hello bit.";
	char str2[] = "hello bit.";
	const char* str3 = "hello bit.";
	const char* str4 = "hello bit.";
	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");

	return 0;
}

inserte la descripción de la imagen aquí
En primer lugar, el nombre de la matriz representa la dirección del primer elemento de la matriz, por lo que aquí str1 y str2 almacenan respectivamente la dirección del primer carácter de la matriz correspondiente, no son lo mismo, por lo que el primer resultado de salida es str1 y str2 no son iguales, aquí str3 y str4 apuntan a la misma cadena constante. C/C++ almacenará cadenas constantes en un área de memoria separada.Cuando varios punteros apuntan a la misma cadena, en realidad apuntarán al mismo bloque de memoria. Pero cuando se usa la misma cadena constante para inicializar diferentes arreglos, se abrirán diferentes bloques de memoria. Entonces str1 y str2 son diferentes, y str3 y str4 son iguales.

2. Matriz de punteros

Hemos hablado de las matrices de punteros al comienzo del lenguaje C,
de la siguiente manera:

int* arr1[10]; //整形指针的数组
char *arr2[4]; //一级字符指针的数组
char **arr3[5];//二级字符指针的数组

3. Puntero de matriz

3.1 Definición de puntero de matriz

¿Los punteros de matriz son punteros? ¿O una matriz?
La respuesta es: punteros.
Ya estamos familiarizados con:
Puntero entero: int * p; Un puntero que puede apuntar a datos enteros.
Puntero de punto flotante: float * pf; Un puntero que puede apuntar a datos de punto flotante.
El puntero de matriz debe ser: un puntero que pueda apuntar a una matriz.
Entonces, ¿cuál de los siguientes códigos es un puntero de matriz?

int *p1[10];
int (*p2)[10];

La respuesta es int (*p2)[10];

p se combina primero con *, lo que indica que p es una variable de puntero, y luego apunta a una matriz de 10 enteros. Entonces p es un puntero que apunta a una matriz, llamado puntero de matriz.

Cabe señalar que la prioridad de [] es mayor que la de *, por lo que se debe agregar () para garantizar que p se combine con * primero

3.2 & nombre de matriz VS nombre de matriz

¿Qué son los arreglos
arr y &arr respectivamente?
Sabemos que arr es el nombre de la matriz y el nombre de la matriz representa la dirección del primer elemento de la matriz.
¿Cuál es el nombre de la matriz &arr?

Sabemos que arr es el nombre de la matriz y el nombre de la matriz representa la dirección del primer elemento de la matriz.
¿Cuál es el nombre de la matriz &arr?
Veamos un trozo de código:

#include <stdio.h>
int main()
{
    
    
 int arr[10] = {
    
    0};
 printf("%p\n", arr);
 printf("%p\n", &arr);
 return 0;
}

inserte la descripción de la imagen aquí
Podemos ver que las direcciones impresas por el nombre del arreglo y el nombre del arreglo & son las mismas, ¿son iguales?
Mira la siguiente pieza de código:

#include <stdio.h>
int main()
{
    
    
	int arr[10] = {
    
     0 };
	printf("arr = %p\n", arr);
	printf("&arr= %p\n", &arr);
	printf("arr+1 = %p\n", arr + 1);
	printf("&arr+1= %p\n", &arr + 1);
	return 0;
}

inserte la descripción de la imagen aquí
De acuerdo con el código anterior, encontramos que, de hecho, &arr y arr tienen el mismo valor, pero el significado debería ser diferente.
De hecho : &arr representa la dirección del arreglo, no la dirección del primer elemento del arreglo. (Experiencia en detalle)
El tipo de &arr en este ejemplo es : int(*)[10], que es un tipo de puntero de matriz, la dirección de la matriz +1, omitiendo el tamaño de toda la matriz, por lo que &arr+1 es relativo a &arr La diferencia es 40

3.3 Uso de punteros de matriz

¿Cómo se usa el puntero de matriz?
Dado que el puntero de matriz apunta a una matriz, la dirección de la matriz debe almacenarse en el puntero de matriz.
Mira el código:

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

Asigne la dirección de la matriz arr a la variable de puntero de matriz p, pero generalmente rara vez escribimos código como este
de la siguiente manera:

#include <stdio.h>
void print_arr1(int arr[3][5], int row, int col)
{
    
    
	int i = 0;
	for (i = 0; i < row; i++)
	{
    
    
		for (j = 0; j < col; j++)
		{
    
    
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}
void print_arr2(int(*arr)[5], int row, int col)
{
    
    
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
    
    
		for (j = 0; j < col; j++)
		{
    
    
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}
int main()
{
    
    
	int arr[3][5] = {
    
     1,2,3,4,5,6,7,8,9,10 };
	print_arr1(arr, 3, 5);
	print_arr2(arr, 3, 5);
	return 0;
}

El nombre de la matriz arr indica la dirección del primer elemento,
pero el primer elemento de la matriz bidimensional es la primera fila de la matriz bidimensional,
por lo que la matriz que se pasa aquí es en realidad equivalente a la dirección de la primera fila, que es la dirección de la matriz unidimensional y
puede ser recibida por un puntero de matriz

Echemos un vistazo a lo que representan los siguientes códigos

int arr[5];//数组
int *parr1[10];//指针数组
int (*parr2)[10];//数组指针
int (*parr3[10])[5];//数组指针数组

4. Parámetros de matriz, parámetros de puntero

4.1 Paso de parámetros de matriz unidimensional

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

Todos estos métodos de entrega son posibles.

4.2 Paso de parámetros de matrices bidimensionales

void test(int arr[3][5])//ok
{
    
    }
void test(int arr[][])//不可以
{
    
    }
void test(int arr[][5])//ok
{
    
    }
void test(int* arr)//不可以
{
    
    }
void test(int* arr[5])//ok
{
    
    }
void test(int(*arr)[5])//ok
{
    
    }
void test(int** arr)//不可以
{
    
    }
int main()
{
    
    
	int arr[3][5] = {
    
     0 };
	test(arr);
}

Resumen: al pasar parámetros en una matriz bidimensional, el diseño de los parámetros de función solo puede omitir el primer número [].
Porque para una matriz bidimensional, no necesita saber cuántas filas hay, pero debe saber cuántos elementos hay en una fila. Esto es conveniente para la operación.

4.3 Paso de parámetros de puntero de primer nivel

#include <stdio.h>
void print(int* p, int sz)
{
    
    
	int i = 0;
	for (i = 0; i < sz; i++)
	{
    
    
		printf("%d\n", *(p + i));
	}
}
int main()
{
    
    
	int arr[10] = {
    
     1,2,3,4,5,6,7,8,9 };
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	print(p, sz);
	return 0;
}

4.4 Paso de parámetros de puntero de segundo nivel

#include <stdio.h>
void test(int** ptr)
{
    
    
	printf("num = %d\n", **ptr);
}
int main()
{
    
    
	int n = 10;
	int* p = &n;
	int** pp = &p;
	test(pp);
	test(&p);
	return 0;
}

5. Punteros de función

primero mira el codigo

#include <stdio.h>
void test()
{
    
    
	printf("hehe\n");
}
int main()
{
    
    
	printf("%p\n", test);
	printf("%p\n", &test);
	return 0;
}

inserte la descripción de la imagen aquí
No es difícil ver que el nombre de la función es la dirección de la función y estas dos direcciones son las direcciones de la función de prueba. Entonces, ¿cómo guardamos la dirección de nuestra función si queremos guardarla?

#include <stdio.h>
void test()
{
    
    
	printf("hehe\n");
}
void (*pfun1)();

pfun1 primero se combina con *, lo que indica que pfun1 es un puntero, y el puntero apunta a una función, la función apuntada no tiene parámetros y el tipo de valor de retorno es nulo.

6. Matriz de punteros de función

Una matriz es un espacio de almacenamiento que almacena el mismo tipo de datos, por lo que ya hemos aprendido acerca de las matrices de punteros, por ejemplo:

int *arr[10];
//数组的每个元素是int*

Luego almacene la dirección de la función en una matriz, luego esta matriz se denomina matriz de punteros de función, ¿cómo definir la matriz de punteros de función?

int (*parr1[10])();

Parr1 primero se combina con [], lo que indica que parr1 es una matriz, ¿cuál es el contenido de la matriz? es un puntero de función de tipo int (*)().
Propósito de la matriz de punteros de función: Tabla de transferencia
Ejemplo: Calculadora de escritura convencional

#include <stdio.h>
int add(int a, int b)
{
    
    
	return a + b;
}
int sub(int a, int b)
{
    
    
	return a - b;
}
int mul(int a, int b)
{
    
    
	return a * b;
}
int div(int a, int b)
{
    
    
	return a / b;
}
int main()
{
    
    
	int x, y;
	int input = 1;
	int ret = 0;
	do
	{
    
    
		printf("*************************\n");
		printf(" 1:add 2:sub \n");
		printf(" 3:mul 4:div \n");
		printf("*************************\n");
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
    
    
		case 1:
			printf("输入操作数:");
			scanf("%d %d", &x, &y);
			ret = add(x, y);
			printf("ret = %d\n", ret);
			break;
		case 2:
			printf("输入操作数:");
			scanf("%d %d", &x, &y);
			ret = sub(x, y);
			printf("ret = %d\n", ret);
			break;
		case 3:
			printf("输入操作数:");
			scanf("%d %d", &x, &y);
			ret = mul(x, y);
			printf("ret = %d\n", ret);
			break;
		case 4:
			printf("输入操作数:");
			scanf("%d %d", &x, &y);
			ret = div(x, y);
			printf("ret = %d\n", ret);
			break;
		case 0:
			printf("退出程序\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
	} while (input);

	return 0;

Implementación utilizando una matriz de punteros de función:

#include <stdio.h>
int add(int a, int b)
{
    
    
	return a + b;
}
int sub(int a, int b)
{
    
    
	return a - b;
}
int mul(int a, int b)
{
    
    
	return a * b;
}
int div(int a, int b)
{
    
    
	return a / b;
}
int main()
{
    
    
	int x, y;
	int input = 1;
	int ret = 0;
	int(*p[5])(int x, int y) = {
    
     0, add, sub, mul, div }; //转移表
while(input)
{
    
    
	printf("*************************\n");
	printf(" 1:add 2:sub \n");
	printf(" 3:mul 4:div \n");
	printf("*************************\n");
	printf("请选择:");
	scanf("%d", &input);
	if ((input <= 4 && input >= 1))
	{
    
    
		printf("输入操作数:");
		scanf("%d %d", &x, &y);
		ret = (*p[input])(x, y);
	}
	else
		printf("输入有误\n");
	printf("ret = %d\n", ret);
}
return 0;
}

De esta manera el código no es redundante.

7. Puntero a una matriz de punteros de función

Un puntero a una matriz de punteros de función es un puntero , y el puntero apunta a una matriz , y los elementos de la matriz son todos punteros de función ;
luego, cómo definirlo, vea el siguiente código:

void test(const char* str)
{
    
    
	printf("%s\n", str);
}
int main()
{
    
    
	//函数指针pfun
	void (*pfun)(const char*) = test;
	//函数指针的数组pfunArr
	void (*pfunArr[5])(const char* str);
	pfunArr[0] = test;
	//指向函数指针数组pfunArr的指针ppfunArr
	void (*(*ppfunArr)[5])(const char*) = &pfunArr;
	return 0;
}

8. Función de devolución de llamada

Una función de devolución de llamada es una función que se llama a través de un puntero de función. Si pasa un puntero de función (dirección) como parámetro a otra función, cuando este puntero se usa para llamar a la función a la que apunta, decimos que se trata de una función de devolución de llamada. El implementador de la función no llama directamente a la función de devolución de llamada, sino que la llama otra parte cuando ocurre un evento o condición específicos, y se usa para responder al evento o condición.

Tomemos como ejemplo la función qsort de la función de biblioteca, veamos primero la definición de esta función

_ACRTIMP void __cdecl qsort(
    _Inout_updates_bytes_(_NumOfElements * _SizeOfElements) void*  _Base,
    _In_                                                    size_t _NumOfElements,
    _In_                                                    size_t _SizeOfElements,
    _In_                _CoreCrtNonSecureSearchSortCompareFunction _CompareFunction
    );

inserte la descripción de la imagen aquí
El primer parámetro formal es void* porque puede acomodar punteros de cualquier tipo. El
último _CoreCrtNonSecureSearchSortCompareFunction _CompareFunction es en realidad una función de devolución de llamada. Cuando usamos la función qsort, necesitamos escribir otra función _CompareFunction para clasificar diferentes tipos. .
Ejemplo:

#include<stdlib.h>
#include <stdio.h>
int int_cmp(const void* p1, const void* p2)
{
    
    
	return (*(int*)p1 - *(int*)p2);
}
int main()
{
    
    
	int arr[] = {
    
     1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
	int i = 0;

	qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);
	for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
    
    
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}

Entre ellos, la función int_cmp es _CoreCrtNonSecureSearchSortCompareFunction _CompareFunction llamada por qsort
inserte la descripción de la imagen aquí
. Cabe señalar que este método de escritura predeterminado generalmente está en orden ascendente. Si desea cambiarlo a orden descendente, puede intercambiar p1 y p2, como se muestra en la siguiente código:

int int_cmp(const void* p1, const void* p2)
{
    
    
	return (*(int*)p2 - *(int*)p1);
}

Veamos la clasificación de la matriz de estructura.

#include<stdlib.h>
#include <stdio.h>
#include <string.h>
struct Stu
{
    
    
	char name[20];
	int age;
};

int cmp_stu_by_age(const void* p1, const void* p2)
{
    
    
	return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}

void test1()
{
    
    
	struct Stu arr[] = {
    
     {
    
    "zhangsan", 20}, {
    
    "lisi", 50},{
    
    "wangwu", 15} };
	int sz = sizeof(arr) / sizeof(arr[0]); 
	printf("初始序列:> ");
	for (int i = 0; i < sz; i++)
	{
    
    
		printf("%s,%d     ", arr[i].name, arr[i].age);
	}
	printf("\n");
	qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
	printf("按年龄排序:> ");
	for (int i = 0; i < sz; i++)
	{
    
    
		printf("%s,%d     ", arr[i].name, arr[i].age);
	}
	printf("\n");
}

int cmp_stu_by_name(const void* p1, const void* p2)
{
    
    
	return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}

void test2()
{
    
    
	struct Stu arr[] = {
    
     {
    
    "zhangsan", 20}, {
    
    "lisi", 50},{
    
    "wangwu", 15} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
	printf("按名字排序:> ");
	for (int i = 0; i < sz; i++)
	{
    
    
		printf("%s,%d     ", arr[i].name, arr[i].age);
	}
}

int main()
{
    
    
	test1();
	test2();
	return 0;
}

inserte la descripción de la imagen aquí
De acuerdo con el mismo principio, también podemos escribir una función de devolución de llamada de tipo burbuja que se adapte a múltiples tipos.
Ejemplo:

#include<stdio.h>
void Swap(void* p1, void* p2, int size)
{
    
    
	for (int i = 0; i < size; i++)
	{
    
    
		char tmp = *((char*)p1 + i);
		*((char*)p1 + i) = *((char*)p2 + i);
		*((char*)p2 + i) = tmp;
	}
}
void Bubble_Sort(void* base, int num, int size, int(*cmp)(void*,void*))
{
    
    
	int i = 0;
	int j = 0;
	for (i = 0; i < num - 1; i++)
	{
    
    
		for (j = 0; j < num - i - 1; j++)
		{
    
    
			if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
				Swap((char*)base + j * size, (char*)base + (j + 1) * size,size);
		}
	}
}

int Int_Sort(const void* p1, const void* p2)
{
    
    
	return *(int*)p1 - *(int*)p2;
}
void Int_Print(int* arr,int sz)
{
    
    
	for (int i = 0; i < sz; i++)
		printf("%d ", arr[i]);
}

void Test1()
{
    
    
	int arr[] = {
    
     7,6,5,4,8,9,3,1,2 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("初始序列:> ");
	Int_Print(arr, sz);
	printf("\n");
	Bubble_Sort(arr, sz, sizeof(arr[0]), Int_Sort);
	printf("排序后  :> ");
	Int_Print(arr,sz);
}

int main()
{
    
    
	Test1();
	return 0;
}

inserte la descripción de la imagen aquí

9. Análisis de las preguntas de la prueba de puntero y pluma de matriz

Todos los siguientes códigos están compilados para la plataforma 64

9.1 Arreglos unidimensionales

int a[] = {
    
    1,2,3,4};
printf("%d\n",sizeof(a));//sizeof中数组名代表整个数组
printf("%d\n",sizeof(a+0));//数组名+0为第一个元素的地址,也就是指针,指针大小就是4/8个字节,当前为64位,所以是8
printf("%d\n",sizeof(*a));//对数组名进行解引用操作,获取指向数组第一个元素
printf("%d\n",sizeof(a+1));//a+1代表第二个元素的地址
printf("%d\n",sizeof(a[1]));//代表第二个元素
printf("%d\n",sizeof(&a));//对数组名取地址,代表的是指针
printf("%d\n",sizeof(*&a));//&再*解引用等于没做操作,还是整个数组
printf("%d\n",sizeof(&a+1));//对数组名取地址再+1代表的是该数组之后的地址
printf("%d\n",sizeof(&a[0]));//代表第一个元素的地址
printf("%d\n",sizeof(&a[0]+1));//代表第二个元素的地址

inserte la descripción de la imagen aquí

9.2 Matrices de caracteres

char arr[] = {
    
    'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));//整个数组
printf("%d\n", sizeof(arr+0));//数组名+0为第一个元素的地址
printf("%d\n", sizeof(*arr));//对数组名进行解引用操作,获取指向数组第一个元素
printf("%d\n", sizeof(arr[1]));//数组第二个元素
printf("%d\n", sizeof(&arr));//整个数组的地址
printf("%d\n", sizeof(&arr+1));//该数组之后的地址
printf("%d\n", sizeof(&arr[0]+1));//代表第二个元素的地址

inserte la descripción de la imagen aquí

char arr[] = {
    
     'a','b','c','d','e','f' };
printf("%d\n", strlen(arr));//因为字符数组arr中没有\0,所以在求字符串长度的时候,会一直往后找,产生的结构就是随机值
printf("%d\n", strlen(arr+0));//arr + 0是首元素的地址,和第一个一样,也是随机值
//printf("%d\n", strlen(*arr));//错误, arr是数组首元素的地址,*arr就是数组首元素,就是'a'-97
//strlen函数参数的部分需要传一个地址,当我们传递的是'a'时,'a'的ASCII码值是97,那就是将97作为地址传参
//strlen就会从97这个地址开始统计字符串长度,这就非法访问内存了
//printf("%d\n", strlen(arr[1]));//错误,同上,只不过这里传的是第二个元素b
printf("%d\n", strlen(&arr));//&arr是数组的地址,数组的地址和数组首元素的地址,值是一样的,那么传递给strlen函数后,依然是从数组的第一个元素的位置开始往后统计
printf("%d\n", strlen(&arr+1));//随机值-6,减去了上面6个元素的长度
printf("%d\n", strlen(&arr[0]+1));//&arr[0] + 1是第二个元素的地址。结果也是随机值

inserte la descripción de la imagen aquí

char arr[] = "abcdef";
printf("%d\n", sizeof(arr));//整个数组
printf("%d\n", sizeof(arr + 0));//arr + 0是首元素的地址
printf("%d\n", sizeof(*arr));//*arr其实就是首元素,1个字节
printf("%d\n", sizeof(arr[1]));//arr[1]是第二个元素,1个字节
printf("%d\n", sizeof(&arr));//&arr是数组的地址,是地址就是4/8个字节
printf("%d\n", sizeof(&arr + 1));//&arr + 1是跳过一个数组的地址,4/8
printf("%d\n", sizeof(&arr[0] + 1));//&arr[0] + 1是第二个元素的地址 4/8

inserte la descripción de la imagen aquí

char arr[] = "abcdef";
printf("%d\n", strlen(arr));//整个字符串的长度
printf("%d\n", strlen(arr+0));//首元素的地址开始,所以结果同上
//printf("%d\n", strlen(*arr));//错误, arr是数组首元素的地址,*arr就是数组首元素
//printf("%d\n", strlen(arr[1]));//错误,同上,只不过这里传的是第二个元素b
printf("%d\n", strlen(&arr));//整个数组的地址,还是从首元素开始
printf("%d\n", strlen(&arr+1));//整个数组后开始计算,所以是随机值
printf("%d\n", strlen(&arr[0]+1));//从第二个元素地址开始算

inserte la descripción de la imagen aquí

9.3 Punteros de caracteres

También se puede decir que es una matriz de caracteres, y la matriz en sí también es un puntero.

char *p = "abcdef";
printf("%d\n", sizeof(p));//p为指针变量,大小为4/8
printf("%d\n", sizeof(p+1));//p+1是'b'的地址
printf("%d\n", sizeof(*p));//*p 就是字符a
printf("%d\n", sizeof(p[0]));//同上
printf("%d\n", sizeof(&p));//*p的地址
printf("%d\n", sizeof(&p+1));//*p之后的地址
printf("%d\n", sizeof(&p[0]+1));//&p[0] + 1得到是'b'的地址

inserte la descripción de la imagen aquí

char *p = "abcdef";
printf("%d\n", strlen(p));//正常计算一个字符串的长度
printf("%d\n", strlen(p+1));//从第二个字符开始算
//printf("%d\n", strlen(*p));//错误,传的是首元素
//printf("%d\n", strlen(p[0]));//错误,同上
printf("%d\n", strlen(&p));//从首元素的地址中计算,是随机值,不确定的,和分配的地址有关
printf("%d\n", strlen(&p+1));//同上也是随机值
printf("%d\n", strlen(&p[0]+1));//从第二个字符开始算

inserte la descripción de la imagen aquí

9.4 Arreglos bidimensionales

int a[3][4] = {
    
    0};
printf("%d\n",sizeof(a));//整个数组
printf("%d\n",sizeof(a[0][0]));//首元素
printf("%d\n",sizeof(a[0]));//第一行
printf("%d\n",sizeof(a[0]+1));
//a[0]作为第一行的数组名,没有单独放在sizeo内部,没有&
//a[0]表示数组首元素的地址,也就是a[0][0]的地址
//所以a[0]+1是第一行第二个元素的地址,是地址就是4/8个字节

inserte la descripción de la imagen aquí

int a[3][4] = {
    
     0 };
printf("%d\n", sizeof(*(a[0] + 1)));//计算的是就是第一行第2个元素的大小
printf("%d\n", sizeof(a + 1));//a是数组首元素的地址,是第一行的地址 int(*)[4],a+1 就是第二行的地址
printf("%d\n", sizeof(*(a + 1)));//计算的是第二行的大小
printf("%d\n", sizeof(&a[0] + 1));//&a[0]是第一行的地址 int(*)[4],&a[0]+1 是第二行的地址 int(*)[4]
printf("%d\n", sizeof(*(&a[0] + 1)));//计算的是第二行的大小
printf("%d\n", sizeof(*a));//计算的是第一行的大小
printf("%d\n", sizeof(a[3]));//计算的是一行的大小,并不存在越界,因为实际并没有访问内存

inserte la descripción de la imagen aquí
Resumen :
El significado del nombre de la matriz:

  1. sizeof(nombre de la matriz), donde el nombre de la matriz representa la matriz completa y el cálculo es el tamaño de la matriz completa.
  2. &Nombre de la matriz, donde el nombre de la matriz representa la matriz completa y se elimina la dirección de la matriz completa.
  3. Además, todos los nombres de las matrices representan la dirección del primer elemento.

10. Preguntas de la prueba de la pluma del puntero

10.1 Pregunta de prueba escrita 1

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

¿Cuál es el resultado del procedimiento?
inserte la descripción de la imagen aquí
El segundo elemento al que se accede mediante *(a + 1), *ptr es la dirección después de omitir toda la matriz

10.2 Pregunta de prueba escrita 2

struct Test
{
    
    
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p= (struct Test*)0x10000000;
int main()
{
    
    
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);
	return 0;
}

Supongamos que el valor de p es 0x10000000. ¿Cuáles son los valores de las siguientes expresiones?
Se sabe que el tamaño variable de la estructura Tipo de prueba es de 20 bytes.
inserte la descripción de la imagen aquí
El primer resultado es omitir toda la estructura, por lo que sumar 20 directamente, y la dirección se imprime en hexadecimal, por lo que es 10000014. El
segundo resultado es el primero. add La dirección de la estructura se convierte en un entero largo, y el cálculo del entero se suma directamente por 1. El
tercer resultado es convertir primero la dirección de la estructura en un puntero, y al agregar 1 se omite el tamaño de un puntero. , es decir, 4/8 bytes

10.3 Pregunta de prueba escrita 3

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;
}

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

10.4 Pregunta de prueba escrita 4

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

inserte la descripción de la imagen aquí
Cabe señalar aquí que durante la inicialización, solo inicializamos los primeros 3 valores, porque hay () en lugar de {}, por lo que solo los números en la expresión de coma, es decir, 1, 3, 5, y luego todo debe ser 0; así que al imprimir el valor que apunta a la primera línea, solo imprima a[0][0], que es 1.

10.5 Pregunta de prueba escrita 5

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;
}

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

10.6 Pregunta de prueba escrita 6

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;
}

inserte la descripción de la imagen aquí
&aa+1 omite la matriz completa, por lo que -1, el valor entero impreso es el último elemento de la matriz aa aa
+1 omite la primera línea de la matriz bidimensional, que es la dirección inicial de 6, por lo que - 1. El valor entero impreso es el último elemento de la primera línea de la matriz aa

10.7 Pregunta de prueba escrita 7

int main()
{
    
    
	char* a[] = {
    
     "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);
	return 0;
}

inserte la descripción de la imagen aquí
Primero, char* a[] almacena la dirección de las primeras tres letras, y char** pa almacena la dirección del primer elemento w en la matriz de punteros, por lo que pa++, pa apunta a la dirección del segundo elemento a, desreferenciando After la impresión está en.

10.8 Prueba escrita Pregunta 8

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;
}

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

epílogo

Los amigos interesados ​​​​pueden prestar atención al autor, si cree que el contenido es bueno, haga un enlace triple con un clic, ¡cangrejo cangrejo! ! !
No es fácil de hacer, por favor señale si hay alguna inexactitud
Gracias por su visita, ver UU es la motivación para perseverar.
Con el catalizador del tiempo, ¡seamos mejores personas los unos de los otros! !
inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/kingxzq/article/details/131613390
Recomendado
Clasificación