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

【C语言】指针篇

目录

  • C 语言指针概述
    • 指针的声明和初始化
      • 声明指针
      • 初始化指针
    • 指针的操作
      • 解引用操作
      • 指针算术运算
    • 指针的用途
      • 动态内存分配
      • 作为函数参数
  • 指针与数组
    • 数组名作为指针
    • 通过指针访问数组元素
    • 指针算术和数组
    • 数组作为函数参数
    • 指针数组和数组指针
      • 指针数组
      • 数组指针
  • 函数指针
    • 函数指针的定义和声明
    • 函数指针的初始化和使用
    • 函数指针作为函数参数(回调函数)
    • 函数指针数组
  • 动态内存分配
    • 概念
    • 动态内存分配函数
      • malloc 函数
      • calloc 函数
      • realloc 函数
      • free 函数
    • 示例代码
    • 注意事项
  • 常见错误与规避
    • 内存泄漏(Memory Leak)
    • 空指针引用(Null Pointer Dereference)
    • 重复释放内存(Double Free)
    • 越界访问(Buffer Overflow)
    • realloc 使用不当

C 语言指针概述

在 C 语言中,指针是一个非常重要且强大的概念。它是一个变量,其值为另一个变量的地址,即内存位置的直接地址。可以把指针想象成一个特殊的变量,它存储的不是普通的数据,而是内存中某个变量的地址。通过指针,我们可以直接访问和操作该内存地址上存储的数据。

指针的声明和初始化

声明指针

在 C 语言中,声明指针的一般语法如下:

数据类型 *指针变量名;

其中,数据类型 表示该指针所指向的变量的数据类型,* 是指针声明符,用于表明这是一个指针变量。例如:

int *p;  // 声明一个指向整型变量的指针p
float *q; // 声明一个指向浮点型变量的指针q

初始化指针

指针可以在声明时进行初始化,也可以在声明后再赋值。指针初始化时,需要将一个变量的地址赋给它。使用 & 运算符可以获取变量的地址。示例如下:

#include <stdio.h>

int main() {
   
    int num = 10;
    int *p = &num;  // 声明并初始化指针p,使其指向变量num

    printf("变量num的地址: %p\n", &num);
    printf("指针p存储的地址: %p\n", p);

    return 0;
}

在上述代码中,&num 表示变量 num 的地址,将其赋给指针 p,这样 p 就指向了 num。

指针的操作

解引用操作

通过指针访问其所指向的变量的值,需要使用 * 运算符,这称为解引用操作。示例如下:

#include <stdio.h>

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

    printf("变量num的值: %d\n", num);
    printf("通过指针p访问num的值: %d\n", *p);

    *p = 20;  // 通过指针p修改num的值
    printf("修改后变量num的值: %d\n", num);

    return 0;
}

在上述代码中,*p 表示指针 p 所指向的变量的值,通过 *p = 20; 可以修改 num 的值。

指针算术运算

指针可以进行一些算术运算,如加法、减法等。指针算术运算的结果取决于指针所指向的数据类型的大小。示例如下:

#include <stdio.h>

int main() {
   
    int arr[5] = {
   1, 2, 3, 4, 5};
    int *p = arr;  // 指针p指向数组arr的首元素

    printf("p指向的元素的值: %d\n", *p);
    p++;  // 指针p向后移动一个位置
    printf("p移动后指向的元素的值: %d\n", *p);

    return 0;
}

在上述代码中,p++ 使指针 p 向后移动一个 int 类型的位置,即移动了 sizeof(int) 个字节。

指针的用途

动态内存分配

C 语言提供了一些函数(如 malloc、calloc、realloc 等)用于动态分配内存,这些函数返回的是一个指针,通过指针可以访问和管理动态分配的内存。示例如下:

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

int main() {
   
    int *p = (int *)malloc(sizeof(int));  // 动态分配一个int类型的内存空间
    if (p == NULL) {
   
        printf("内存分配失败\n");
        return 1;
    }

    *p = 10;
    printf("动态分配内存中存储的值: %d\n", *p);

    free(p);  // 释放动态分配的内存
    return 0;
}

作为函数参数

指针可以作为函数参数,通过指针传递参数可以在函数内部修改实参的值。示例如下:

#include <stdio.h>

void swap(int *a, int *b) {
   
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
   
    int x = 10, y = 20;
    printf("交换前: x = %d, y = %d\n", x, y);
    swap(&x, &y);
    printf("交换后: x = %d, y = %d\n", x, y);

    return 0;
}

在上述代码中,swap 函数接受两个指针作为参数,通过指针可以交换 x 和 y 的值。

指针与数组

在 C 语言中,指针和数组有着密切的联系。

数组名作为指针

在 C 语言里,数组名在大多数表达式中会被隐式转换为指向数组首元素的指针。也就是说,数组名代表了数组首元素的地址。
示例代码:

#include <stdio.h>

int main() {
   
    int arr[5] = {
   1, 2, 3, 4, 5};
    // 打印数组首元素的地址
    printf("数组首元素的地址(使用&arr[0]): %p\n", &arr[0]);
    // 打印数组名代表的地址
    printf("数组名代表的地址: %p\n", arr);
    return 0;
}

在上述代码中,&arr[0] 是获取数组 arr 首元素的地址,而 arr 本身在这个表达式中也被解释为指向数组首元素的指针,所以它们的值是相同的。

通过指针访问数组元素

由于数组名可以当作指针使用,因此可以借助指针来访问数组中的元素。
示例代码:

#include <stdio.h>

int main() {
   
    int arr[5] = {
   1, 2, 3, 4, 5};
    int *p = arr;  // 指针p指向数组arr的首元素
    for (int i = 0; i < 5; i++) {
   
        // 通过指针访问数组元素
        printf("arr[%d] = %d\n", i, *(p + i));
    }
    return 0;
}
    <

相关文章:

  • Python | 机器学习中最常用的超参数及使用示例
  • window系统中的start命令详解
  • SSM架构 +Nginx+FFmpeg实现rtsp流转hls流,在前端html上实现视频播放
  • RSA-OAEP填充方案与定时攻击防护
  • 人工智能之数学基础:对线性代数中逆矩阵的思考?
  • springboot011基于springboot的课程作业管理系统(源码+包运行+LW+技术指导)
  • Android中AIDL和HIDL的区别
  • 智慧校园总体方案
  • React Native国际化实践(react-i18next)
  • Centos的ElasticSearch安装教程
  • 退化环境定位(四):基于强度的感知定位方法
  • 云计算VS网络安全,应该怎么选?
  • hooks useModule自定义hooks (二次封装AgGridReact ag-table)自定义表头,自定义表头搜索
  • 浪涌测试方法与保护电路
  • Halcon 算子 一维码检测识别、项目案例
  • 任务10:三层交换机配置
  • 从零开始实现大语言模型(十四):高阶训练技巧
  • 国内外网络安全政策动态(2025年2月)
  • SyntaxError: Unexpected keyword ‘else‘
  • const iterator 和 const_iterator的区别