• 语法复习之C语言与指针


    内存是如何存储数据的?

      在C语言中定义一个变量后,系统就会为其分配内存空间。这个内存空间包括了地址和长度。将变量赋值后,该值就被写入到了指定的内存空间中。内存空间的大小一般以字节作为基本单位。
      普通变量存放的是数据,指针变量存放的是地址。

    int a = 10 ; //定义了一个整型变量
    int *a ;//定义一个指向整型的指针变量
    
    • 1
    • 2

      为什么指针要有数据类型?因为在定义指针的时候,不光要定义指针的起始地址,还要定义指针的地址长度,方便分配内存空间。而指针变量的数据类型就是内存空间长度。
                  在这里插入图片描述
    由图可以看到地址和数据一一对应。

    取地址运算符和取值运算符

    //如果要获取某个变量的地址,可以使用取地址运算符&
    char *pa = &a;   //将字符串类型的变量a的地址赋值给字符串指针变量pa
    int *pb = &f; 	//将整型类型的变量f的地址赋值给整型变量指针pb
    
    //如果要访问指针变量指向的数据,可以使用取值运算符 *
    int *a = 0x100000000//定义一个整型指针变量a,该指针指向的地址为0x10000000
    b = *a ;   //将a指针指向的内存空间中0x10000000的值赋值给b
    printf("%c, &d\n\r",*pa, *pb);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    直接访问和间接访问

      通过指针变量来访问内存中的数据被称为直接访问
      通过定义变量并访问内存中的数据被称为间接访问

    //间接访问
    char *p_ptr = 0x10000000;
    char p;
    p = *p_ptr;
    //直接访问
    char p = 'a';
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    使用指针的注意事项

    //避免访问未初始化的指针,因为不知道该指针指向何处。语法上正确,但是会产生未知错误。
    int *a;
    *a = 123;
    
    • 1
    • 2
    • 3

    数组与指针

    数组与指针的基本关系

      数组名就是指针的首地址,也是数组第一个元素的地址。数组的下标代表的是指针的偏移,偏移量就是数组内存放的数据类型所占的字节数乘以下标。
      如果想用指针来指向数组,则可以直接用数组名赋值,或者用数组的第一个元素取地址。但是数组名和指针变量有区别。数组名属于右值,不可改变,但指针变量属于左值,可以改变。假如a是一个数组名。a++为错误写法。但是p=a;p++;是可以的。
      当指针变量p指向数组的第一个变量时,指针变量p+1则指向数组的第二个元素

    #include
    int main(){
    	char a[] = "FishC";
    	int b[5] = {1,2,3,4,5};
    	float c[5] = {1.1,1.2,1.3,1.4,1.5};
    	double d[5] = {1.1,2.2,3.3,4.4,5.5};
        printf("*****************************************\n");
    	printf("a[0] -> %p, a[1] -> %p, a[2] -> %p\n",&a[0], &a[1], &a[2]);
    	printf("b[0] -> %p, b[1] -> %p, b[2] -> %p\n",&b[0], &b[1], &b[2]);
    	printf("c[0] -> %p, c[1] -> %p, c[2] -> %p\n",&c[0], &c[1], &c[2]);
    	printf("d[0] -> %p, d[1] -> %p, d[2] -> %p\n",&d[0], &d[1], &d[2]);
        printf("*****************************************\n");
        int *p;
        p = b;
    	printf("p=b赋值时 p -> %p,\n",p);
        p = &b[0];
    	printf("p = &b[0]赋值时 p -> %p,\n",p);
        printf("*****************************************\n");
        printf("*p = %d, *(p+1) = %d, *(p+2) -> %d\n",*p, *(p+1), *(p+2));
        printf("*****************************************\n");
    	return 0 ;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    输出结果为

    *****************************************
    a[0] -> 0x7ffd2fdaaa30, a[1] -> 0x7ffd2fdaaa31, a[2] -> 0x7ffd2fdaaa32
    b[0] -> 0x7ffd2fdaa9c0, b[1] -> 0x7ffd2fdaa9c4, b[2] -> 0x7ffd2fdaa9c8
    c[0] -> 0x7ffd2fdaa9e0, c[1] -> 0x7ffd2fdaa9e4, c[2] -> 0x7ffd2fdaa9e8
    d[0] -> 0x7ffd2fdaaa00, d[1] -> 0x7ffd2fdaaa08, d[2] -> 0x7ffd2fdaaa10
    *****************************************
    p=b赋值时 p -> 0x7ffd2fdaa9c0,
    p = &b[0]赋值时 p -> 0x7ffd2fdaa9c0,
    *****************************************
    *p = 1, *(p+1) = 2, *(p+2) -> 3
    *****************************************
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    指针数组与数组指针

      指针数组是数组,数组指针是指针。
      指针数组是存放了多个指针的数组。数组指针是指向一整个数组的指针,并不是指向数组第一个元素的指针。虽然他们取值相同,但并不等价,因为他们存储数据的长度不同。

    指针数组

    int *p1[5];
    
    • 1

      首先从优先级开始分析,[]符号的优先级大于* ,所以优先看p1[5],这是一个数组,里面包含五个元素。后面看*,这是一个指针变量,所以p1[5]里面存放了五个指针变量,最后看int,表明了指针变量的存放的数据类型是int类型。结合起来就是定义了一个数组,数组的元素指针,指针指向的地址中存放的数据类型是int类型。

    int a = 1;
    int b = 2;
    int c = 3;
    int d = 4;
    int e = 5;
    int *p1[5] = {&a,&b,&c,&d,&e};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

      指针数组的实际用法

    #include
    int main(){
        char *p1[5] = {
            "char *a =\"hello\"代表的是一个字符串",
            "所以上一句中的a代表的是字符串的首地址",
            "char *p1[5]中的p1[5]存放了五个字符串的首地址",
            "%s代表用字符串的首地址来打印字符串",
            "所以%s中可以用p1[i]可以打印出字符串"
        };
        for(int i = 0; i < 5 ;i++){
            printf("%s\n",p1[i]);
        }
    	return 0 ;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    输出结果:

    char *a ="hello"代表的是一个字符串
    所以上一句中的a代表的是字符串的首地址
    char *p1[5]中的p1[5]存放了五个字符串的首地址
    %s代表用字符串的首地址来打印字符串
    所以%s中可以用p1[i]可以打印出字符串
    
    • 1
    • 2
    • 3
    • 4
    • 5

    数组指针

    int (*p2)[5]
    
    • 1

      也是从优先级开始分析,括号里面的优先级最高,所以p2被定义成了一个指针,指向了一个含有五个元素的数组。指针的类型就是他指向的数据类型,int定义的就是数组元素的类型。所以这个数组指针的含义是定义了一个数组指针p2,指针指向了含有五个整型元素的数组。

    #include
    int main(){
        int temp[5] = {1,2,3,4,5};  //  这是一个数组,temp是数组名。
        int (*p2)[5] = &temp;       //定义一个整形数组指针p2,p2指向数组temp本身 p2 = &temp
        int i;
        for(i=0;i<5;i++){
            printf("%d\n",*(*p2 + i));  //p2指向数组本身 p2 = &temp  *p2 = temp  所以*(*p2 + i) = *(temp + i)  即可遍历数组元素
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    输出结果

    1
    2
    3
    4
    5
    
    • 1
    • 2
    • 3
    • 4
    • 5

    函数与指针

      有些函数需要传递参数

  • 相关阅读:
    【文件I/O】标准IO:库函数
    redis多线程操作
    React 高阶组件
    Linux文件管理知识:文本处理
    预约美睫平台搭建,上门预约美睫平台该如何推广
    一个.Net Core开发的开源动态壁纸软件
    【原创】解决Kotlin无法使用@Slf4j注解的问题
    2023-2028年中国硫氰酸胍(GTC)市场研究及前景投资预测报告
    Linux:非常实用的Linux命令
    前端启动项目将http协议改为https协议
  • 原文地址:https://blog.csdn.net/q1594/article/details/134023140