1、指针
计算机将内存分割为字节,每个字节可以存储8位信息。
程序中每个变量占有一个或多个字节内存,把第一个字节的地址称为变量的地址。
如变量i占有地址为2000和2001的两个字节,则变量i的地址为2000。
2、取地址运算符 和 间接寻址运算符
取地址:变量x,&x就是x在内存中的地址;
间接寻址:指针p,*p表示p指向的对象。
例1:
// 打印地址(地址也被称为指针)
#include <stdio.h>
int main()
{
int a = 10; //向内存申请4个字节,存储10
printf("%p\n", &a); //&a取a的地址,64位电脑打印出16位十六进制数(64位二进制)
int* p; //定义一个指针变量p,*是间接寻址操作符,
p = &a; //p是指针变量(里面存的是地址)
//*说明p是指针变量,int表示p指向的对象是int类型
*p = 20; //间接寻址操作符,意思就是通过p中存放的地址,找到p所指向的对象,*p就是p指向的对象,即a
return 0;
}
例2:
// &和*(取地址和间接寻址)
#include <stdio.h>
int main ()
{
int var = 20; //声明一个变量var
int* ip; //声明指针变量ip
ip = &var; //把var的存储地址放到指针变量ip中
printf("var 变量的地址: %p\n", &var ); // &是取地址符,&var是取变量var的存储地址
printf("ip 变量存储的地址: %p\n", ip ); // ip是定义的指针变量,存的是&var
printf("*ip 变量的值: %d\n", *ip ); // *是寻址符,*ip是指针ip指向的变量var,其值为20
return 0;
}
3、NULL指针(空指针)
在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。
NULL 指针是一个定义在标准库中的值为零的常量。
// NULL指针(空指针)
#include <stdio.h>
int main()
{
int* ptr = NULL;
printf("ptr的指针是 %p\n", ptr); //输出一堆0是因为编译环境是64位的,地址是8个字节,%p是十六进制输出
return 0;
}
4、指针的算术运算
指针可以++、--、+、-;
指针递增和递减时跳跃的字节数,取决于指针所指向的变量数据类型长度,比如int就是跳跃4个字节;
#include <stdio.h>
const int N = 3;
int main()
{
int arr[] = {1, 2, 3};
int i, *p;
p = arr; //把数组arr存到指针p中
for(i = 0; i < N; i++)
{
printf("存储地址: arr[%d] = %p\n", i, p); //p是指针变量,是一个地址
printf("存储值: arr[%d] = %d\n", i, *p); //*p是取指针对应的变量
p++; //指向下一个位置
}
return 0;
}
指针可以用==、>、<进行比较,如p1和p2指向两个相关变量,如同一个数组中的不同元素,则可对p1和p2比较;
#include <stdio.h>
const int N = 3;
int main()
{
int i = 0, *p;
int arr[] = {1, 2, 3};
p = arr; //将数组第一个元素的地址给p
// printf("%p", p);
while(p <= &arr[N - 1])
{
printf("存储地址: arr[%d] = %p\n", i, p); //p是指针变量,是一个地址
printf("存储值: arr[%d] = %d\n", i, *p); //*p是取指针对应的变量
p++; //指向下一个位置,指针变量是int型,所以跳转4个字节
i++;
}
return 0;
}