C语言初阶——指针

这篇博客介绍了C语言中的指针基础知识,包括指针的概念、类型、指针+整数运算、指针的解引用、野指针及其规避方法、指针运算以及指针与数组的关系。通过学习,读者可以理解指针在C语言中的重要性和基本用法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天,我们要学习的是C语言中的指针。指针可以说是C语言中的重磅角色,能够理解和掌握指针,今后我们写起代码来,感觉将会是如鱼得水,游刃有余。接下来,赶紧让我们一起来看看吧!!!
本章目录:

1.指针是什么?

在计算机科学中,指针(pointer)是编程语言中的一个对象,利用地址,它的值直接指向存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的成为指针。意思是通过它能找到以它为地址的内存单元。
那我们就可以这样理解:
内存:
请添加图片描述
指针:指针是个变量,它存放内存单元的地址编号。通过下面的代码我们就可以得到指针:

#include<stdio.h>
int main()
{
    int a = 10;//我们在这里开辟一块空间
    int* p = &a;//用&操作符取出变量a的地址,p是一个指针变量
    printf("%p\n", p);
    return 0;
}

所以,指针就是一个变量,用来存放地址的变量。存放在指针中的值都被当做地址处理。
那这里的问题是:
1.一个内存单元它的地址是多大?——一个字节,8个二进制位。
2.如何编址?
经过仔细的计算和权衡,我们发现一个字节给一个对应的地址是比较合适的。对于32位机器,假设有32根地址线,那么假设每根地址线在寻址的时候,产生高电平和低电平,也就是计算机中的1或0,那么32根地址线就可以产生32位的二进制序列。相应的就会有2的32次方个地址,如果每个地址标识一个字节,就会有( 2 ^ 32 Byte== 2 ^ 32 /1024 KB == 2 ^ 32 /1024 /1024 MB == 2 ^ 32 /1024 /1024/1024 GB == 4GB)4G的空间进行编址。
同理,在64位平台上,地址就是8个字节。

2.指针和指针类型

我们都知道,变量有不同的类型,如整型、浮点型等。准确的说,指针也有类型
当有这样的代码:

int num = 10;
p = &num;

要将&num(num的地址) 保存到p中,我们知道p是一个指针变量,那它的类型是什么样的呢?我们给指针变量相应的类型:

char* pa = NULL;
int* pb = NULL;
short* pc = NULL;
long* pd = NULL;
float* pe = NULL;
double* pf = NULL;

这里我们可以看到,指针的定义方式是:type +
其实char
类型的指针是为了存放char类型的变量
int* 类型的指针是为了存放int类型的变量,
short* 类型的指针是为了存放short类型的变量
那指针类型的意义又是什么呢?

2.1指针+整数

#include<stdio.h>
int main()
{
    int n = 10;
    char* pc = (char*)&n;
    //这里将int*型的指针强制类型转换为char*型的指针
    int* pi = &n;

    printf("%p\n", &n);    //004FFBB0
    printf("%p\n", pc);    //004FFBB0
    printf("%p\n", pc + 1);//004FFBB1
    printf("%p\n", pi);    //004FFBB0
    printf("%p\n", pi + 1);//004FFBB4
    return 0;
}

通过上面这段代码,我们发现int型指针走一步为4个字节,char型的指针走一步是一个字节。我们可以得到:指针的类型决定了指针向前或向后走一步有多大。

2.2指针的解引用

#include<stdio.h>
int main()
{
    int n = 0x11223344;
    char* pc = (char*)&n;
    int* pi = &n;
    *pc = 0;//重点在调试的过程中观察内存的变化
    *pi = 0;//重点在调试的过程中观察内存的变化
    return 0;
}

总结:指针的类型决定了对指针解引用的时候有多大的权限,能操作几个字节。比如:char* 的指针决定了解引用只能访问一个字节,int* 的指针解引用就只能访问4个字节。

3.野指针

野指针:野指针就是指针指向的位置是不确定的,随机的、不正确的、没有明确限制的都叫做不正确的。

3.1野指针的成因

1.指针未初始化

#include<stdio.h>
int main()
{
    int* p;
    //局部变量指针未初始化,默认为随机值
    *p = 20;
    return 0;
}

2.指针越界访问

#include<stdio.h>
int main()
{
    int arr[10] = { 0 };
    int* p = arr;
    for (i = 0; i <= 11; i++)
    {
        *(p++) = i;
        //当指针指向范围超出数组arr范围的时候,p就是野指针
    }
    return 0;
}

3.指针指向的空间释放
这个知识点我会在动态内存开辟的时候讲解。

3.2如何规避野指针

1.指针初始化
2.小心指针越界
3.指针指向的空间释放及时置NULL.
4.避免返回局部变量的地址
5.指针使用之前检查有效性

4.指针运算

4.1.指针±整数

#define N_VALUES 5
float values[N_VALUES];
float* vp;
for (vp = &values[10]; vp < &values[N_VALUES];)
{
    *vp++ = 0;
}

2.指针-指针

int my_strlen(char* s)//计算字符串长度
{
    char* p = s;
    while (*p != '\0')//'\0'是字符串结束标志
        p++;
    return p - s;
}

3.指针的关系运算

for (vp = &values[10]; vp > &values[N_VALUES];)
{
    *--vp = 0;
}
//代码简化:将代码修改如下
for (vp = &values[10]; vp > &values[N_VALUES];vp--)
{
    *vp = 0;
}

实际上在绝大部分的编译器上是可以顺利完成任务的,然而我们还是要避免这样写,因为标准并不保证它可行。
标准规定:允许数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较。但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。

5.指针和数组

数组名是什么?我们看下面的代码:

#include<stdio.h>
int main()
{
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    printf("%p\n", arr); //00AFFAB0
    printf("%p\n", &arr[0]); //00AFFAB0
    return 0;
}

我们可以看到,数组名和数组首元素的地址是一样的,结论是数组名实际上就是数组首元素的地址

6.二级指针

指针变量也是变量,有变量就有地址,那么指针变量的地址存放在哪里呢?答案是二级指针。关于二级指针的内容我会在C语言高阶中的指针那里讲解,敬请期待。

7.指针数组

指针数组是数组还是指针呢?答案是数组!

int* arr[5];

arr 是一个数组,有5个元素,每个元素都是一个整型指针。
关于指针的内容就先讲到这里,初阶指针,大家只需要能够简单运用即可,无需深究。我会在高阶指针那部分,和大家一起更加深入的挖掘指针。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暗月の流星劫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值