ponteiro
Índice
- ponteiro
-
- 1. Definição da variável de ponteiro
- 2. Ponteiro de matriz
- 3. Variáveis de ponteiro apontando para arrays multidimensionais
- Quarto, a variável de ponteiro apontando para a string
- 5. Variáveis de ponteiro apontando para funções
- 6. Funções que retornam ponteiros
- 7. Arrays de ponteiros e variáveis de ponteiros apontando para ponteiros
- 8. Ponteiro nulo
- Nove. Resumo
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.
- 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.
- 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:
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:
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:
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:
Resposta e análise:
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:
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+1
o que é adicionado é um elemento, int a[3][4]
, o que a+1
é adicionado é uma linha, conforme a figura abaixo
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)
Iguala[i]
a , é um ponteiro de coluna que aponta para um elemento.③
*(a+i)+j
éa[i]+j
igual a , ambos representama[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]
ea[i][j]
o mesmo, todos representam elementosa[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:
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:
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:
/*
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:
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):
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:
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:
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:
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
-
Em
int *a;
, o nome da variável é a, não*a
porque 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
tipoint *
, chamado de tipo de ponteiro. -
No int
*a;
, o a ocupa 8 bytes, claro*a
que ocupa 4 bytes, pois*a
é do tipo int, então tem 4 bytes,char *b
e o b nele também ocupa 8 bytes, mas*b
ocupa 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). -
No ponteiro
*
e&
, são operações inversas,&
e[]
são recíprocas, ou seja, podem se anular, comoint a[3]; int b; int *a; int *p; a=&b; p=&a[0]; <=> p=a; p=&a[3]; <=> p=a+3; & 和 * 互逆 *和 [] 等价 & 和 [] 互逆
-
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
-
equivalência importante
int divertido(int a[10]) <=> int divertido(int *a) <=> int divertido(int a[])
-
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’的地址。
-
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 -
Ponteiro nulo
char *q =NULO;
-
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
-
equivalência importante
int divertido(int a[10]) <=> int divertido(int *a) <=> int divertido(int a[])
-
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’的地址。
-
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