我们已经学习了一段时间的C语言了,从今天开始,我们就要开始上难度了,就是指针,之前学的都是小儿科,今天开始我们才算真正的学习C语言了,所以,指针的第一部分,就此开始了!!!
就让我们走进指针,继续提升我们的能力,让我们在C语言的知识中继续遨游吧!!!
什么是指针?
指针就是内存的地址,指针变量就是保存内存地址的变量。
为了理解指针,就让我们来慢慢了解:
目录
(1)在32位机器上,地址是32个0/1的二进制序列,存储起来需要32个比特位,即4个字节。
(2) 在64位机器上,地址是64个0/1的二进制序列,存储起来需要64个比特位,即8个字节。
(3)指针变量不再使用时,及时置NULL,指针使用之前检查有效性
一、指针变量和地址
1、取地址操作符(&)
&a是取出a所占4个字节中地址较小的字节的地址
2.指针变量与解引用操作符(*)
指针变量也是⼀种变量,这种变量就是⽤来存放地址的,存放在指针变量中的值都会理解为地址。
在下面的代码中,p是变量,它的类型是int * ,其中,* 说明p是指针变量,int 说明p指向的是整型类型的对象。
* 就是解引用操作符(间接访问操作符),*p 等价于a。
我们用代码来进行验证:
#include<stdio.h>
int main()
{
int a = 10;
int* p = &a;
*p = 100;
printf("%d", a);
return 0;
}
//运行结果是100
3.指针变量的大小
指针变量需要多大空间取决于存放的地址需要多大空间,地址存放需要多大空间,指针变量的大小就是多大。
(1)在32位机器上,地址是32个0/1的二进制序列,存储起来需要32个比特位,即4个字节。
代码如下:
(2) 在64位机器上,地址是64个0/1的二进制序列,存储起来需要64个比特位,即8个字节。
代码如下:
二、指针变量类型的意义
我们已经学习了指针,但是为什么要学习指针?学习指针的意义是什么?我们就在这里解答。
1、指针的解引用
指针的类型决定了对指针解引用的时候有多大的权限(一次能操作几个字节)。
比如: char* 的指针解引用就只能访问⼀个字节,而int* 的指针的解引用就能访问四个字节。
2、指针 +- 整数
由上面的代码可以看出,char类型的指针+1跳过了1个字节,int 类型的指针+1跳过了4个字节,这就是指针变量类型带来的差异。
所以,指针的类型决定了指针向前或者向后走一步有多大。
3、void*指针
这里由于类型不兼容会有以上错误,这时候就该使用void*指针来接收地址了。
这时候我们就能看出来void*指针可以接收不同类型的指针了。
现在void*可以接收不同类型的地址,但是无法进行指针运算。至于为什么这样呢?我们会在后面的文章中解释。
三、const修饰指针
1、const修饰变量
我们看下面的代码,很明显,m和n都是可以被修改的,但是我们加上const呢?
在加上const以后就会报错了。
这里的const是常属性的意思,就是不能被修改了。虽然并不能被修改了,但n和m本质还是变量。
2、const修饰指针变量
(1)const放在*左边
代码如下:
在下面的代码中,const放在*的左边,限制的是*p,意思是不能通过p来改变p指向的对象的内容,但是p本身是可以改变的,p可以指向其他对象。
(2)const放在*右边
代码如下:
在下面的代码中,const放在*的右边,限制的是p,意思是不能修改p本身的值,但是p指向的内容是可以通过p来修改的。
总结:
所以,通过以上两个例子,我们可以总结出以下两条规律:
1.const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变,
但是指针变量本身的内容可变。
2.const如果放在*的右边,修饰的是指针变量本身,保证了指针变量的内容不能修改,但是指针指
向的内容,可以通过指针改变。
四、指针运算
1、指针运算
(1)指针 +- 整数
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
int* p = &arr[0];
for (int i = 0; i < sz; i++)
{
printf("%d ", *p);
p++;
}
return 0;
}
//运行结果为1 2 3 4 5 6 7 8 9 10
(2)指针 - 指针
运算的前提是两个指针指向同一块空间
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
printf("%d\n", &arr[9] - &arr[0]);
printf("%d\n", &arr[0] - &arr[9]);
//指针 - 指针的绝对值是指针和指针之间的元素个数
return 0;
}
//运算结果为: 9
// -9
指针 - 指针的应用:
模拟实现strlen
//方法一
#include<stdio.h>
int my_strlen(char*str)
{
int count = 0;
while (*str != '\0')
{
str++;
count++;
}
return count;
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
//方法二
#include<stdio.h>
int my_strlen(char* p)
{
char* p1 = p;
while (*p != '\0')
{
p++;
}
return p - p1;
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
(3)指针的关系运算
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
int* p = &arr[0];
while (p < arr + sz)
{
printf("%d ", *p);
p++;
}
return 0;
}
五、野指针
1、什么是野指针?
野指针就是指针指向位置是不可知的。
2、野指针成因
(1)指针未初始化
(2)指针越界访问
(3)指针指向的空间释放
#include <stdio.h>
int* test()
{
int n = 100;
return &n;
}
int main()
{
int* p = test();
printf("%d\n", *p);
return 0;
}
3、如何规避野指针
(1)指针初始化
#include <stdio.h>
int main()
{
int n = 10;
int* p1 = &n;
int* p = NULL;
return 0;
}
(2)小心指针越界
一个程序向内存申请了多少空间,通过指着就访问多少空间,不能超出范围。
(3)指针变量不再使用时,及时置NULL,指针使用之前检查有效性
当指针变量指向一块区域的时候,我们可以通过指针访问该区域,后期不再使用这个指针访问空间的时候,我们可以把指针置为NULL。
#include<stdio.h>
int main()
{
int a = 10;
int* p = &a;
if (p != NULL) //检查
{
*p = 20;
}
printf("%d", a);
return 0;
}
(4)避免返回局部变量的地址
到这里,咱们指针的第一部分就结束了,我们也确实可以感觉到指针并不简单,但是我们学习最好的方法就是去不断的复习,最好的是我们可以去找一些视频来学习,它比文章更直观,也更易理解。