page contents

C语言的灵魂—指针

c语言指针可以有效地表示复杂的数据结构、动态分配内存、高效地使用数组和字符串、使得调用函数时得到多个返回值等。指针的应用往往与数组联系在一起,是最频繁的,也是最基础的。参数传递时只需要拷贝地址值,提高程序的运行效率。有效的表示数据结构,能动态分配内存。

指针是什么

在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。总结来说,指针就是指向地址的变量!

指针的作用

c语言指针可以有效地表示复杂的数据结构、动态分配内存、高效地使用数组和字符串、使得调用函数时得到多个返回值等。指针的应用往往与数组联系在一起,是最频繁的,也是最基础的。参数传递时只需要拷贝地址值,提高程序的运行效率。有效的表示数据结构,能动态分配内存。

指针的语法

指针变量的定义: 类型 * 指针变量名 &:表示取地址操作 *: 表示取地址中的值

怎么去理解指针

大家可能一时半会可能很难理解指针含义。我们的计算机都会有一个内存,并且这个内存的每一个部分有一个标记表示它的位置,这个标识就是我们的地址,地址对应的区域存放的就是我们的数据(值)。就像我们住酒店,酒店是内存,门牌号是我们的地址,住在房间里的人就是我们的数据!

代码示例

#include<stdio.h>

int main(){
    int num = 10;
    double num2 = 10.0;
    int * p ;
    p = &num;

    //这种不同类型的变量之前的操作是不合法的
    // p = &num2;

    printf("p = %p\n",p);
    printf("num = %d\n",num);
    printf("*p = %d\n",*p);

    // num 和 p代表的是同一个地址的数据,
    // 当使用 *p 去修改数据的时候,num代表的数据也会改变!
    *p = 11;
    printf("p = %p\n",p);
    printf("num = %d\n",num);
    printf("*p = %d\n",*p);

    return 0;
}

/*
    运行结果:
        p = 0x7ffee1eee7c8
        num = 10
        *p = 10
        p = 0x7ffee1eee7c8
        num = 11
        *p = 11
*/
复制代码

通过以上代码我们不难理解:指针变量中,p 存放的是地址,*p 是取地址对应的值。num 变量直接存放地址对应的值!当我们使用 *p 修改数据的时候,我们 num 的存放的值也会发生改变!我们使用 & 符号即可取出变量的地址 举个例子,p 存放的是门牌号,*p 代表居住的客人,num 也是代表这个门牌号下居住的客人,当使用 *p 修改掉居住的人,num 也会发生相应的改变,因为他们代表的都是这个门牌号下居住的人。&num 即代表取出这个客人的房间门牌号

什么是双重(n重)指针

我们根据之前的解释可以知道,每个变量在内存中都有一个地址相对应。双重指针实际上存放的全是地址。

代码示例

#include<stdio.h>

int main(){
    int num = 10;
    int * p;
    p = &num;

    // 双重指针
    int  ** q;

    // 指针变量也是变量的一种,即 p 也是有对应的地址
    // &p 即取 p 变量的地址
    q = &p;

    // p 变量存放的地址 ,即num变量的地址
    printf("p = %p\n",p);
    // p 变量自身的地址
    printf("p = %p\n",&p);
    // q 存放的地址就是 p 变量自身的地址
    printf("q = %p\n",q);
    // *p == num
    printf("*p = %d\n",*p);  
    // **q == *p == num
    printf("**q = %d\n",*p);

    return 0;
}

/*
    执行结果:
        p = 0x7ffee910c7c8
        p = 0x7ffee910c7c0
        q = 0x7ffee910c7c0
        *p = 10
        **q = 10
*/
复制代码

图解

graph LR
    q --> p
    p --> num
复制代码

n重指针

n重指针同理

数组实际上使用的就是指针,我们再学习下数组类型

指针函数和函数指针

指针函数

顾名思义,指针函数就是返回值为指针的函数

语法示例

#include <stdio.h>

int *fun(int a, int b, int *p)
{
    *p = a + b;
    return p;
}
int main()
{
    int *p;
    p = fun(10, 10, p);
    printf("%d \n", *p);
    return 0;
}
/*
    执行结果:
        20
*/
复制代码

函数指针

函数指针就是指向函数的指针。一个函数标识符就表示了它的地址

示例代码

#include <stdio.h>

int add(int a, int b)
{
    return a + b;
}

int sub(int a, int b)
{
    return a - b;
}

int (*fun)(int a, int b);

int main()
{
    // 函数指针用法一
    fun = add;
    //调用方法二
    printf("%d \n", fun(10, 10));

    //用法二
    fun = &sub;
    //调用方法一
    printf("%d \n", (*fun)(10, 10));
    return 0;
}
/*
    执行结果:
        20
        0
*/
复制代码

一维数组

语法规则

类型名 变量名 [数组大小] 字符串数组:C语言中一个字符串的界定范围是 '\0',当遇到'\0'时认为字符串已经结束

语法示例

#include<stdio.h>

int main(){
    char chs[100] = {'a','b','c','\0'};
    printf("chs = %s\n",chs);

    //指针版示例
    printf("point verion:\n");
    printf("chs = ");
    for(int i = 0; *(chs + i) != '\0';i ++){
        printf("%c",*(chs + i));
    }
    printf("\n");
    return 0;
}

/*
    运行结果:
    chs = abc
    point verion:
    chs = abc
*/
复制代码

我们从示例代码中可以看到: chs[i] 等价于 * (chs + i)

二位数组

语法定义

类型名 数组变量名称 [行数][列数]

代码示例

#include <stdio.h>

int main()
{

    //未初始化的数组其值是不确定的
    int arr[7][7] = {0};

    //输入行数
    printf("%lu\n", sizeof(arr) / sizeof(arr[0]));

    //输出列数
    printf("%lu\n", sizeof(arr[0]) / sizeof(int));

    //打印数组信息 数组实际上就是二维指针
    for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
    {
        for (int j = 0; j < sizeof(arr[0]) / sizeof(int); j++)
        {
            printf("%d ", (*(arr + i) + j));
        }
        printf("\n");
    }

    // 打印数组的地址信息 可以看到,数组实际上是一块连续的地址空间
    for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)  
    {
        for (int j = 0; j < sizeof(arr[0]) / sizeof(int); j++)
        {
            printf("%p ", (*(arr + i) + j));
        }
        printf("\n");
    }
    return 0;
}

/*
    执行结果:
    7
    7
    0 0 0 0 0 0 0
    0 0 0 0 0 0 0
    0 0 0 0 0 0 0
    0 0 0 0 0 0 0
    0 0 0 0 0 0 0
    0 0 0 0 0 0 0
    0 0 0 0 0 0 0
    0x7ffee5a9d700 0x7ffee5a9d704 0x7ffee5a9d708 0x7ffee5a9d70c 0x7ffee5a9d710 0x7ffee5a9d714 0x7ffee5a9d718
    0x7ffee5a9d71c 0x7ffee5a9d720 0x7ffee5a9d724 0x7ffee5a9d728 0x7ffee5a9d72c 0x7ffee5a9d730 0x7ffee5a9d734
    0x7ffee5a9d738 0x7ffee5a9d73c 0x7ffee5a9d740 0x7ffee5a9d744 0x7ffee5a9d748 0x7ffee5a9d74c 0x7ffee5a9d750
    0x7ffee5a9d754 0x7ffee5a9d758 0x7ffee5a9d75c 0x7ffee5a9d760 0x7ffee5a9d764 0x7ffee5a9d768 0x7ffee5a9d76c
    0x7ffee5a9d770 0x7ffee5a9d774 0x7ffee5a9d778 0x7ffee5a9d77c 0x7ffee5a9d780 0x7ffee5a9d784 0x7ffee5a9d788
    0x7ffee5a9d78c 0x7ffee5a9d790 0x7ffee5a9d794 0x7ffee5a9d798 0x7ffee5a9d79c 0x7ffee5a9d7a0 0x7ffee5a9d7a4
    0x7ffee5a9d7a8 0x7ffee5a9d7ac 0x7ffee5a9d7b0 0x7ffee5a9d7b4 0x7ffee5a9d7b8 0x7ffee5a9d7bc 0x7ffee5a9d7c0
*/
复制代码

数组相关的函数

#include <stdio.h>
int main(){
    char old[100];
    char new[200];
    int n = 10;

    //字符数组操作函数
    //将旧数组的数据拷贝到的新的数组之中。旧数组的数据遇到了\0就停止复制。新数组的长度必须大于等于旧数组数据长度 + 1
    strcpy(new,old);

    //  将旧数组的前n位字符拷贝到新数组中。新数组的长度必须大于等于新数组原数据长度 + 旧数组数据长度 + 1
    strncpy(new,old,n);

    //两个字符数组进行比较。首先从第一位开始逐位比较,按照字典序的大小进行比较。遇到第一个不等的字符或者遇到了\0停止比较。等于返回0,new < old返回 -1,new > old 返回 1
    strcmp(new,old);

    //将两个字符串进行连接。新数组的长度必须大于等于 新数组的数据长度 + 旧数组的数据长度 + 1
    strcat(new,old);

    return 0;
}
  • 发表于 2020-12-12 10:06
  • 阅读 ( 478 )
  • 分类:C/C++开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
Pack
Pack

1131 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. Pack 1131 文章
  3. 小柒 1046 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章