指针用法
指针也就是内存地址,指针变量是用来存放内存地址的变量。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:
type *var_name;
#include <stdio.h>
int main ()
{
int var_runoob = 10;
int *p;
p = &var_runoob;
printf("var_runoob 变量的地址: %p\n", p);
return 0;
}
#include<stdio.h>
int main(){
int var = 20;
int *ip;
ip = &var;
printf("%p", &var);
printf("%p", ip);
printf("%d", *ip);
}
通过汇编理解指针
#include<stdio.h>
int main(){
int var = 20;
int *ip;
ip = &var;
printf("%p", &var);
printf("%p", ip);
printf("%d", *ip);
}
编译 demo.c
// GCC: (GNU) 11.2.1 20220127 (Red Hat 11.2.1-9)
gcc -S demo.c
查看 demo.s(为了便于理解未开启优化且删除了部分和本文要讨论的内容无关代码)
main:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl $20, -12(%rbp)
leaq -12(%rbp), %rax
movq %rax, -8(%rbp)
leaq -12(%rbp), %rax
movq %rax, %rsi
movl $.LC0, %edi
movl $0, %eax
call printf
movq -8(%rbp), %rax
movq %rax, %rsi
movl $.LC0, %edi
movl $0, %eax
call printf
movq -8(%rbp), %rax
movl (%rax), %eax
movl %eax, %esi
movl $.LC1, %edi
movl $0, %eax
call printf
movl $0, %eax
leave
ret
根据上述汇编代码,我们总结以下什么是指针:
- 指针就是一个内存单元中保存了一个地址。
- 在 C 语言中使用
& 地址符可以获取这个地址,相当于汇编的 lea 指令。 - 在 C 语言中使用
* 解地址符号,访问内存地址中的变量信息,相当于汇编中的 () 。
下面我们再看一个例子加深理解
#include <stdio.h>
void sum(int *p){
*p=3;
}
int main(void)
{
int shareData=1;
sum(&shareData);
return 1;
}
// GCC: (GNU) 11.2.1 20220127 (Red Hat 11.2.1-9)
gcc -S demo.c
sum:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movl $3, (%rax)
nop
popq %rbp
ret
main:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl $1, -4(%rbp)
leaq -4(%rbp), %rax
movq %rax, %rdi
call sum
movl $1, %eax
leave
ret
指针的算数运算
C 语言中,对指针执行 +1 运算,编译器会参照指针类型的大小,执行+1。如果是 int 类型的指针,对其 +1,编译器就会自动加上 int 类型大小的长度,即 4 字节。
#include<stdio.h>
int main(){
int a[] = {1,2,3,4};
printf("%p", a);
printf("%p", a+1);
}
数组
#include <stdio.h>
int main(void){
int arr[3] = {1,2,3};
int a = arr[0];
int b = arr[1];
int c = arr[2];
return 1;
}
gcc -S -m32 demo.c
main:
pushl %ebp
movl %esp, %ebp
subl $32, %esp
movl $1, -24(%ebp)
movl $2, -20(%ebp)
movl $3, -16(%ebp)
movl -24(%ebp), %eax
movl %eax, -4(%ebp)
movl -20(%ebp), %eax
movl %eax, -8(%ebp)
movl -16(%ebp), %eax
movl %eax, -12(%ebp)
movl $1, %eax
leave
ret
根据上述汇编代码,我们总结指针与数组的关系:
- C 语言中的
arr[n] 等价于汇编中的括号 ()
指针获取数组元素
推理
由上文可知在 C 语言中使用 * 解地址符号,访问内存地址中的变量信息,相当于汇编中的 () C 语言中的 arr[n] 等价于汇编中的括号 () 所以我们推测可以通过指针操作访问数组,即使用 *(a) 代替 a[0] 访问数组元素。
验证
用指针获取数组元素
#include<stdio.h>
int main(){
int a[] = {1,2,3,4};
printf("%d", *a);
printf("%d", *(a+1));
}
二级指针
指向指针的指针。 一个指向指针的指针变量必须如下声明,即在变量名前放置两个星号。例如,下面声明了一个指向 int 类型指针的指针:
int **var;
指针数组
int *ptr[COUNT];
#include<stdio.h>
const int MAX = 3;
int main{
int var[] = {2, 43, 212};
int i, *ptr[3];
for(i = 0; i < MAX; i++){
ptr[i] = &var[i];
}
for(i = 0; i < MAX; i++){
printf("var[%d] = %d", i, *ptr[i]);
}
return 0;
}
参考资料
|