A explicação mais detalhada dos ponteiros

ponteiro

1. Definição da variável de ponteiro

Existem dois tipos de variáveis ​​na linguagem C, incluindo variáveis ​​comuns (variáveis ​​de conteúdo) e variáveis ​​de endereço (variáveis ​​de ponteiro). Variáveis ​​comuns (variáveis ​​de conteúdo) armazenam conteúdo e variáveis ​​de endereço (variáveis ​​de ponteiro) armazenam endereços.

  1. formato definido

格式: tipo * nome da variável do ponteiro

//普通变量
int a;
//地址变量
int *a;

Observação:

① Definir variáveis ​​(variáveis ​​comuns, variáveis ​​de ponteiro) deve ter um nome de tipo na frente

② Ao definir uma variável de ponteiro, o símbolo antes do nome da variável de ponteiro "*"indica que uma variável do tipo ponteiro está definida no momento.“*”nãoParte do nome da variável do ponteiro é apenas um sinalizador.

③ As variáveis ​​de ponteiro são usadas especialmente para armazenar endereços e é proibido atribuir diretamente um número inteiro a uma variável de ponteiro.

  1. referência a variável de ponteiro

“&”Pegue o operador de endereço, o endereço &de variáveis ​​comuns pode ser obtido por meio do operador
.
*Operador de ponteiro, *você pode tirar o valor da variável comum apontada pela variável de ponteiro
, (refere-se indiretamente à variável comum)

exemplo:

#include<stdio.h>
int main(){
    
    
	int a=4,b=0;
	int *p,*q,*t;
	p=&a;    //取出变量a的地址
	b=*p;
	 
	printf("a=%d\nb=%d\n*p=%d\n",a,b,*p);
	printf("\n\n\n");
	printf("a的地址为:%p\nb的地址为:%p\np的地址为:%p",&a,&b,p);
	return 0;	
}
//运行结果:
a=4
b=4
*p=4
a的地址为:000000000062FE14
b的地址为:000000000062FE10
p的地址为:000000000062FE14
--------------------------------
Process exited after 0.0017 seconds with return value 0

Diagrama de operação:

insira a descrição da imagem aqui

Observação:

① Você pode atribuir uma variável de ponteiro para "apontar" para uma variável comum (variável de ponteiro=&variável comum)

②A abordagem correta na linguagem C é deixar a variável de ponteiro apontar para uma determinada unidade de armazenamento primeiro e, em seguida, usar a variável de ponteiro para se referir à unidade de armazenamento para a qual ela aponta.

③ Todos os nomes de variáveis ​​(variáveis ​​comuns, variáveis ​​de ponteiro) representam o valor em sua unidade de armazenamento.

④ Se a variável de ponteiro p aponta para a variável a, o endereço da variável a é atribuído à variável de ponteiro p.

⑤ Todas as variáveis ​​de ponteiro têm o mesmo número de bytes alocados na memória.

//关于第五条的解释
#include<stdio.h>
int main(){
    
    
	int *p;
	double *q;
	float *t;
	char *r;
	printf("\t int *p = %d\n",sizeof(p));
	printf("\t double *q = %d\n",sizeof(q));
	printf("\t float *t = %d\n",sizeof(t));
	printf("\t char *r = %d\n",sizeof(r));
	return 0;	
}

resultado da operação:

insira a descrição da imagem aqui

2. Ponteiro de matriz

Como os elementos do array são iguais às variáveis ​​comuns, definir uma variável de ponteiro apontando para um elemento de array é exatamente o mesmo que definir uma variável de ponteiro apontando para uma variável comum

int *p;
int a[10];
//a é o primeiro endereço do array, ou seja, a <=> &a[0];
p=a; equivalente p=&a[0];
p=a+1 equivalente p= &(a+1)

O nome do array é o primeiro endereço do array

//上述等价的实例
#include<stdio.h>
int main(){
    
    
	int a[10];
	int *p,*q;
	p=&a[1];
	q=a+1; 
	printf("%p\n",p);
	printf("%p\n",q);
}

resultado da operação:

insira a descrição da imagem aqui

Observação:

① Está estipulado na linguagem C: o nome do array representa o primeiro endereço do array, e é uma constante de endereço.

②Quando a variável de ponteiro aponta para um elemento na matriz, a variável de ponteiro aponta para o próximo elemento da matriz após ser aumentada em 1 e aponta para o elemento anterior na matriz quando a variável de ponteiro é decrementada em 1.

③ Quando a variável de ponteiro aponta para uma matriz, a operação de subscrito ([]) pode ser usada após a matriz ou após a variável de ponteiro

④ Se duas variáveis ​​de ponteiro apontam para o mesmo array, as duas variáveis ​​de ponteiro podem ser comparadas em tamanho como

⑤ A matriz no parâmetro formal é na verdade uma variável de ponteiro, não uma matriz real, porque o valor do "nome da matriz" pode ser alterado, mas o valor do nome da matriz real não pode ser alterado.

⑥ Se o parâmetro formal for uma matriz ou variável de ponteiro, o valor do parâmetro real pode ser alterado na função através do parâmetro formal

Exemplo 1:

insira a descrição da imagem aqui

Resposta e análise:

insira a descrição da imagem aqui

Exemplo 2:

//运行结果是什么?
#include<stdio.h>
int main() {
    
    
	int *p,a[3];
	p=a;  //将数组a的首地址,赋值给指针p 
	for(int i=0; i<3; i++) {
    
    
		scanf("%d",p++); //因为数组名就是地址,所以不用加取地址符 
	}
	printf("\n\n");
	
	for(p=a;p<a+3;){
    
      //将数组a的首地址,赋值给指针p 
		printf("%d ",*p++); //没输出一次,就向后移动一位 
	} 
	return 0;
}

resultado da operação:

insira a descrição da imagem aqui

3. Variáveis ​​de ponteiro apontando para arrays multidimensionais

Ⅰ. A diferença entre um ponteiro e um ponteiro

Por exemplo: em int a[3], a+1o que é adicionado é um elemento, int a[3][4], o que a+1é adicionado é uma linha, conforme a figura abaixo
insira a descrição da imagem aqui

Lembrar:

① Somente ponteiros de coluna "realmente" apontam para elementos. Ou seja, uma unidade de armazenamento que aponta para um elemento.
② O nome da matriz unidimensional representa o ponteiro da coluna; o nome da matriz bidimensional representa o ponteiro da linha.

Nota: Se a for um array bidimensional, então existem

a+ié um ponteiro de linha, ou seja, uma linha inteira apontada. Se você adicionar 1 a ele, ele apontará para a próxima linha.

*(a+i)Igual a[i]a , é um ponteiro de coluna que aponta para um elemento.

*(a+i)+jé a[i]+jigual a , ambos representam a[i][j]o endereço do elemento, ou seja, equivale &a[i][j]a . *(a+i)+j= a[i]+j= &a[i][j].

*(*(a+i)+j), *(a[i]+j), (*(a+i))[j]e a[i][j]o mesmo, todos representam elementos a[i][j].

Exemplo 1:

Dadas as seguintes definições: int w[2][3]então uma referência ilegal a w é:

A, *(w[0]+2)B, *(w+1)[2]C, w[0][0]D, *(w[1]+2)E,w[1]+2

Análise: A representa o w[0][2]elemento Sim, C representa o elemento w[0][0]D representa o w[1][2]elemento Sim, E representa o elemento Sim, &w[1][2]ou seja, E é um endereço e não um elemento.

Em B, w refere-se w[0][0]ao endereço, então w+1 refere-se a descer uma linha, *(w+1)[2]ou seja, descer duas linhas, então o w[3][0]elemento representado, mas porque int w[2][3]B está fora dos limites

Exemplo 2:

int a[3][4]; int *p=&a[0][3];

mas:

p+1 aponta para o elemento?

p+4 aponta para o elemento?

p-2 aponta para o elemento?

Comumente usado para obter o endereço do array bidimensional um elemento?

analise como abaixo:

insira a descrição da imagem aqui

Exemplo 3:

Imprima uma matriz bidimensional a[4][4](apenas um loop for pode ser usado)

#include<stdio.h>
int main() {
    
    
	int a[4][4] = {
    
    
		{
    
    1, 2, 3, 4},
		{
    
    5, 6, 7, 8},
		{
    
    9, 10, 11, 12},
		{
    
    13,14,15,16}
	};
	int *p;
	for(p=a[0]; p<a[0]+12; p++) {
    
    
		printf("%d ",*p);
	}
	return 0;
}

resultado da operação:

insira a descrição da imagem aqui

Variável de ponteiro para uma matriz unidimensional de m elementos

Ⅱ . Uma variável de ponteiro apontando para uma matriz unidimensional composta por m elementos

Defina o formato de uma variável de ponteiro apontando para uma matriz unidimensional de m elementos:

Tipo (* nome da variável do ponteiro) [m]

variável de ponteiro de linha

como:

int a[5][7];
int (*p)[7];
p=a;

char b[ 10][80];
char (*r)[80];
r=b+5;

O código de análise de pseudocódigo acima é o seguinte:

/*
int a[5][7];
int (*p)[7];
p=a;
 */

#include<stdio.h>
int main() {
    
    
	int a[4][4];  //定义一个二维数组
	int (*p)[4];  //定义一个一维数组的指针变量,也就是说该数组是指向某一行第四列的一维数组
	int *c;       //普通的指针变量
	p=a;          //将二维数组的首地址赋值给p,也就是说此时的p是指向的a的首行,且(*p)[4]等价于p[0][4]
	printf("%p\n%p\n",a,p);   //打印数组a的首地址和p的首地址
	printf("%d ",sizeof(a));  //打印数组a所占的空间,也就是二维数组a[4][4]所占的空间
	printf("%d ",sizeof(*p)); //打印数组p所占的空间,也就是一维数组p[0][4]所占的空间
	printf("%d ",sizeof(c));  //打印指针变量(地址变量)c所占的空间,
	printf("\n\n");
 	return 0;
}

Os resultados impressos são os seguintes:

insira a descrição da imagem aqui

/*
char b[ 10][80];
char (*r)[80];
r=b+5;
*/

#include<stdio.h>
#include<string.h>
int main() {
    
    
	char b[10][80];  //定义一个二维数组
	char (*r)[80];   //定义一个一维数组的指针变量,也就是说该数组是指向某一行第八十列的一维数组
	r=b+5;			//将b[0][0]向下移动五行再赋值给r,也就是将a[5][0]的地址赋值给r。
	printf("%p\n%p\n",r,b[5]); //打印地址
	printf("%d ",sizeof(*r));  //查看空间
	printf("%d ",sizeof(b[5]));//查看空间
	return 0;
}

Os resultados impressos são os seguintes:
insira a descrição da imagem aqui

Exemplo 1:

Quais resultados serão impressos quando o código a seguir for executado e escrever outro método de impressão de um loop for e escrever o código de p=a+1; e o que será impresso?

#include<stdio.h>
int main() {
    
    
	int a[3][4]= {
    
    1,2,3,4,5,6,7,8,9,10,11,12};
	int (*p)[4];
	p=a;
	int *q;
	for(int i=0; i<3; i++) {
    
    
		for(int j=0; j<4; j++) {
    
    
			printf("%d\t",p[i][j]);
		}
		printf("\n");
	}
	return 0;
}

Resposta e análise:

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

	int a[3][4]= {
    
    1,2,3,4,5,6,7,8,9,10,11,12};
	int (*p)[4];
	p=a;
	int *q;
	for(int i=0; i<3; i++) {
    
    
		for(int j=0; j<4; j++) {
    
    
			printf("%d\t",p[i][j]);
		}
		printf("\n");
	}
	printf("\n\n");
	
	//一层for循环打印二维数组 
	for(q=a[0];q<a[0]+12;q++){
    
    
		printf("%d  ",*q);
	}
	printf("\n\n");
	
	
	//打印p=a+1,回打印出什么 
	p=a+1;
	for(int i=0; i<2; i++) {
    
    
		for(int j=0; j<4; j++) {
    
    
			printf("%d\t",p[i][j]);
		}
		printf("\n");
	}
	return 0;
}

Resultados de execução (combinados com os pontos de conhecimento acima para auto-análise):

insira a descrição da imagem aqui

Exemplo 2:

O que será impresso quando o seguinte código for executado?

#include<stdio.h>
main() {
    
    
	int a[2][3]= {
    
    {
    
    1,2,3},{
    
    4,5,0} },(*pa)[3];
	int i;
	pa=a;
	for(int i=0;i<3;i++){
    
    
		if(i<2){
    
    	
			pa[1][i]=pa[1][i]-1;
		}
		else {
    
    
			pa[1][i]=1;
		}
	}
	printf("%d\n",a[0][1]+a[1][1]+a[1][2]);
}

Resposta e análise:

insira a descrição da imagem aqui

Quarto, a variável de ponteiro apontando para a string

Constantes de string: a linguagem C trata as constantes de string de acordo com o primeiro endereço

Como é um ponteiro, o princípio das variáveis ​​de ponteiro deve ser seguido.Ao mesmo tempo, sabemos que uma constante de string é uma constante, então ela não pode ser escrita no lado esquerdo do número de atribuição.

Para a string char *p="abc"

①Primeiro endereço

② Constante de endereço "abc"

③O endereço do primeiro caractere é armazenado em p

exemplo:

Quais dos seguintes códigos estão corretos e quais estão errados, indique e explique o motivo.

char str[]="China";char *p="China";     ✔   因为字符串是地址常量,所以正确

str = "Chinese";     ❌    str也是地址常量,不能放在赋值号的左边    

p="Chinese";         ✔    p是地址变量,字符串是地址常量,也是"C"的地址

char *q ={
    
    "China"};  ❌    加大括号是初始化,此时就不是地址常量了,所以错误

char s[]={
    
    "China"};  ✔    初始化,大括号可加可不加。所以✔

char *p;*p="china";*p是内容值,但是字符串是地址值,所以❌

5. Variáveis ​​de ponteiro apontando para funções

O nome da função é o mesmo que o nome da matriz, é o endereço inicial e é uma constante de endereço.

A maneira de definir uma variável de ponteiro de função:

typename(*nome da variável do ponteiro)();

exemplo:

Qual é o resultado da execução do seguinte código?

#include<stdio.h>
int min(int a,int b) {
    
    
	return a>b?b:a;
}
int max(int a,int b) {
    
    
	return a>b?a:b;
}
int main() {
    
    
	int x= 6,y=10;
	int (*p)(int a,int b);  //定义指向函数的指针变量
	p=max; 				   //将max函数的地址赋值给指向函数的指针变量
	printf("%d\n",max(x,y));
	printf("%d\n",p(x,y));
	p=min;				   //将min函数的地址赋值给指向函数的指针变量
	printf("%d\n",min(x,y));
	printf( "%d\n",p(x,y)); 
}

resultado da operação:
insira a descrição da imagem aqui

Observação:

(1) Ao definir uma variável ponteiro apontando para uma função, deve-se observar que deve haver dois parênteses e não há necessidade de definir parâmetros formais. Mas para alguns compiladores como devc++, parâmetros formais podem ter que ser definidos.

(2) Um único nome de função representa o primeiro endereço da função (o endereço de entrada da função).

(3) A variável de ponteiro da função só pode apontar para o ponto de entrada da função (o primeiro endereço da função) e não pode apontar para uma determinada instrução na função. (Também não faz sentido adicionar 1 a uma variável de ponteiro apontando para uma função).

(4) Ao atribuir um valor a uma variável de ponteiro apontando para uma função, escreva apenas o nome da função e não precise escrever parâmetros.

6. Funções que retornam ponteiros

Uma função que retorna um ponteiro é definida como:

nome do tipo * nome da função (lista de parâmetros) {

}

exemplo:

#include<stdio.h>
int *fun(int *x,int *y) {
    
    
	if(*x<*y)
		return x;
	else
		return y;
}
int main() {
    
    
	int a=7,b=8,*p,*q,*r;
	p=&a;
	q=&b;
	r=fun(p,q);
	printf("%d,%d,%d\n",*p,*q,*r);
	return 0; 
}



7,8,7

--------------------------------
Process exited after 0.1331 seconds with return value 0
请按任意键继续. . .

7. Arrays de ponteiros e variáveis ​​de ponteiros apontando para ponteiros

matriz de ponteiros

Se todos os elementos de uma matriz forem tipos de ponteiros (endereços), ela é chamada de matriz de ponteiros.

Formatar:

类型名 *数组名[常量表达式];

int *a[5];

Observação:

(1) Preste atenção na diferença entre definir uma variável de ponteiro apontando para uma matriz unidimensional composta por m elementos

类型名 *数组名[常量表达式];Em essência, é uma matriz unidimensional e as constantes de endereço são armazenadas na matriz.

类型名 (*指针名)[常量表达式m];Em essência, é uma matriz bidimensional, que é uma variável de ponteiro apontando para uma matriz unidimensional

(2) Cada um de seus elementos é um tipo de ponteiro (endereço), ou seja, cada um de seus elementos equivale a uma variável de ponteiro.

exemplo:

#include<stdio.h>
int main() {
    
    
	char ch[3][4]= {
    
    "123","456","78"},*p[3];
	int i;
	for(i=0; i<3; i++)
		p[i]=ch[i];
	for(i=0; i<3; i++){
    
    
		printf("p = %p \n" ,p[i]);
		printf("ch =%p\n" ,&ch[i][0]);
		printf("p = %s \n" ,p[i]);
		printf("ch =%s \n" ,ch[i]);
		printf("\n");
	}	
	return 0; 
}

Resultados e análises de execução:

insira a descrição da imagem aqui

variável de ponteiro para ponteiro

Uma variável de ponteiro usada para armazenar o endereço de uma variável de ponteiro é chamada de variável de ponteiro para um ponteiro.

Formato de definição:

nome do tipo **nome da variável do ponteiro;

int a=3;

int *p=&a;

int **k=&p;

Então: *k obtém a variável p (endereço da variável a). **k obtém o valor da variável a (dados 3 de a).

8. Ponteiro nulo

Uma variável de ponteiro pode ter um valor nulo, ou seja, uma variável de ponteiro não aponta para nenhuma variável e não se refere a nenhuma unidade de armazenamento útil.

NULL foi definido como 0 no sistema, ou seja, o valor de NULL é 0.

int a,b, C, *p=NULO;

Neste momento, o valor de p é um ponteiro nulo, ou seja, p não aponta para nenhuma unidade de armazenamento útil. Embora o valor de NU LL seja 0, não podemos pensar que p aponta para a unidade de memória cujo endereço é 0.

Observação:

(1) Quando o valor de uma variável de ponteiro é um ponteiro nulo, não podemos nos referir à unidade de armazenamento para a qual ele aponta.

(2) Se o tipo base de um ponteiro (endereço) for do tipo void, a substituição obrigatória do tipo correspondente deve ser realizada quando houver uma referência.

Nove. Resumo

Alguns pontos a serem observados sobre variáveis ​​de ponteiro

  1. Em int *a;, o nome da variável é a, não *aporque o nome da variável segue as regras de nomenclatura do nome da variável, ou seja, o sublinhado alfanumérico, e o número não pode começar, então o nome da variável da variável do ponteiro não é, é um nome do*a tipo int *, chamado de tipo de ponteiro.

  2. No int *a;, o a ocupa 8 bytes, claro *aque ocupa 4 bytes, pois *aé do tipo int, então tem 4 bytes, char *be o b nele também ocupa 8 bytes, mas *bocupa 1 byte. Portanto, não importa que tipo de variável de ponteiro de tipo base seja, ela ocupa 8 bytes e *指针变量ocupa os bytes desse tipo. (Vale ressaltar que os resultados de diferentes sistemas operacionais não são iguais, mas uma coisa é igual, ou seja, o número de bytes ocupados pela variável ponteiro é o mesmo, independente do tipo base).

  3. No ponteiro *e &, são operações inversas, &e []são recíprocas, ou seja, podem se anular, como

    int a[3]; 
    int b;
    int *a;
    int *p;
    a=&b;
    p=&a[0]; <=> p=a;
    p=&a[3]; <=> 
    p=a+3;
    
    &* 互逆
    
    *[] 等价
    
    &[] 互逆
    
  4. Existem cinco fórmulas para ponteiros

    ① Obtenha o endereço da variável de endereço e quem obtiver o endereço aponta para quem

    ② Há * como o valor do conteúdo, leia ou escreva, coloque-o no lado esquerdo do número da atribuição para escrever e os outros são lidos

    ③ Não há * como endereço, a atribuição do endereço significa alterar para

    ④ A variável ponteiro só pode ser usada depois de definida e inicializada

    ⑤ A variável de endereço armazena o endereço e a variável de conteúdo armazena o conteúdo

  5. equivalência importante

    int divertido(int a[10]) <=> int divertido(int *a) <=> int divertido(int a[])

  6. Em uma variável de ponteiro para uma string, por

    char *p="qweqweqweqw";
    char a[]="qweqwewqeq";
    char *q;
    q=a; a是数组的地址,是一个地址常量,同时也是数组的首地址,即'q'的地址
    p="asdasd"; 虽说p是个地址变量,但是,由于对于字符串来说,"asdasd"也就相当于一个地址常量,也就是‘a’的地址。
    
  7. distinguir

    (1) Preste atenção na diferença entre definir uma variável de ponteiro apontando para uma matriz unidimensional composta por m elementos

    类型名 *数组名[常量表达式];Em essência, é uma matriz unidimensional e as constantes de endereço são armazenadas na matriz.

    类型名 (*指针名)[常量表达式m];Em essência, é uma matriz bidimensional, que é uma variável de ponteiro apontando para uma matriz unidimensional

  8. Ponteiro nulo

    char *q =NULO;

  9. Existem cinco fórmulas para ponteiros

    ① Obtenha o endereço da variável de endereço e quem obtiver o endereço aponta para quem

    ② Há * como o valor do conteúdo, leia ou escreva, coloque-o no lado esquerdo do número da atribuição para escrever e os outros são lidos

    ③ Não há * como endereço, a atribuição do endereço significa alterar para

    ④ A variável ponteiro só pode ser usada depois de definida e inicializada

    ⑤ A variável de endereço armazena o endereço e a variável de conteúdo armazena o conteúdo

  10. equivalência importante

    int divertido(int a[10]) <=> int divertido(int *a) <=> int divertido(int a[])

  11. Em uma variável de ponteiro para uma string, por

    char *p="qweqweqweqw";
    char a[]="qweqwewqeq";
    char *q;
    q=a; a是数组的地址,是一个地址常量,同时也是数组的首地址,即'q'的地址
    p="asdasd"; 虽说p是个地址变量,但是,由于对于字符串来说,"asdasd"也就相当于一个地址常量,也就是‘a’的地址。
    
  12. distinguir

    (1) Preste atenção na diferença entre definir uma variável de ponteiro apontando para uma matriz unidimensional composta por m elementos

    类型名 *数组名[常量表达式];Em essência, é uma matriz unidimensional e as constantes de endereço são armazenadas na matriz.

    类型名 (*指针名)[常量表达式m];Em essência, é uma matriz bidimensional, que é uma variável de ponteiro apontando para uma matriz unidimensional

Acho que você gosta

Origin blog.csdn.net/LOL_toulan/article/details/109356397
Recomendado
Clasificación