Linguagem C - versão completa de ponteiros

Índice

1. Operações de ponteiro

1.1 ponteiro +- inteiro

1.2 Ponteiros - Ponteiros

1.3 ponteiro vazio*

2. Percurso do ponteiro da matriz

2.1 Percurso de ponteiro do array

1. Compreenda o significado dos nomes dos arrays (e a diferença entre nomes de arrays e nomes de arrays).

2. Percorra o array usando ponteiros 

3. Matriz de ponteiro, ponteiro de matriz, ponteiro de função

3.1 Matriz de ponteiros

3.1.1 Forma de array de ponteiros

3.1.2 Casos de uso de matrizes de ponteiros

3.2 Ponteiro de matriz

3.3 Ponteiros de função

3. Matriz de ponteiros de função

3.1 Forma de array de ponteiros de função

3.2 Objetivo da matriz de ponteiros de função: tabela de transferência

4. Matriz como parâmetro do corpo da função

5. Use arrays como valores de retorno em funções

5.1 Retornar o endereço de um array local estático

5.2 Retorne o endereço da string na área constante literal

5.3 Retorne o endereço do conteúdo do heap

5.4 Resumo


1. Operações de ponteiro

1.1 ponteiro +- inteiro

Resumo: O tipo de ponteiro determina a distância (distância) em que o ponteiro se move para frente ou para trás.

1.2 Ponteiros - Ponteiros

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

Quando queremos usar dois ponteiros para subtrair, podemos adivinhar pela imagem acima: a saída é o número de elementos entre os dois endereços ou a diferença (byte) entre os dois endereços?

Ao executar podemos saber que o resultado do ponteiro - ponteiro: o número de elementos entre o ponteiro e o ponteiro.

Então, quaisquer dois ponteiros podem ser subtraídos? Das respostas acima podemos obter:

Ponteiro - A premissa do ponteiro : dois ponteiros apontam para a mesma área e o tipo de ponteiro é o mesmo.

Portanto, se usarmos um ponteiro pequeno - um ponteiro grande, nosso resultado será -9.

Portanto, podemos obter uma conclusão mais rigorosa:

Ponteiro - o resultado de um ponteiro : seu valor absoluto é o número de elementos entre os ponteiros.

1.3 ponteiro vazio*

Ponteiros do tipo void* não podem ser usados ​​para operadores de desreferência, nem para operações + - inteiras.

Um ponteiro do tipo void* é usado para armazenar o endereço de qualquer tipo de dado.

void* Ponteiro sem tipo concreto

Você pode usar ponteiros void* para receber ponteiros de qualquer tipo. Se precisar desreferenciar um ponteiro void*, você pode lançá-lo.

2. Percurso do ponteiro da matriz

2.1 Percurso de ponteiro do array

1. Compreenda o significado dos nomes dos arrays (e a diferença entre nomes de arrays e nomes de arrays).

O nome do array é o endereço do primeiro elemento do array. Existem duas exceções:
1. sizeof(nome do array), calcula o tamanho de todo o array, sizeof coloca um nome de array separado dentro e o nome do array representa o array inteiro.
2. & array name retira o endereço do array. & nome do array, o nome do array representa o array inteiro.
Exceto nos dois casos 1 e 2, todos os nomes de array representam o endereço do primeiro elemento do array.

Vejamos um trecho de código para entender a diferença entre & nome do array e nome do array.

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

De acordo com o código acima, descobrimos que, na verdade, embora os valores de &arr e arr sejam iguais, seus significados deveriam ser diferentes.
Na verdade: &arr representa o endereço do array , não o endereço do primeiro elemento do array.
O endereço do array é +1 , ignorando o tamanho de todo o array, então a diferença entre &arr+1 e &arr é 40.

2. Percorra o array usando ponteiros 

Como o nome do array pode ser armazenado em um ponteiro como um endereço, torna-se possível usar um ponteiro para acessá-lo.

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

 Como você pode ver, podemos percorrer cada elemento do array através de um ponteiro:

p+i na verdade calcula o endereço do array arr com índice i .
Então *(p+1) pode acessar cada elemento do array arr .

3. Matriz de ponteiro, ponteiro de matriz, ponteiro de função

3.1 Matriz de ponteiros

Uma matriz de ponteiros é uma matriz que armazena ponteiros.

3.1.1 Forma de array de ponteiros

Vamos primeiro dar uma olhada na aparência de um array de ponteiros (o mesmo se aplica a outros tipos):

int* arr[5];    //数组名称:arr  数组元素个数:5  数组元素的类型:int* 

Então, qual é a utilidade de conhecer uma série de ponteiros?

3.1.2 Casos de uso de matrizes de ponteiros

Já sabemos que o nome do array representa o endereço do primeiro elemento do array na maioria dos casos, então podemos usar um array de ponteiros para simular um array bidimensional.

int arr1[] = { 0,1,2,3,4,5 };
int arr2[] = { 1,2,3,4,5,6 };
int arr3[] = { 2,3,4,5,6,7 };

int* arr[] = { arr1,arr2,arr3 };

Então, como devemos usar esse array bidimensional simulado?

Podemos acessá-lo diretamente usando seu subscrito.

a diferença:

A diferença entre nossa matriz simulada e uma matriz bidimensional real é que o endereço do elemento de cada elemento da matriz bidimensional real é contínuo, enquanto o endereço da matriz unidimensional de cada matriz unidimensional da matriz bidimensional simulada matriz não é contínua.

3.2 Ponteiro de matriz

Um ponteiro de array é um ponteiro para um array.

int(*p)[10];
	/*
	解释:p先和 * 结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。
	所以p是一个指针,指向一个数组,叫数组指针。
	*/
	//这里要注意:[]的优先级要高于*号的,所以必须加上()来保证p先和*结合。

Sabemos que inteiro, ponto flutuante de precisão total, etc., todos têm um tipo de dados, int, double... Claro, aqui, o ponteiro do array também tem seu tipo de dados.

3.3 Ponteiros de função

Vamos dar uma olhada em um trecho de código primeiro

#include <stdio.h>
void test()
{
 printf("hello!\n");
}
int main()
{
 printf("%p\n", test);//打印test地址
 printf("%p\n", &test);//打印&test地址
 return 0;
}

A partir dos resultados da execução, podemos ver que o nome da função e o nome do array realmente têm o mesmo efeito.No entanto, para conveniência de observação, quando precisarmos do endereço da função no futuro, ainda usaremos & nome da função para implementá- lo .

Se quisermos usar um ponteiro para armazenar a função de teste acima, o que devemos fazer?

void(*pf)() = &test;
pf1 é primeiro combinado com *, indicando que pf1 é um ponteiro. O ponteiro aponta para uma função. A função apontada não tem parâmetros e o tipo de valor de retorno é nulo.

Do exposto podemos obter:

int max(int a, int b)
{
	if (a > b)
		return a;
	else
		return b;
}
int main()
{
	int (*pf2)(int, int) = &max;
	return 0;
}

Desta forma, podemos entender claramente a forma dos ponteiros de função.

3. Matriz de ponteiros de função

3.1 Forma de array de ponteiros de função

Um array é um espaço de armazenamento que armazena dados do mesmo tipo. Já aprendemos sobre arrays de ponteiros.
por exemplo:
int * arr [ 10 ];
// Cada elemento do array é int*
Então precisamos armazenar o endereço da função em um array. Então esse array é chamado de array de ponteiros de função. Como definir o array de ponteiros de função?
(Tome o int max(int ​​​​a, int b) acima como exemplo, assumindo que a matriz de ponteiros de função armazena tais funções)
int ( * parr [ 10 ])( int, int );
Parr é primeiro combinado com [], e parr parece ser um array.
Qual é o conteúdo da matriz?
É um ponteiro de função do tipo int (*)(int, int) .

3.2 Objetivo da matriz de ponteiros de função: tabela de transferência

Vamos pegar uma calculadora simples como exemplo para ver a conveniência de usar uma matriz de ponteiros de função.
O que preparar:
Quando a matriz de ponteiros de função não é usada, precisamos chamar uma função, uma por uma, de acordo com a entrada do usuário:
Depois de usar o array de funções, precisamos apenas encapsular todas as quatro funções na fase de preparação em um array de ponteiros de função:

Na próxima vez que usarmos, podemos usá-lo com flexibilidade:

Não é muito simplificado?

4. Matriz como parâmetro do corpo da função

Ao definir o corpo da função,quando o parâmetro é um array,ele pode ser recebido usando um array ou um ponteiro.O uso do recebimento do array não tem nada a ver com o subscrito do elemento do array.

5. Use arrays como valores de retorno em funções

Retornar um array é, na verdade, retornar um ponteiro.

char* fun()
{
	char str[100] = "hello world!";
	return str;
}
int main()
{
	char* pf;
	pf = fun();

	printf("%s\n", pf);

	return 0;
}

5.1 Retornar o endereço de um array local estático

O código acima tem uma falha óbvia:

str é criado no corpo da função fun e é uma variável temporária. Quando queremos usar pf para recebê-lo na função principal, str foi destruído. Neste momento, podemos modificar nosso str com static na função fun para estender isso. seu ciclo de vida.

A operação é conforme mostrado na figura:

5.2 Retorne o endereço da string na área constante literal

Uma string constante é uma constante e sempre existe.

5.3 Retorne o endereço do conteúdo do heap

arquivo de cabeçalho malloc:

#include<stdlib.h>

malloc aplica-se dinamicamente à memória para str, o tamanho é 100 e a unidade é bytes. A memória alocada dinamicamente não será liberada após o término da função.

O conteúdo da área de heap sempre existe até ser liberado.

5.4 Resumo

O endereço retornado e o conteúdo da memória apontado pelo endereço devem existir para serem significativos.

Acho que você gosta

Origin blog.csdn.net/m0_75186846/article/details/132081257
Recomendado
Clasificación