问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

C语言指针·入门用法超详解

创作时间:
作者:
@小白创作中心

C语言指针·入门用法超详解

引用
CSDN
1.
https://m.blog.csdn.net/MANONGDKY/article/details/140794951

本文详细介绍了C语言中指针的概念、定义格式以及其多种应用场景。通过理论解释配合代码示例,逐步展示了指针在查询数据、存储数据、操作其他函数中的变量、函数返回多个值以及函数结果和计算状态分开等场景中的具体应用。

1. 什么是指针

通过内存地址,指向的空间,我们可以对空间的数据进行修改,而这个内存地址就被称为指针。

在代码当中,我们会拿一个变量将指针进行存起来,那么这个变量就叫做指针变量。

通常情况下,我们会将指针变量,称为指针,但我们需要了解,真正的指针,实际上是指针变量存起来的内存地址。

2. 指针变量的定义格式

指针变量起始就是存着指针的变量,本身也是变量,而我们变量的定义格式是:

数据类型 变量名;

但如果我们要是这样声明指针变量,那么就无法和普通变量做一个区分,因此我们将指针的数据类型和变量名之间加一个“*”进行区分:

数据类型 * 变量名;

对于指针变量的数据类型要跟指向的变量类型保持一致,例如:

int a = 10;
int* p1 = &a;
double b = 10;
double* p2 = &b;

对于指针变量的可以理解为这是一个标记,见到我们可以理解为此时声明的变量为指针变量,他右面声明的变量名,所存储的是内存地址,例如以上代码的p1,p2。

对于指针变量的变量名,就是字节起的名字,可随意取,但是需要避开关键字。

3. 指针的作用

3.1 查询数据

格式:*指针名

其中*在这里是解引用运算符

首先我们创建如下代码:

int a = 10;         //①
int* p = &a;         //②
printf("%d\n", *p); //③
*p = 200;           //④
printf("%d\n", *p); //⑤

对于①我们可以理解为,在一个内存当中存储一个变量,这个变量的数据为10,下面我们假设这个数据存储的内存地址位0x0011:

对于②我们可以理解为,我获取了变量a的地址,在存储到指针p当中,指针p可以通过内存地址指向了变量a:

对于③中的p,我们直到此时的p代表地址0x0011,而p代表通过内存地址获取改地址下变量数据的意思,因此此时输出的数据为10;

注意:这里会有人将指针变量格式的和解引用运算符的混淆:

指针变量格式的定义指针的*,仅仅作为标记使用,告诉你*右边的变量记录的是内存地址;

而查询数据里面的是解引用运算符,他表示通过后面的内存地址去获取到对应的数据。

3.2 存储数据(修改数据)

格式:*指针名 = 数据值;

对于④,我们可以理解为修改改地址下的数据,及此时0x0011下的数据会从10变为200:

完整代码:

#include <stdio.h>
int main()
{
    int a = 10;
    //定义一个指针变量a
    int* p = &a;
    //利用指针获取变量中的数据
    printf("%d\n", *p);
    //利用指针去存储数据/修改数据
    *p = 200;
    //输出打印
    printf("%d\n", a);
    printf("%d\n", *p);
}

指针使用细节:

(1)指针变量的名字,例如int* p需要分开;

(2)指针变量的数据类型要跟指向的变量的类型保持一致;

(3)指针变量占用的大小,跟数据类型无关,跟编译器有关,32位的是4字节,64位的是8字节。对于这里我们可以看一下:C++学习之指针-CSDN博客的1.3中的介绍;

(4)给指针变量赋值的时候,不能把一个数值赋值给指针变量。例如下图右侧,因为对于500编译器并未分配该空间的内存地址,要是将其赋值给p编译器会报错。

3.3 操作其他函数中的变量

在使用,指针变量前,我们先来了解一下普通变量的值传递,编写代码:

#include <stdio.h>
void swap(int num1, int num2);
int main()
{
    //定义两个变量,要求交换变量中记录的值
    //注意:交换的代码写在一个新的函数swap中
    //定义两个变量
    int a = 10;
    int b = 20;
    //调用swap函数
    printf("调用前:%d,%d\n", a, b);
    swap(a, b);
    printf("调用后:%d,%d\n", a, b);
    return 0;
}
void swap(int num1, int num2)
{
    int temp = num1;
    num1 = num2;
    num2 = temp;
}

该段代码主要想要实现的功能是:定义两个变量,要求交换变量中记录的值,但是我们会发现调用了交换变量的函数,但是a和b的值并未发生转换,那是因为上面这段函数,仅仅是将a和b的值赋值给了num1和num2:

变量之间值的交换也仅仅是num1和num2值的交换,根本就没有修改a和b的值:

因此最终输出的结果会是:

那么我们如何实现不同函数之间,值的修改呢?

这里我们就可以使用指针变量的功能,修改代码:

#include <stdio.h>
void swap(int* p1, int* p2);
int main()
{
    //定义两个变量,要求交换变量中记录的值
    //注意:交换的代码写在一个新的函数swap中
    //定义两个变量
    int a = 10;
    int b = 20;
    //调用swap函数
    printf("调用前:%d,%d\n", a, b);
    swap(&a, &b);
    printf("调用后:%d,%d\n", a, b);
    return 0;
}
void swap(int* p1, int* p2)
{
    int temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}

这里我们可以理解为swap(&a,&b)是将a和b的内存地址,也就是指针指向的变量作为参数p1和p2,通过指针操作,将p1指向的值和p2指向的值进行交换,实现了变量值的交换:

注意:

函数中的变量的生命周期跟函数相关,函数结束消失,变量也会消失,此时在其他函数中,就无法通过指针使用了:

#include <stdio.h>
int* method();
int main()
{
    //调用method函数,并使用该函数的变量a
    int* p = method();
    printf("%d\n", *p);
    return 0;
}
int* method()
{
    int a = 10;
    return &a;
}

此时运行我们会发现:

为什么,不是说函数结束消失,变量也会消失吗?这是一个偶然发生的概念,那是因为我们执行完 int* p = method(); 并没有别的代码执行,此时这一块内存还没来得及被回收,所以此时还能使用到变量a,那我们就在该段指令后拖点时间多执行几条指令:

#include <stdio.h>
int* method();
int main()
{
    //调用method函数,并使用该函数的变量a
    int* p = method();
    printf("拖点时间\n");
    printf("拖点时间\n");
    printf("拖点时间\n");
    printf("拖点时间\n");
    printf("拖点时间\n");
    printf("拖点时间\n");
    printf("拖点时间\n");
    printf("%d\n", *p);
    return 0;
}
int* method()
{
    int a = 10;
    return &a;
}

会发现:

如果不想函数中的变量被回收,可以在变量前加static关键字:

#include <stdio.h>
int* method();
int main()
{
    //调用method函数,并使用该函数的变量a
    int* p = method();
    printf("拖点时间\n");
    printf("拖点时间\n");
    printf("拖点时间\n");
    printf("拖点时间\n");
    printf("拖点时间\n");
    printf("拖点时间\n");
    printf("拖点时间\n");
    printf("%d\n", *p);
    return 0;
}
int* method()
{
    static int a = 10;
    return &a;
}

3.4 函数返回多个值

老样子,我们下不使用指针看看如何实现:

#include <stdio.h>
//函数返回多个值
int main()
{
    //定义一个函数,求数组的最大值和最小值,并进行返回
    return 0;
}
void getMaxAndMin(int arr[], int len)
{
    //求数组的最大值
    int max = arr[0];
    for (int i = 0; i < len; i++)
    {
        if (arr[i] > max)
        {
            max = arr[i];
        }
    }
    //求数组的最小值
    int min = arr[0];
    for (int i = 0; i < len; i++)
    {
        if (arr[i] < min)
        {
            min = arr[i];
        }
    }
    int res[] = { max, min };
    return res;
}

我们正常情况下,一个函数只能返回一个值,而若是我们想要返回多个值,我们可以如上代码,创建一个数组,将想要返回的值全部保存到数组内,不过这样会出现,若是别人想要调用你这个函数,还要读懂你这个函数,了解你这个函数的返回值,每一位都代表什么,比较麻烦,那么如何更简便一些呢?

我们可以直接使用指针操控该内存地址的值,进行修改变量,达到返回值的目的:

#include <stdio.h>
void getMaxAndMin(int arr[], int len, int* max, int* min);
//函数返回多个值
int main()
{
    //定义一个函数,求数组的最大值和最小值,并进行返回
    //定义数组
    int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int len = sizeof(arr) / sizeof(arr[0]);
    //调用getMaxAndMin求最大值和最小值
    int max = arr[0];
    int min = arr[0];
    getMaxAndMin(arr, len, &max, &min);
    printf("数组最大值为:%d\n", max);
    printf("数组最小值为:%d\n", min);
    return 0;
}
void getMaxAndMin(int arr[], int len, int* max, int* min)
{
    //求数组的最大值
    *max = arr[0];
    for (int i = 0; i < len; i++)
    {
        if (arr[i] > *max)
        {
            *max = arr[i];
        }
    }
    //求数组的最小值
    *min = arr[0];
    for (int i = 0; i < len; i++)
    {
        if (arr[i] < *min)
        {
            *min = arr[i];
        }
    }
}

其中,如何求len可以参考2.2.1:C++学习之数组-CSDN博客

3.5 函数的结果和计算状态分开

继续我们编写一个小例子:

#include <stdio.h>
//函数的结果和计算状态分开
int main()
{
    //定义一个函数,将两个数相除,获取他们的余数
    return 0;
}
int getRemainder(int num1, int num2)
{
    if (num2 == 0)
    {
        return ???;
    }
    int res = num1 % num2;
    return res;
}

首先,定义一个函数,将两个数相除,获取他们的余数,然后return 返回值res,但是这就会出现一个问题,若是num2==0,那么等式将会不成立,那么我们就需要加一个判断条件if(num2==0)进行返回别的值,但是此时返回什么呢?当然我们代码也可以这样写:

#include <stdio.h>
//函数的结果和计算状态分开
int main()
{
    //定义一个函数,将两个数相除,获取他们的余数
    return 0;
}
int getRemainder(int num1, int num2)
{
    if (num2 != 0)
    {
        int res = num1 % num2;
    }
    return res;
}

或者也可以写为:

#include <stdio.h>
//函数的结果和计算状态分开
int main()
{
    //定义一个函数,将两个数相除,获取他们的余数
    return 0;
}
int getRemainder(int num1, int num2)
{
    if (num2 == 0)
    {
        return -1;
    }
    int res = num1 % num2;
    return res;
}

这两种方法都可以完成,除此之外,我们也可以使用指针来进行操作:

#include <stdio.h>
//函数的结果和计算状态分开
int main()
{
    //定义一个函数,将两个数相除,获取他们的余数
    //定义两个变量
    int a = 10;
    int b = 3;
    int res = 0;
    
    //调用函数获取余数
    int flag = getRemainder(a, b, &res);//获取getRemainder(a, b, &res);的返回值赋值给flag
    //对状态进行判断
    if (!flag)
    {
        printf("获取到的余数为:%d\n", res);
    }
    return 0;
}
//此时返回值表示计算的状态,0表示正常,1表示不正常
int getRemainder(int num1, int num2, int* res)
{
    if (num2 == 0)
    {
        return 1;
    }
    *res = num1 % num2;
    return 0;
}

指针_时光の尘的博客-CSDN博客

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号