Linux笔记 --- 指针+数组

指针这种数据类型的使用极其频繁并且也很复杂所以在此单开一个笔记记录指针的特殊使用方法

二级指针

所谓二级指针就是指向指针的指针

cpp 复制代码
int a = 1;      
int *p1 = &a;   //指向a
int **p2 = &p1; //指向p1

printf("a:%d\n",a);
printf("%d\n",*p1);
printf("%d\n",**p2);//三种方式打印出来的都是a的值

上面例子里对p2进行了两次解引用,第一次解引用解出p1的值即a地址,第二次解引用就是解出a的数据

数组指针

指向数组的指针,此处所谓指向数组的指针不是只指向数组中的某个元素,而是指向整个数组,我们可以直接使用指针来间接访问数组的内容,实例:

cs 复制代码
int a[5] = {1,2,3,4,5};      
int (*p1)[5] = &a;   //指向a

int i=0;
for (i=0;i<5;i++)
{
    printf("%d\n",(*p1)[i]);
}

在此例中指针p1指向整个数组a,我们可以访问指针代替访问数组

函数指针

指向一个函数,也就是指向一段代码的指针,在使用中,函数名 其实就是函数的起始地址,那我们就可以指向函数名

cpp 复制代码
void swap(int *a,int *b)
{
    int temp;
    temp = *a;
    *a = *b;
    *b = temp;

}

int main(int argc, char const *argv[])
{
    void (*p)(int *a,int *b);//定义一个函数指针
    p = swap;
    
    int a = 1;
    int b = 2;

    p(&a,&b);

    printf("a:%d\n",a);
    printf("b:%d\n",b);

    return 0;
}

注意定义函数指针的类型一定要与函数的返回类型相同

二维数组

实际上并不存在真正的二维数组,所有数组都是一维的,区别就在于其中的元素,所谓二维数组就是**由两个具有三个整形元素组成的数组的数组,**只是这样叫太过繁琐因此取了个简称

cpp 复制代码
int (a[2]) [3];

上面例子就定义了一个二维数组,在括号中表明此数组是具有两个元素的名为a的数组,外部表明其中的元素的类型是int【3】的小数组

对于数组a来说首元素为a[0],首元素的首元素为a[0][0],

cpp 复制代码
    int arr[2][3]={{1,2,3},{4,5,6}};
    int (*pa)[2][3] = &arr;
    int (*pb)[3] = &arr[0];
    int *pc = &arr[0][0];

    printf("pa:%p\n",pa);
    printf("pa+1:%p\n",pa+1);

    printf("pb:%p\n",pb);
    printf("pb+1:%p\n",pb+1);

    printf("pc:%p\n",pc);
    printf("pc+1:%p\n",pc+1);



    //运行结果
    pa:0x7ffff50c7a10
    pa+1:0x7ffff50c7a28
    pb:0x7ffff50c7a10
    pb+1:0x7ffff50c7a1c
    pc:0x7ffff50c7a10
    pc+1:0x7ffff50c7a14

定义三个指针分别指向整个数组,数组中第一个元素,第一个元素中的第一个元素,再分别打印地址和指针加1,由此我们就能看出差别

零长数组

在Linux中我们需要在不同客户机间发送信息,这些信息中包括部分定长数据和不定长数据,比如用户自定义的文本和文件,那么我们在定义这个数据包时就可以用上零长数组

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>

struct package
{
   int  msg_len;
   char msg[0];
};

void test_package(struct package *p)
{
    printf("total len:%ld\n",sizeof(struct package)+p->msg_len);
    printf("msg:%s\n",p->msg);
}


int main(int argc, char const *argv[])
{
    //char *fgets(char *str, int n, FILE *stream) 从指定的流 stream 读取一行,
    // 并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,
    // 或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
    char buffer[100];
    while (1)
    {
        fgets(buffer,100,stdin);

        struct package *p = malloc(sizeof(struct package)+strlen(buffer)+1);
        p->msg_len =strlen(buffer)+1 ;
        strncpy(p->msg , buffer , p->msg_len);
        test_package(p);
    }
    
    return 0;
}

在此例子中零长数组就担任了表示可变字长数据的作用,搭配利用malloc函数进行动态的内存分配实现不同字长数据发送

const指针

使用const修饰的指针只能通过该指针访问这块地址的数据,但是不能通过这个指针对此地址的数据进行更改,虽然不能通过指针修改数据了但是不代表指针本身的指向不可以改变,被const修饰的指针也可以改变指向。

cpp 复制代码
int const *p;
int * const p;

而第二种方法中const是直接修饰的p变量,因此此指针可以改变地址中的数据但是不能改变指向地址

相关推荐
m0_678693332 分钟前
深度学习笔记29-RNN实现阿尔茨海默病诊断(Pytorch)
笔记·rnn·深度学习
sigmoidAndRELU1 小时前
读Vista
笔记·stable diffusion·世界模型
Sincerelyplz2 小时前
【Temproal】快速了解Temproal的核心概念以及使用
笔记·后端·开源
Yo_Becky3 小时前
【PyTorch】PyTorch预训练模型缓存位置迁移,也可拓展应用于其他文件的迁移
人工智能·pytorch·经验分享·笔记·python·程序人生·其他
DIY机器人工房3 小时前
0.96寸OLED显示屏 江协科技学习笔记(36个知识点)
笔记·科技·stm32·单片机·嵌入式硬件·学习·江协科技
future14125 小时前
每日问题总结
经验分享·笔记
循环过三天7 小时前
3-1 PID算法改进(积分部分)
笔记·stm32·单片机·学习·算法·pid
之歆7 小时前
Python-封装和解构-set及操作-字典及操作-解析式生成器-内建函数迭代器-学习笔记
笔记·python·学习
DKPT9 小时前
Java组合模式实现方式与测试方法
java·笔记·学习·设计模式·组合模式
受之以蒙9 小时前
Rust & WASM 之 wasm-bindgen 基础:让 Rust 与 JavaScript 无缝对话
前端·笔记·rust