6.指针学习
指针
- 指针
- 指针类型
- 野指针
- 指针运算
- 指针+- 整数
- 指针-指针
- 指针的关系运算
- 指针和数组
- 二级指针
- 指针数组
指针
- 指针 == 内存编号 == 地址
- 口语指针:指针变量,是用来存放内存地址的变量
指针变量:存放地址的变量。
- &取出变量的内存真实地址
- 把地址存放到一个变量中
- 这个变量就是指针变量
int main()
{
int a = 10;//在内存中开辟一块空间
int* p = &a;//取a地址,p就是一个指针变量。
return 0;
}
a变量占用4个字节的空间
将a的4个字节的第一个字节的地址存放在p变量中
p就是一个指针变量。
int* p
*:p是指针,*p是指针变量-->a
int:a是int类型
32位地址,指针变量大小是4个字节。
64位地址,指针变量大小是8个字节。
指针类型
存数据再内存中是倒着存的,访问是正着访问的
指针类型 | 指针解引用时可访问的字节数 |
---|---|
char* | 1byte |
short* | 2byte |
int* | 4byte |
野指针
指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针成因
- 指针未初始化(随机找了一块空间)
- 指针越界访问(数组越界)
- 指针指向的空间释放了(局部变量,进函数创建,出函数销毁)
如何规避野指针 - 指针初始化 int* ptr = NULL; -->空指针,没有指向有效空间,不能直接使用。
- 小心指针越界
- 指针指向空间释放,及时置NULL
- 避免返回局部变量的地址
- 指针使用之前检查有效性 if(ptr != NULL)
指针运算
指针± 整数
int main()
{
int arr[10] = {0};
int* p = &arr[0];
int i = 0;
for(i = 0;i < 10;i++)
{
*p = i;//将i赋值给 *p,即arr[i] = i
p++;//给地址++
//or
*(p + i) = i;//在p 的基础上增加
}
return 0;
}
arr数组名 == 首元素地址 arr[0] == 指针 p
*(p + i)== *(arr + i) == arr[i] == i[arr] == *(i + arr)
指针-指针
地址 - 地址,前提:指向同一块空间
(指针 - 指针) 的绝对值 得到的是 指针之间的元素个数
int main()
{
int arr[10] = {0};
printf("%d", &arr[9] - &arr[0]);//9
return 0;
}
计算字符串长度
int my_strlen(char* s)
{
char* start = s;
while(*s)//a b c d e f /0
{
s++;
}
return s - start;
}
int main()
{
char arr[] = "abcdef";//a b c d e f /0
int len = my_strlen(arr);
printf("%d", len);
return 0;
}
指针的关系运算
#define N_VALUES 5
float values[N_VALUES];
float *vp;
for(vp = &values[N_VALUES]; vp > &values[0];)
{
*--vp = 0;
}
代码简化, 这将代码修改如下
for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{
*vp = 0;
}
实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证
它可行。
标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较
但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
指针和数组
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
printf("%p\n", arr); //012FFB90
printf("%p\n", &arr[0]); //012FFB90
return 0;
}
数组名 == 数组首元素的地址 == 指针
数组是连续存放的,是一块连续的空间
可以通过 指针 访问 数组,通过 指针 遍历
&arr
的类型是 int (*)[10]
,而 arr
的类型是 int *
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
int* p = arr;/p存放的是数组首元素的地址
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%p==%p\n", &arr[i], p + i);//010FFDFC==010FFDFC ……
printf("%d ", *(p + i));//1 2 3 4 5 6 7 8 9 0
}
return 0;
}
二级指针
int main()
{
int a = 10;
int* p = &a;//*:p是指针,int:a是int类型
int** pp = &p;//*:pp是指针,int*:p是int*类型
printf("%d ", *(*pp));//10
*(*pp) = 100;//*pp-->p;*(*pp)==*p-->a
printf("%d ", a);//100
return 0;
}
指针数组
存放指针(地址)的数组
eg:
int arr1[10];//存整形的数组
char arr2[10];//存字符的数组
int* arr3[10];//存整形指针的数组
int main()
{
char arr1[] = "abcdefghijklmn";
char arr2[] = "1,2,3,4,5,6,7,8,9,0";
char arr3[] = "hello world";
char* parr[] = { arr1,arr2,arr3 };//类型是char*
int i = 0;
for (i = 0; i < 3; i++)
{
printf("%s\n", parr[i]);//%s打印只需要知道字符串起始位置,打印到\0
}
return 0;
}
指针数组模拟出2维数组
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 2,3,4,5,6 };
int arr3[] = { 3,4,5,6,7 };
int* parr[] = { arr1,arr2,arr3 };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ", parr[i][j]);
printf("%d ", *(parr[i]+j));//与上等价
}
printf("\n");
}
return 0;
}
2维数组:在内存中是连续的
指针数组:arr1,arr2,arr3不一定连续