什么是指针?
指针和指针类型
野指针
指针运算
指针和数组
二级指针
指针数组
什么是指针?
指针是内存中一个最小单元的编号,也就是地址。
1.把内存划分为一个个的内存单元,一个内存单元的大小是一个字节。
2.每个字节都给定唯一的编号,这个编号称之为地址。地址在C语言中也叫 指针。
编号==地址==指针
2.我们说的指针,通常指的是指针变量,是用来存放内存地址的变量。
int main()
{
int a = 10;
int* pa = &a;//a的地址放在指针变量pa中,pa的类型是int *
return 0;
}
指针变量:使用&(取地址操作符)取出变量的内存起始地址,把地址存放到一个变量中,这个变量就是指针变量。
int main()
{
int a = 10;
int* pa = &a;
pa=10
return 0;
}
💭注意:
a是整型,占用4个字节的内存空间,每个字节都有对应的地址。
&a 得到的是a的地址,其实得到的是a所占内存中4个字节中第一个字节地址
pa=10 其实存放的是地址
4.一个指针变量在32位的平台上是4个字节,在64位的平台上是8个字节
2.指针和指针类型
所有指针类型在x86环境下全是4个字节,在x64环境下是8个字节。
指针类型的意义:
1.指针类型决定了在解引用指针的时候能访问几个字节
对于整型指针,解引用时访问4个字节
对于字符型指针,解引用时访问1个字节
2.指针进行加减整数时,int型加4个字节,char型加1个字节
int main()
{
int a = 10;
int* pa = &a;
char* pc = &a;
printf("%p\n", pa);
printf("%p\n", pa + 1);
printf("%p\n", pc);
printf("%p\n", pc + 1);
return 0;
}

int main()
{
int arr[10] = { 0 };
int* p = &arr[0];
int i = 0;
for (i = 0; i < 10; i++)
{
*p = i + 1;
p++;
}
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);//1 2 3 4 5 6 7 8 9 10
}
return 0;
}
3. 指针解引用:指针的类型决定了,对指针进行解引用有多大的权限。char* 只能访问一个字节,int* 访问4个字节
3.野指针
野指针就是指针指向的位置是不可知的(随机的,不正确的,没有明确限制的)。
野指针成因:
指针未初始化

指针越界访问

指针指向的空间释放
int* test()
{
int a = 10;//a的空间被释放(局部变量)
return &a;
}
int main()
{
int* p = test();
*p = 100;
}
如何规避野指针?
指针初始化
int main()
{
int a = 10;
int* p = &a;
return 0;
}
小心指针越界
指针指向空间释放时,及时置NULL,一个指针不知道指向哪里时,暂时可以置为空指针(NULL)
避免返回局部变量的地址
int* test()
{
int a = 10;//a的空间被释放(局部变量)
return &a;
}
int main()
{
int* p = test();
*p = 100;
}
指针使用之前检查有效性(使用指针之前判断指针是否为空)
指针运算
指针+-整数
int my_strlen(char* str)
{
int count = 0;
while (*str != '\0')
{
count++;
str++;//指针+整数
}
return count;
}
int main()
{
char arr[10] = "abcdef";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
char* str是字符型指针,所以str++是跳过一个字符
指针-指针(地址-地址)
💭注意:
1.两个指针指向同一块内存空间(指针的类型是一致的)
2.指针-指针得到的是指针和指针之间的元素个数
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int n = &arr[9] - &arr[0];
//&arr[0]-&arr[9]=-9
printf("%d", n);//9
return 0;
}

int my_strlen(char* str)
{
char* start = str;
while (*str != '\0')
{
str++;
}
return str - start;
}
int main()
{
char arr[10] = "abcdef";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
指针的关系运算
标准规定:
1.允许指向数组元素的指针与指向数组最后一个元素后面的那么内存位置的指针进行比较
2.不允许与指向第一个元素之前的那个内存位置的指针进行比较
//1.
for (vp = &values[N_VALUES]; vp > &values[0];)
{
*--vp = 0;
}

//2.
for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{
*vp = 0;
}


5.指针和数组
指针就是指针,数组就是数组
指针的大小:4/8个字节,指针是存档地址的,地址的存放需要多大空间,指针变量的大小就是多少。
数组的大小:取决于数组的元素个数和每个元素的类型。
int main()
{
int arr[10] = { 0 };
int* p = arr;//&arr[0]
int i = 0;
//存放
for (i = 0; i < 10; i++)
{
*p = i + 1;
p++;
}
//打印
p = arr;
for (i = 0; i < 10; i++)
{
*(p + i) = i + 1;
printf("%d ", *(p + i));
}
return 0;
}
6.二级指针
int main()
{
int a = 10;
//一级指针
int* pa = &a;//pa是指针变量,用来存放地址,向内存申请空间4/8
//二级指针
int** ppa = &pa;//指向pa空间的指针变量ppa
return 0;
}

int main()
{
int a = 10;
//一级指针
int* pa = &a;//pa是指针变量,用来存放地址,向内存申请空间4/8
//二级指针
int** ppa = &pa;//指向pa空间的指针变量ppa
printf("%d", **ppa);//10
return 0;
}
7.指针数组
int main()
{
int a = 10;
int b = 20;
int c = 30;
//存放指针的数组
int* arr[] = { &a,&b,&c };
int i = 0;
for (i = 0; i < 3; i++)
{
printf("%d ", *(arr[i]));
}
return 0;
}
指针数组是一个数组,数组中每个元素都是指针类型
拓展:
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
int* p = arr;
//arr[i]-->*(arr+i)-->*(i+arr)-->i[arr]
//*(arr+i)-->*(p+i)-->arr[i]
for (i = 0; i < 10; i++)
{
printf("%p=%p\n", &arr[i], p + i);
}
return 0;
}

这里arr[i]和i[arr]相等,[ ]就相当于一个操作符
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", i[arr]);
//i[arr]--*(i+arr)
//arr[i]--*(arr+i)
}
return 0;
}
int main()
{
int arr[3][5];
//arr[i[[j]
//(*(arr + i))[j]
//*(*(arr + i) + j)
return 0;
}
感谢阅读,欢迎大家批评指正!