printf 指针地址_C语言基础(中)——指针,C语言的灵魂

C语言的灵魂—指针

指针是什么

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

指针的作用

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

指针

指针的语法

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

怎么去理解指针

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

代码示例
#include

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

    //这种不同类型的变量之前的操作是不合法的
    // 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

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

    // 双重指针
    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 

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 

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 = ⊂
    //调用方法一
    printf("%d \n", (*fun)(10, 10));
    return 0;
}
/*
    执行结果:
        20
        0
*/

一维数组

语法规则

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

语法示例

#include

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 

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 
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;
}

以上就是本期的全部内容了,感谢你能看到这里。我们下期见!

a35d48fd8f9811a58ff2f3301fe957b7.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值