目录
前言:指针简介
我们在生活中有许多指针,时钟的指针指向时间,指南针的指针指向南方......
C语言的指针又是什么呢?指针是内存中的一个最小单元(规定最小内存单元的大小为1个字节)的编号(我们可以理解为门牌号),也就是地址。
注意:指针就是地址,但是我们口语所说的指针通常说的是指针变量
一、指针和指针类型
1.指针变量的定义
' * ' —— 解引用操作符(有两种不同的作用)
1.定义指针变量
2.取出指针变量指向的内容
' & ' —— 取地址操作符(作用如其名)
' %x ' —— 地址的格式化输出(作用如其名)
int main()
{
int num = 10;
int *p = #
printf("%x\n", &num);
printf("%x\n", p);
printf("%d\n", num);
printf("%d\n", *p);
return 0;
}
这里建议*号靠近变量名,避免混淆
int* pa, pb;//我们有可能会误以为pa、pb都是指针变量
int *pa, pb;//我们更容易看出pa是指针变量,pb不是指针变量
运行结果如下:
下面的定义方式能够让我们更好地区分指针变量
char *pc = NULL;
short *ps = NULL;
int *pi = NULL;
long *pl = NULL;
float *pf = NULL;
double *pd = NULL;
注意:尽管NULL和0的意义相同,但是为了区分它是一个指针变量,我们尽量使用NULL
2.指针变量的大小
指针变量的大小为4/8个字节,分别对应x32/x64
以下为x64环境演示代码
3.二级指针
一级指针 -> 变量的地址
二级指针 -> 指针变量的地址
n级指针 -> (n-1级)指针变量的地址
int main()
{
int num = 10;
int *p = #
int **pp = &p;
printf("%x\n", p);
printf("%x\n", *pp);
printf("%x\n", &p);
printf("%x\n", pp);
printf("%d\n", *p);
printf("%d\n", **pp);
return 0;
}
运行代码如下:
二、野指针
1.概念及其成因
野指针是指针没有初始化产生的,它指向的位置是不可知的
虽然有的编译器或者场合会报错
但是更多的情况下,程序会在暗中崩溃
如果修改for循环次数为10,就可以正常运行啦
2.如何规避野指针
1.指针初始化NULL;
2.注意防止指针越界;
3.指针指向的空间释放时,及时赋值NULL;
4.避免返回局部变量的地址;
5.指针使用之前检查有效性。
三、指针运算和一维数组
1.指针运算
注意:上述代码中的 ' str ' 就是数组的首地址了
int main()
{
int str[3] = { 1,3,5 };
int* p = &str[1];
printf("%x\n", p - 1);
printf("%x\n", &str[0]);
printf("%x\n", p);
printf("%x\n", &str[1]);
printf("%x\n", p + 1);
printf("%x\n", &str[2]);
printf("%d\n", *(p - 1));
printf("%d\n", *p - 1);
printf("%d\n", *p);
printf("%d\n", *(p + 1));
printf("%d\n", *p + 1);
return 0;
}
运行结果如下:
p 指向str[1]的地址
p - 1 指向str[0]的地址
p + 1指向str[2]的地址
p-1、p、p+1相邻(相差4个字节(int))
此外,我们还可以看到,' * ' 的优先级大于 ' + '
2.指针与一维数组
如果你能够分析出下面代码的运行结果,就表示你已经能够把指针和数组联系起来了,如果你还是编程新手,你一定会对下面的代码感到头疼!!!
int main()
{
int str[5] = { 1,3,5,7,9 };
int* p = str;
printf("%x\n", str);
printf("%x\n", &str[0]);
printf("%x\n", p);
printf("%x\n", &p[0]);
printf("%d\n", *(str + 1));
printf("%d\n", *(p + 1));
printf("%d\n", *(&p[0] + 1));
printf("%d\n", p[0]);
return 0;
}
请读者先自行仔细思考,然后再阅读下文
运行结果如下:
int main()
{
int str[5] = { 1,3,5,7,9 };
int* p = str;
int i = 2;//i表示数组的下标,当前取值范围为0~4
printf("%d\n", str[i]);
printf("%d\n", *(str + i));
printf("%d\n", *(p + i));
printf("%d\n", p[i]);
return 0;
}
结论(非常重要)
//i表示数组的下标,当前取值范围为0~4
str[i] <=> *(str + i) <=> p[i] <=> *(p + i)
四、指针与二维数组
如果你已经对指针与一维数组足够了解了,那么指针与二维数组也难不倒你。在学习二维数组的时候,我们把二维数组根据行下标分解为多个一维数组,这种思想在本节也适用
我们应该怎样为二维数组定义指针变量呢,与一维数组一样吗?
实际上应该这样定义
int (*p)[4] = str;
接下来请读者分析下面的代码吧!
int main()
{
int str[3][4] = { 1,3,5,7,9,11,13,15,17,19,21,23 };
int(*p)[4] = str;
printf("%x\n", str[1]);//str[0] <=> &str[0]
printf("%x\n", &str[1][0]);
printf("%x\n", str + 1);
printf("%x\n", p[1]);
printf("%d\n", *(str[2] + 1));
printf("%d\n", *(&str[2][0] + 1));
printf("%d\n", *(*(str + 2) + 1));
printf("%d\n", *(p[2] + 1));
printf("%x\n", str);
printf("%x\n", p);
printf("%x\n", *p);
printf("%d\n", *(*p));
return 0;
}
请读者先自行仔细思考,然后再阅读下文
运行结果如下:
结论(非常重要)
//i、j分别表示数组的行下标、列下标
str[i][j] <=> *(str[i] + j) <=> *(p[i] + j) <=> *(*(str + i) + j)
五、指针数组与数组指针
指针数组的孪生兄弟数组指针在本文实际上已经与各位读者见过面了(暗藏玄机)
在为二维数组定义“ 指针变量 ” 的时候,你觉得它与为一维数组定义的指针变量相同吗?
1.数组指针
显然我们不能简单地把它称为指针变量
int (*p)[10] = &str;
(*p)表示它是一个指针,指向数组的地址,这个数组的长度为10
注意:[] 的优先级高于 *号,所以才需要括号
2.指针数组
int main()
{
//数组指针
int str[2][3] = { 1,3,5,7,9,11};
int(*p)[3] = str;
//指针数组
int str1[3] = { 1,3,5 };
int str2[3] = { 7,9,11 };
int* pstr[3] = { str1,str2 };
return 0;
}
指针数组是一个数组,示例代码的指针数组pstr的每一个元素都是指针(int*)类型的
int main()
{
int str1[3] = { 1,3,5 };
int str2[3] = { 7,9,11 };
int* pstr[3] = { str1,str2 };
printf("%d\n", sizeof(pstr));
printf("%d\n", sizeof(str1));
printf("%d\n", sizeof(pstr[0]));
printf("%d\n", sizeof(str1[0]));
return 0;
}
总结
这里对文章进行总结:
概念:
指针就是地址,但是我们口语所说的指针通常说的是指针变量,指针变量的大小为4/8个字节,分别对应x32/x64
野指针是指针没有初始化产生的,它指向的位置是不可知的
数组指针(*p)是一个指针,指向数组的地址,[ ]里面是数组的元素个数
指针数组是一个数组,指针数组的每一个元素都是指针(int*)类型的
结论:
str[i] <=> *(str + i) <=> p[i] <=> *(p + i)
str[i][j] <=> *(str[i] + j) <=> *(p[i] + j) <=> *(*(str + i) + j)
作者是萌新,欢迎各位读者批评指正本文的错误
以上就是今天要讲的内容,希望能够对你有所帮助^V^