C语言 指针

C语言 指针

最近接触到C语言的一个项目,碰到一些关于指针的问题,在这总结一下,以供以后学习

指针的本质

指针可以简单理解为内存地址。在代码中常说的指针变量,其含义是指向某一种变量的在内存中的地址,实质表现为。但同时也需要注意,指针本身也是一种变量,所以也存在指针的指针,即指向某一指针变量的地址。
案例1:

#include <stdio.h>
int main() {
    int a=1;
    int *p;
    int **pp;
    p=&a;
    pp=&p;
    printf("0x%x\n",p);
    printf("size:%d\n",sizeof(p));
    printf("0x%x\n",pp);
    printf("size:%d\n",sizeof(pp));
    return 0;
}

输出:

0x61fe14
size:8
0x61fe08
size:8

从案例1中可以看出,对于int类型a,使用符号‘&’获取变量a的地址,并赋值给指针变量p。同理,获取指针变量p的指针,复制给pp,即指针变量的指针。、

对于指针变量本身来说,其存储在C语言编译器的栈空间中,指向的是堆空间。且由于C语言本身的特殊性,其指针空间的大小与编译机器有关,与指向的类型无关(指针在栈中独占一行,而栈的大小受编译机器相关)。比如案例1中,使用的是64位win11,其指针大小是4个字节,即64比特位。

运用

指针的运算

指针变量也能参与运算,且其运算过程主要用于指针地址之间的上移或者下移,以及通过上下移动统计特定类型数据的个数。
案例2:

#include <stdio.h>
int main() {
    int nums[]={1,2,3,4,5};
    int *p1=&nums[0];
    int *p2=&nums[4];

    char str[]={"hello world"};
    char *q1=&str[0];
    char *q2=&str[10];

    //指针移动
    printf("p1:%p\n",p1);
    printf("p1+1:%p\n",p1+1);
    printf("*p1:%d\n",*p1);
    printf("*(p1+1):%d\n",*(p1+1));

    printf("q1:%c\n",*q1);
    printf("q2:%c\n",*q2);

    printf("q1+2:%s\n",q1+2);

    //指针移动
    printf("p2-p1:%d\n",p2-p1);
    printf("q2-q1:%d\n",q2-q1);
}

输出:

p1:000000000061FDE0
p1+1:000000000061FDE4
*p1:1
*(p1+1):2
q1:h
q2:d
*(q1+2):llo world
p2-p1:4
q2-q1:10

从案例2中可以看出,指针除了指定变量的内存地址之外还能衍生出另外三个作用:

  1. 通过对指针加减,让指针指向另外的数据。在案例2中,对于数组元素nums和str,在指向数组头的时候,可以对指针使用加法,从而让指向变化到临近的元素。(需要注意的时,对指针使用加减法,不是对于内存地址直接加减法,而是相对于指针的类型,一次性加减相对于指向类型的字节数。比如对于int类型,p1+1相当于p1向下移动4个字节(int的大小))
  2. 对于字符串数组来说,当使用指针来输出字符串时,可以使用指针来确定输出字符串的起始点。在案例2中,对字符指针q2,在加2的情况下,使用printf("q1+2:%s\n",q1+2)输出字符串,可以看到输出字符串是从字符串指向位置开始,直至‘\0’结束。
  3. 由第一个作用,可以从指向同一数组的指针中,判断两个指针之间的距离或者说是两个指向位置之间元素个数。比如案例2中,printf("p2-p1:%d\n",p2-p1),可以判断出两个指针中有多少元素。

字符串使用

对于字符串,即字符数组,在使用指针的时候有一些特殊情况。
案例3:

#include <stdio.h>
#include<stdlib.h>
int main() {
    char str[]={"hello world"};
    char *p=str;
    char *q1=&str[0];
    char *q2;
    q2=(char *)malloc(sizeof(char));

    //str=&str[0]??
    if(p==q1){
        printf("true\n");
    }else{
        printf("false\n");
    }
    //以指针输入和输出、
    //注意:q2要提前声明存储空间
    scanf("%s",q2);
    printf("%s",q2);
}

输出:

true
121212
121212

注意:

  1. 对于字符数组来说,其数组名是一个地址,且指向的是数组的第一个元素。在案例3中,可以发现str=&str[0]成立。
  2. 对于字符串的输入和输出,均是以数组名,即指针为实参。

指针数组

由指针组成的数组。

定义:element *数组名[]

#include <stdio.h>
#include<stdlib.h>
int main()
{
    int *p[2];
    int a=1;
    int b=2;
    p[0]=&a;
    p[1]=&b;
    for (int i = 0; i < 2; ++i) {
        printf("%d\n",*p[i]);
    }
    return 0;
}

数组指针

指向数组的指针。主要用在二维数组。

定义:element (*指针名)[]

#include <stdio.h>
#include<stdlib.h>
int main()
{
    int (*p)[2];
    int a[2]={1,2};
    p=&a;
    for (int i = 0; i < 2; ++i) {
        printf("%d\n",*(*p+i));
    }
    return 0;
}

结构体使用

#include <stdio.h>
#include<stdlib.h>
#include<string.h>
struct Student
{
    int age;
    char firstname[10];
    char *secondname;
};
int main()
{
    //不使用指针
    struct Student A;
    A.age=10;
    strcpy(A.firstname,"Wu");
    strcpy(A.secondname,"Yanzu");

    printf("%s ",A.firstname);
    printf("%s\n",A.secondname);

    //使用指针
    struct Student *B;
    B=(struct Student *)malloc(sizeof(struct Student));
    strcpy(B->firstname,"liu");

    //strcpy(B->secondname,"Yifei");  错误用法
    B->secondname="Yifei";
    printf("%s ",B->firstname);
    printf("%s",(*B).secondname);

    return 0;
}

char * secondname和char firsrname[]是不一样的,具体看引用3。

注意:以下 3 种形式是等价的:
结构体变量.成员名。
(*指针变量).成员名。
指针变量->成员名。

还有一部分没写完。。。。

ref:

  1. https://blog.csdn.net/weixin_59174190/article/details/123420800
  2. https://zhuanlan.zhihu.com/p/442422112
  3. https://blog.csdn.net/edward_zcl/article/details/89451078

本文作者:weliars

本文链接:https://www.cnblogs.com/weliars/p/16631700.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   weliars  阅读(74)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起