第七天
好多学生都认为C语言中指针是最难的,在我看来,并没有想象的那么难,希望读者不要害怕指针。
指针:
地址从内存分配什么地址?一个地址就是一个编号,编号和编号之间相差一个字节,如果地址需要存储占用4个字节
什么指针? 指针常量和指针变量
指针常量就是地址编号
指针变量就是存放地址编号的变量
通常直接将指针常量和指针变量简称为指针。
如何定义指针变量。
xxx *p;
xxx代表了一个数据类型
int a = 10;
int *p = &a; *和int结合构成了一个指针类型叫做int *
*p = 20;本质修改了a的内容
操作的是指针变量指向的空间内容(一个空间包含多个地址编号,其中第一个地址编号就可以被称为指向了这个空间,
指针变量存放空间首地址编号,所以也可以直接描述为指针变量指向了这个空间)。
算数运算符:+ - ++ --
int a = 10;
int *p = &a;
p + 1跳过的字节数和p指向的空间的类型相关
*p ++ 打印结果为10 p指向偏移了
(*p)++ 单纯打印也是10 p指向没有改变
int *p;叫做野指针
int a = 0x12345678;
char *p = (char *)&a;
*(p + 1) 获取了 0x56
*(p + 3) 获取了 0x12
一级指针和一维数组的关系
数组名是一个常量地址
int a[5] = {a[0],a[1],a[2],a[3],a[4]};
//int *p1 = &a[0];
//int *p2 = &a[1];
int *p = a;
p + i <==> a + i
*(p + i) <==> *(a + i) <==> a[i]
/\ 操作a+i指向的空间内容
||
\/
p[i]
例子:
#include<stdio.h>
int main(int argc, const char *argv[])
{
int a[2][3];
//取出二维数组中实际元素,要对列指针操作
printf("a[1] = %p\n",a[1]);
printf("a[1] + 1 = %p\n",a[1] + 1);
printf("*(a + 1) = %p\n",*(a + 1));
printf("*(a + 1) + 1 = %p\n",*(a + 1) + 1);
printf("********************\n");
printf("a + 1 = %p\n",a + 1);
printf("a + 1 + 1 = %p\n",a + 1 + 1);
printf("&a[1] = %p\n",&a[1]);
printf("&a[1] + 1 = %p\n",&a[1] + 1);
//行指针取*变成列指针 列指针取地址变成行指针
//列指针取*获取了空间具体值
return 0;
}
int a[2][3];当作一个特殊的一维数组,定义如下:xxx a[2]; xxx是12字节的类型
a[0],a[1]都是a数组中的元素。每个元素是12个字节——12字节包含了3个整型,所以认为a[0],a[1]都代表了一个一维数组
“a[0],a[1]都代表了一个一维数组” <==> 普通的一维数组数组名是整个数组空间首地址
普通的一维数组名 + 1跳过了数组名代表的数组内部中一个元素。<==> a[0] + 1跳过了a[0]代表的一维数组中一个元素
二维数组中:
int a[2][3];<==> int (a[2])[3]; ==>转化后的类型是 int (*)[3];
行序优先
定义变量:数据类型 变量名;
int (*)[3] p; 通过类型定义的一个变量
这里的p本质也是行指针
编译器识别的用法:int (*p)[3];很多资料上被叫做数组指针(一个指向数组的指针)
p = a;
行指针
a + i <==> &*(a + i) <==> &a[i]
p + i <==> &*(p + i) <==> &p[i]
列指针
a[i] + j <==> *(a + i) + j
p[i] + j <==> *(p + i) + j
例子:
#include<stdio.h>
int main(int argc, const char *argv[])
{
int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
// int (*)[4] p;//这里的错误是编译器问题,老版本编译器允许这样做。现在编译器不允许。
int (*p)[4];//如果有一个指针类型是 xxx (*)yyy,定义的变量或者数组或者函数,都放到括号内部*的后面
//这里为什么出现[4],就是为了告诉指针,每次加1跳一行时,需要跳过4个元素。
p = a;
int i,j;
for(i = 0;i < 3;i ++)
{
for(j = 0;j < 4;j ++)
{
// printf("%d\t",a[i][j]);
// printf("%d\t",*(*(a + i) + j));
// printf("%d\t",*(a[i] + j));
printf("%d\t",p[i][j]);
printf("%d\t",*(*(p + i) + j));
printf("%d\t",*(p[i] + j));
}
}
printf("\n");
return 0;
}
指针和指针数组的关系:
char *str[2];
char **p = str;
{
int a=10;
int *p=&a;
int * *q=&p;
}
char (*str[2])[3];<==> char (*)[3] str[2];这是一个数组,里面存的是
char (*)[3] *p = str; <==> char (**p)[3] = str;
int *q;
p = (char (**)[3]) q;
char (*str[2][3])[4];这是什么?二维数组,存char (*)[4];
<==> char (*)[4] str[2][3];
char (*)[4] (*)[3] p; <==> char (*(*p)[3])[4];