指针大小在32位平台上是4个字节,在64位平台上是8个字节
既然指针大小无论类型都是一样的,那么为什么不存在一个通用类型指针呢?
指针类型存在的意义
int a = 0x11223344;
int* pa = &a;
*pa = 0;
运行后:
int a = 0x11223344;
char* pa = &a;
*pa = 0;
运行后:
可见,指针类型决定了解引用时权限的大小
int main()
{
int arr[10] = { 0 };
int* p = arr;
char* pc = arr;
printf("%p\n", p);
printf("%p\n", p + 1);
printf("%p\n", pc);
printf("%p\n", pc + 1);
return 0;
}
可见,指针类型决定了指针向前和向后走一步有多大
野指针
指针指向方向未知
造成野指针原因
- 指针未初始化
int main()
{
int* p;//属于局部指针变量,需初始化
*p = 20;
return 0;
}
- 指针越界
int main()
{
int* p;
*p = 20;
int arr[10] = { 0 };
int* p = arr;
int i = 0;
for (i = 0; i <= 10; i++)
{
*p = i;
p++;
}
}
3.指针指向的空间释放
int* test()
{
int a = 10;
return &a;
}
int main()
{
int* p = test();
*p = 20;
return 0;
}
使用完test()函数后,a的地址被返给p,然后a的地址被释放掉,此时将20赋给*p,会造成冲突。
如何避免野指针
1.指针初始化
不知道初始化为何时,可以直接初始化为NULL
但要注意:
不能乱用NULL指针。对一个NULL指针进行解引用操作是非法的。在对指针进行解引用操作之前,必须首先确保它并非NULL指针
2.注意指针越界问题
3.及时放置NULL
4.指针使用之前检查有效性
指针运算
- 指针±整数
- 指针-指针
- 指针的关系运算
指针+-整数
指针-指针
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", &arr[9] - &arr[0]); //9
return 0;
}
得到的是两个指针之间的元素个数
#include<stdio.h>
int my_strlen(char* str)
{
char* start = str;
while (*str != '\0')
{
str++;
}
return str - start;
}
int main()
{
int len = my_strlen("abc");
printf("%d\n", len); //3
return 0;
}
数组和指针
&arr[i] <=> *(arr+i)
等价关系
arr[2] <==>*(arr+2) <==> *(p+2) <==> *(2+p) <==> *(2+arr) <==>2[arr]
[ ]是一个操作符 ,因此可以进行交换
对于编译器来说,这些形式没有区别,但是我们平时在写代码时,还是应该注意程序的可读性!,不要随便写。
结构体
struct Stu
{
char name[20];
int age;
char id[20];
}s1,s2;//全局变量
int main()
{
struct Stu s; //局部变量
return 0;
}
结构体传参
print(s);//传值调用
print(&s);//传址调用
传址调用效率比传值调用高
传值调用需要将参数的一份拷贝传递给函数,将要开辟空间。这涉及到栈区的使用。因此,传址调用比传值调用效率更高。当然,传址调用也有一定的风险,体现在函数会对调用程序的结构变量进行修改。(有时候我们并不想要修改)
const修饰指针
const int* p = #
int * const p = #
const int * const p;
int const * const p;
const如果放在*的左边,修饰的是 *p ,表示 指针指向的内容 ,是不能通过指针来改变的,不过指针变量本身是可以修改的。
const如果放在 的右边,修饰的是 p ,表示指针变量本身,是不能通过指针来改变的,不过指针指向的内容是可以修改的。
const既放在的左边,const又放在 *的右边,表示指针本身和它指向的数据都有可能是只读的
栈区小tips:
栈区使用习惯:先使用高地址,再使用低地址
由于局部变量是放在栈区的,所以创建局部变量时,先创建的变量先放在高地址
数组随着下标的增长地址是由低到高变化的。 因此,数组越界就有可能覆盖掉局部变量。
从这一角度来看,这也是数组越界访问错误的原因之一。