c语言指针:程序需要载入内存中运行,在32bit系统中内存地址的范围是:0x0000 0000-0xFFFF FFFF,内存大小为4GB,内存地址指的是内存单元的编号是固定的,本身就是一个整数,对于32bit系统,内存地址对应的编号是4字节的正整数
地址:c语言规定用户有权对对内存地址进行命名,地址编号本身也可以当初数据存在变量中
指针:c语言规定,用户打算定义一个变量来存储地址,则在定义变量前需要指明,变量中存的是一个地址,存储地址的变量叫做指针变量,指针变量定义格式:数据类型 *变量名;如int *p ==>p是变量名,*修饰变量p表示p是一个指针即p里面存储的数据是一个地址 ==> int 表示p指向的地址的内存下面的数据是整型
空指针:对指针变量初始化需要吧指针变量里面对应的内存设置为0,需要吧0强制转换成地址
0x00000000 ==> (void *)0x00000000 == c语言提供了宏定义NULL
保留区:linux系统的内存中有一部分内存是保留区,地址范围为:0x0000 0000-0x0804 8000,此区域用户无法访问,一旦访问就会出现段错误
int *p = NULL; //对指针变量进行初始化,目的是防止野指针出现,避免段错误
#include <stdio.h>
int main()
{
int data = 20;
int *p = NULL; //对指针进行初始化,避免野指针出现
p = &data; //p ==> &p ==> *(&p) == p,使用变量是操作系统默认先找到变量的地址(&),在间接访问地址里面的数据(*)
//通过变量名访问
data = 10;
printf("data: %d\n", data); //10
*(&data) = 20;
printf("data: %d\n", data); //20 data == *(&data)
//通过指针访问
*p = 40;
printf("data: %d\n", data); //40 p = &data ==> *p == *(&data)
return 0;
}
保留区地址用户是无法访问的,但可以定义指针指向这块空间,指针变量只能存储这个地址,不能间接访问该地址下的值,否则会段错误(Segmentation fault)
数组指针:int b[5]; int *p = b;
#include <stdio.h>
int main()
{
int a[5] = {1,2,3,4,5};
for(int i=0; i<5; i++){
printf("a[%d]=%d ", i, a[i]);
}
printf("\n");
int *p = a; //此处a表示数组首元素地址,即a==&a[0]
//通过数组下标访问
a[0] = 10;
printf("a[0]=%d\n", a[0]); //10
//通过指针访问
*(p+1) = 20;
printf("*(p+1)=%d\n", a[1]); //20 p == a ==> *(p+1) ==*(a+1) == a[1]
return 0;
}
地址的运算:一般只能对地址进行 +- 运算,表示地址的偏移,偏移的单位取决于该地址下存储的数据的类型
#include <stdio.h>
int main()
{
int a[5] = {1,2,3,4,5};
printf("a的地址为: %p\n", a); //a表示数组首元素地址
printf("a+1的地址为: %p\n", a+1); //a+1表示地址向后偏移一个数组元素单位即4字节
printf("&a+1的地址为: %p\n", &a+1); //&a表示 整个数组地址,&a+1表示地址向后偏移一个数组单位即4*5=20字节
int *ptr = (int*)(&a+1);
printf("*(a+1)=%d\n", *(a+1)); //2 *(a+1) = a[1] = 2
printf("*(ptr-1)=%d\n", *(ptr-1)); //5
return 0;
}
二维数组与指针
#include <stdio.h>
int main()
{
int aa[2][5] = {{1,2,3,4,5},{6,7,8,9,10}};
//单独从地址的值来说,aa==aa[0]==&aa[0][0]==&aa
printf("aa地址 %p\naa[0]地址 %p\naa[0][0]地址%p\n&aa地址 %p\n", aa, aa[0], &aa[0][0], &aa);
//aa表示数组首元素地址,即aa == &aa[0]
printf("&aa[0]的地址: %p\naa的地址: %p\n", &aa[0], aa);
printf("aa+1的地址: %p\n", aa+1); //aa+1表示地址从aa[0]偏移到aa[1],偏移aa[2]数组中一个元素的字节:4*5=20字节
printf("&aa的地址: %p\n\n", &aa); //&aa表示整个数组的地址
printf("&aa+1的地址: %p\n\n", &aa+1); //&aa+1,表示地址向后偏移一个数组单位即2*4*5=40字节
int *ptr1 = (int*)(&aa +1); //此时ptr1指向数组aa的后一个地址
printf("*(ptr1-1)=%d\n", *(ptr1-1)); //10 向后偏移一个整型元素aa[1][4]的值
int *ptr2 = (int*)(*(aa+1)); //此时ptr2表示aa[1]的地址,int*表示指向aa[1][0]
printf("*(ptr2-1)=%d\n", *(ptr2-1)); // 5 aa[0][4]
return 0;
}
二维数组的访问
#include <stdio.h>
int main()
{
int aa[2][5] = {{1,2,3,4,5},{6,7,8,9,10}};
for(int i=0; i<2; i++){
for(int j=0; j<5; j++){
printf("aa[%d][%d]=%d ", i, j, aa[i][j]);
}
printf("\n");
}
//p变量名,*p表示p是指针,[5]表示p指向有5个元素的匿名数组,int表示指针指向的内存中数据为整型
int (*p)[5] = aa; //将数组aa的首地址即&aa[0]存到指针变量p中
//数组下标访问
aa[0][0] = 10; // aa[0][0] == *(aa[0]+0) == *aa[0] == *(&aa[0][0])
printf("a[0][0]=%d\n", aa[0][0]);
//指针变量访问aa[1][2]
//aa[1][2] == *(aa[1]+2) == *(*(aa+1)+2) ==>aa==&aa[0]==p ==>*(*(p+1)+2)
*(*(p+1)+2) = 80;
printf("a[1][2]=%d\n", aa[1][2]);
return 0;
}
指针数组:数组中每个元素都是指针,定义格式:数据类型 *数组名[元素个数];如:int *p[5];
二级指针:指针变量中存储的值,是另一个指针变量的地址
指针与数组的定义:int * (*p)[3][4]
p:表示变量p
*p:表示变量p是一个指针,用于存放地址
[3]:表示指针p存储的地址下的数据类型是一个匿名数组,可以存放三个元素
[4]:表示匿名数组[3]中每个元素都是一个有4个元素的匿名数组
*: 表示匿名数组[4]中每个元素的类型是一个指针
int:表示[4]中存储的指针所指向的地址是int
int *(*p)[2][3]; //运算符优先级()>[]>*
// *p :表示p是一个指针存放的数据是地址
// (*p)[2] :表示p指针里面存放的地址,地址下面的数据类型为匿名数组[2]里面有两个元素
// (*p)[2][3] :表示匿名数组[2]里面的数据,类型是匿名数组[3]->里面有三个元素
// *(*p)[2][3] :表示匿名数组[3]里面的数据,类型是指针
// int *(*p)[2][3]:表示匿名数组[3]里面存的地址,地址所下面存的数据类型为int
二级指针定义格式:int data; int *p1= &data; int **p2 = &p1;==>*p2是一个指针存储的值为地址,*表示p1里面存的地址下面的值,还是指针
#include <stdio.h>
int main()
{
int data = 10; //定义整型变量
int *p1 = &data; //定义指针变量存储data的地址
int **p2 = &p1; //定义二级指针,存储指针p1的地址
//用变量名访问数据
data = 20;
printf("data=%d\n", data);
//用指针p1访问数据
*p1 = 30; //p1==&data ==>*p1 == *(&data) == data
printf("*p1=%d\n", data);
//用指针p2访问
**p2 = 40; //p2 == &p1 ==> *p2 == *(&p1) == p1 ==> **p2 ==*p1 == data
printf("**p2=%d\n", data);
//一维数组形式访问
p1[0] = 50; //p1[0] == *(p1+0) == *p1 == data
printf("p1[0]=%d\n", data);
//二维数组形式访问
p2[0][0] = 60; // p2[0][0] == *(p2[0]+0) == *p2[0] == *(*(p2+0)) == **p2 == data
printf("p2[0][0]=%d\n", data);
return 0;
}
练习:
#include <stdio.h>
int main()
{
int buf[5] = {1,2,3,4,5};
int *p = buf;
printf("%d\n", *p++); //1:++后置,*p =buf[0]=1,结束后P指向a[1]的地址
printf("%d\n", (*p)++); //2:++后置,*p=buf[1]=2,结束后p指向a[2]的地址
return 0;
}