- 1.指针是什么?
- 2.指针和指针类型
- 2.1指针的解引用
- 3.野指针
- 3.1野指针成因
- 指针未初始化
- 指针越界访问
- 指针指向的空间释放
- 3.2如何规避野指针
- 4.指针运算
- 4.1指针+- 整数
- 4.2指针-指针
- 4.3指针的关系运算
- 5.指针和数组
- 6.二级指针
- 7.指针数组
指针是内存中一个最小单元的编号 ,也就是地址
平时口语中说的指针其实本质上是指针变量,是用来存放内存地址的变量
- 内存
一个字节为一个内存单元,我们可以通过编号找到内存 ,编号在生活中叫地址,对应我们c语言其实就是指针
#includeint main()
{int a = 10;
int *p = &a;
return 0;
}
那我们&a是取出的是哪一个字节的地址?取出的是第一个字节的地址(较小的地址)
- 内存单元是如何进行编号?
2.指针和指针类型在32位机器上,地址就是32个0或1组成二进制序列,那地址就得用用4个字节的空间进行储存 ,也就是说32位机器,指针变量大小就是4个字节
在64位机器上,地址就是64个0或1组成二进制序列,那地址就得用用8个字节的空间进行储存 ,也就是说64位机器,指针变量大小就是8个字节
int main()
{int a = 0x11223344;
char* pc = (char*)&a;
int i = 0;
for (i = 0; i< 4; i++)
{*pc = 1;
pc++;
}
return 0;
}
- 指针类型的不同意义:指针的不同类型提供了不同的视角去观看和访问内存
指针的不同类型决定了,指针在解引用的时候一次性访问几个字节,决定了访问权限的大小
如果是char *的指针,解引用访问一个字节
如果是int *的指针,解引用访问四个字节
int main()
{int a = 0x11223344;
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;
}
2.1指针的解引用指针类型决定了指针+1跳过几个字节(步长)
如果是字符指针 ,+1跳过一个字节
如果是整形指针 ,+1跳过四个字节
#includeint main()
{int n = 0x11223344;
char* pc = (char*)&n;
int* pi = &n;
*pc = 0;
*pi = 0;
return 0;
}
3.野指针3.1野指针成因 指针未初始化野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
#includeint main()
{int *p;
*p = 20;
return 0;
}
指针越界访问局部变量指针未初始化,默认为随机值
int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10 };
int* p = arr;
int i = 0;
for (i = 0; i<= 10; i++)
{printf("%d\n", *p );
p++;
}
return 0;
}
指针指向的空间释放当指针指向的范围超过数组arr的范围 , p 就是野指针
int* test()
{int a = 10;
return &a;
}
int main()
{int *p = test();
printf("hehe\n");
printf("%d\n", *p);
return 0;
}
3.2如何规避野指针- 指针初始化
int main()
{int a = 10;
int* pa = &a;
return 0;
}
如果实在不知道指针指向哪里 也需要初始化
#includeint main()
{int* p = NULL;
if (p != NULL)
{}
return 0;
}
- 使用assert(断言)
assert中可以放一个表达式,如果表达式为假就报错,如果为真就什么也不发生
举个例子
void * my_strcpy(char* dest, const char* src)
{ assert(dest && src);//断言指针的有效性
//assert(dest!= NULL)
//assert(src!= NULL)
while (*dest++ = *src++)
{ ;
}
}
int main()
{char arr1[] = "hello";
char arr2[20] = {0 };
my_strcpy(arr2, arr1);
printf("%s\n", arr2);
return 0;
}
- 小心指针越界
- 指针指向空间释放,及时设置NULL
- 避免返回局部变量的地址
- 指针使用之前检查有效性
前提 :两个指针要指向同一块空间
指针-指针的绝对值得到的是两个指针之间的个数
int main()
{char ch[5] = {0};
int arr[10] = {0 };
printf("%d\n", &arr[0] - &arr[9]);
return 0;
}
4.3指针的关系运算标准规定:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
也就是说可以允许向后找到越界的地址和数组某个元素进行比较,但是不允许向前越界找到的地址和数组某个元素进行比较。这里的越界是指跳出了自己的范围,并没有非法访问越界之后的指针。这里只是比较大小。
#define N_VALUES 5
float values[N_VALUES];
float *vp;
for(vp = &values[N_VALUES]; vp >&values[0];)
{*--vp = 0;
}
5.指针和数组6.二级指针指针和数组是不同的对象
指针是一种变量,用来存放地址,大小为4/8个字节。
数组是一组相同类型元素的集合,是可以存放多个元素的,大小取决于元素个数和元素类型。
数组的数组名是数组首元素的地址,地址是可以放在指针变量中,可以通过指针访问数组。
int main()
{int a = 10;
int* pa = &a;
int* * ppa = &pa;
return 0;
}
7.指针数组pa是一级指针变量 ,ppa 是二级指针变量。 a 开辟了一块内存,用来存放数据 ,数据为10。 a的地址是0x0012ff40。 pa里面存放a的地址
存放指针的数组
使用一维数组模拟二维数组
int main()
{int a[] = {1,2,3,4 };
int b[] = {2,3,4,5, };
int c[] = {3,4,5,6 };
int* arr[] = {a , b ,c };
int i = 0;
for (i = 0; i< 3; i++)
{int j = 0;
for (j = 0; j< 4; j++)
{ printf("%d", arr[i][j] );
}
printf("\n");
}
return 0;
}
关于arr [i] [ j] 的解释: arr[ i] 当i 为 0 , 1 ,2 时 arr [0] 访问的是a数组首元素地址 arr[1] 访问的是b数组首元素的地址 arr[ 2] 访问的是c数组首元素的地址
*(arr [0] + j ) 当j是 0 , 1,2,3 时 ,就可以等价于 arr[0] [j ]
如果你觉得这篇文章对你有帮助,不妨动动手指给点赞收藏加转发,给鄃鳕一个大大的关注
你们的每一次支持都将转化为我前进的动力!!!
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
网页标题:学习指针这篇文章就够了!【c语言】-创新互联
当前URL:http://lswzjz.com/article/dcgcis.html