当前位置: 首页 > article >正文

C语言指针详解与应用(不断更新)

指针简介

指针(Pointer)是C语言的一个重要知识点,其使用灵活、功能强大,是C语言的灵魂

指针与底层硬件联系紧密,使用指针可操作数据的地址,实现数据的间接访问

指针生活实例化

指针的本质是地址,在生活中比如你取快递时的快递单号,所发的位置地址,比如中国北京清华大学,这个就是地址,在生活中int(c语言的基本类型),就好比装water的容器,int a=0;可以这么理解有一个int类型的水杯,它的名字叫a,里面存放0这个水,但是我们如果想让舍友帮忙拿一下水杯,我们可以怎么说“哥们帮我拿一下我的水杯,在咱们宿舍里,我的桌子上”,其中“我的水杯(水杯类型的指针),在咱们宿舍里,我的桌子上”这个就是目前我的水杯的地址==(int *p=&a),这就是指针的实例化

计算机存储机制

int a = 0x12345678;

short b = 0x5A6B;

char c[ ] = {0x33, 0x34, 0x35};

指针

定义指针

指针即指针变量,用于存放其他数据单元(变量/数组/结构体/函数等)的首地址。若指针存放了某个数据单元的首地址,则这个指针指向了这个数据单元,若指针存放的值是0,则这个指针为空指针 定义一个指针变量:

 在定义指针时,它分配的字节大小是由计算机本身决定的,32位操作系统分配四个字节,64位操作系统分配8个字节

指针的操作

若已定义:  

 int a;        //定义一个int型的数据   

 int *p;      //定义一个指向int型数据的指针

q++理解:指向下一个(相邻的内存地址)char类型数据的地址,在内存中移动了sizeof(char)个位置

d++理解:指向下一个(相邻的内存地址)int类型数据的地址,在内存中移动了sizeof(int)个位置

其实可以等效理解为数组q++指向下一个存储单元

数组与指针

数组是一些相同数据类型的变量组成的集合,其数组名即为指向该数据类型的指针。数组的定义等效于申请内存、定义指针和初始化

例如:     char c[ ] = {0x33, 0x34, 0x35};

等效于:  申请内存         

                定义 char *c = 0x4000;

                初始化数组数据

利用下标引用数组数据也等效于指针取内容。

例如:    c[0];    等效于:    *c;

               c[1];    等效于:    *(c+1);

               c[2];    等效于:    *(c+2);

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    //第6页示例代码
    int *e;
    e=(int*)malloc(3*4);
    printf("(int*)malloc(3*4)= %x\n", (int*)malloc(3*4));//把分配到的首地址给e
    *e=10;
    *(e+1)=20;
    *(e+2)=30;
    printf("%d\n", *e);
    printf("%d\n", *(e+1));
    printf("%d\n", *(e+2));
    free(e);
    
    int n[]={1,2,3};
    printf("n[0]= %d\n", n[0]);
    printf("n[1]= %d\n", n[1]);
    printf("n[2]= %d\n", n[2]);

    printf("*n= %d\n", *n);
    printf("*(n+1)= %d\n", *(n+1));
    printf("*(n+2)= %d\n", *(n+2));
    
    char str[] = "Hello, World!";
    printf("%s\n", str);
    printf(str);
    return 0;
}

malloc:属于  #include <stdlib.h> 中的方法分配一个3*4这么大的内存空间,同时把它强转为int*类型,在使用完malloc之后要使用free();释放空间

数组的底层就是指针的操作,数组名e就是数组的地址,也是数组的第一元素的首地址

字符串的底层是数组

在底层,实际存储的时候,c语言还是会帮我们把字符串"abc"转换成字符数组进行保存,并且在未尾还要再加上"\0"

注意事项

在对指针取内容之前,一定要确保指针指在了合法的位置,否则将会导致程序出现不可预知的错误 同级指针之间才能相互赋值,跨级赋值将会导致编译器报错或警告

指针的应用

传递参数

使用指针传递大容量的参数,主函数和子函数使用的是同一套数据,避免了参数传递过程中的数据复制,提高了运行效率,减少了内存占用

使用指针传递输出参数,利用主函数和子函数使用同一套数据的特性,实现数据的返回,可实现多返回值函数的设计

#include <stdio.h>

// 函数:计算和与差
void calculate(int a, int b, int *sum, int *difference) {
    *sum = a + b;            // 计算和
    *difference = a - b;     // 计算差
}

int main() {
    int x = 10;
    int y = 5;
    int result_sum;        // 存放和
    int result_diff;       // 存放差

    // 调用函数
    calculate(x, y, &result_sum, &result_diff);

    // 输出结果
    printf("Sum: %d\n", result_sum);
    printf("Difference: %d\n", result_diff);

    return 0;
}

传递返回值

将模块内的公有部分返回,让主函数持有模块的“句柄”,便于程序对指定对象的操作

#include <stdio.h>
#include <stdlib.h>

// 定义一个结构体作为句柄
typedef struct {
    int *data;      // 动态数组指针
    int size;       // 数组大小
} ArrayHandle;

// 模块函数:创建动态数组
ArrayHandle createArray(int size) {
    ArrayHandle handle;
    handle.data = (int *)malloc(size * sizeof(int));
    handle.size = size;

    // 初始化数组
    for (int i = 0; i < size; i++) {
        handle.data[i] = i + 1; // 示例初始化
    }

    return handle; // 返回句柄
}

// 模块函数:释放动态数组
void freeArray(ArrayHandle *handle) {
    if (handle->data != NULL) {
        free(handle->data);
        handle->data = NULL; // 避免悬空指针
    }
}

// 模块函数:打印数组
void printArray(ArrayHandle handle) {
    for (int i = 0; i < handle.size; i++) {
        printf("%d ", handle.data[i]);
    }
    printf("\n");
}

int main() {
    // 创建动态数组句柄
    ArrayHandle myArray = createArray(5);

    // 打印数组内容
    printArray(myArray);

    // 释放动态数组
    freeArray(&myArray);

    return 0;
}

直接访问物理地址下的数据

访问硬件指定内存下的数据,如设备ID号等

将复杂格式的数据转换为字节,方便通信与存储

关于CLion的安装可以参考CLion安装、配置、使用、调试(完全小白向)-CSDN博客。


http://www.kler.cn/news/329247.html

相关文章:

  • MongoDB 入门及实践
  • 【cache】浅析四种常用的缓存淘汰算法 FIFO/LRU/LFU/W-TinyLFU
  • MongoDB 聚合管道
  • Springboot3 + MyBatis-Plus + MySql + Vue + ProTable + TS 实现后台管理商品分类(最新教程附源码)
  • Webpack和GuIp打包原理以及不同
  • IDM下载器如何下载网盘文件 IDM下载器支持哪些网盘
  • 【数据库】Java 集成mongodb— MongoTemplate 详解
  • OpenCV图像文件读写(6)将图像数据写入文件的函数imwrite()的使用
  • YOLO11改进|卷积篇|引入可变核卷积AKConv
  • 程序计数器(学习笔记)
  • Docker 进入容器运行命令的详细指南
  • “图像识别技术:重塑生活与工作的未来”
  • Linux:编译,调试和Makefile
  • Spring MVC系统学习(一)——初识Spring MVC框架
  • AIGAME平台的由来与未来展望 —— 蒙特加密基金推动区块链与AI融合创新
  • Redis篇(应用案例 - 短信登录)(持续更新迭代)
  • GEE教程:利用sentinel-2数据和NDVI指数监测火灾
  • Ansible实现剧本远程服务器创建、删除用户
  • SpringGateway(网关)微服务
  • MDM监管锁系统上锁流程
  • Redis 中 String 命令的基础操作
  • 【CKA】一、基于角色的访问控制-RBAC
  • 【分布式微服务云原生】消息队列全解析:原理、应用场景与主流MQ对比
  • 基于Qt/C++UDP 调试软件功能及用途介绍
  • 蓝桥杯【物联网】零基础到国奖之路:十五. 扩展模块之双路ADC
  • Android 利用OSMdroid开发GIS 添加点、线、面和标记点
  • 【STM32】【rt-thread】C函数调用
  • 深入理解机器学习中的 K-均值聚类算法及其优缺点
  • mp取数据,模糊查询redis
  • 对于基础汇编的趣味认识