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

面经——C语言——指针大小,内存分配,野指针,大小端

文章目录

    • 指针大小
    • 分段
    • C语言内存分配
      • 1. 静态内存分配
        • 1.1 栈内存分配
        • 1.2 数据段内存分配
      • 2. 动态内存分配
        • 2.1 `malloc`(Memory Allocation)
        • 2.2 `free`(Free Memory)
      • 动态内存分配的流程
      • 例子
    • 野指针
      • 野指针的原因:
      • 防止野指针的做法:
    • 大小端
      • 如何检测当前机器的字节序?
        • 指针法
        • 联合体法

指针大小

在C++中,指针的大小是与编译器平台相关的,通常与操作系统和架构的位数有关。具体来说,指针的大小通常取决于计算机的字长(即操作系统和处理器的位数),常见的情况如下:
32位系统:指针大小通常为4字节(32位)。
64位系统:指针大小通常为8字节(64位)。

分段

内存区域描述特点
代码段存储程序的可执行指令(代码)。只读,防止程序修改自身指令;多个进程共享,节省内存空间。
数据段存储已初始化的全局变量和静态变量。可读写,程序启动时加载到内存,存储已初始化的全局和静态变量。
BSS段存储未初始化的全局变量和静态变量,启动时初始化为零。不存储数据,只分配空间;程序启动时操作系统将其初始化为零。
用于动态分配内存,程序员在运行时手动管理。动态分配和释放内存;大小可随程序需求变化;需使用mallocfree等函数。
存储函数的局部变量、参数和函数调用时的上下文信息。后进先出(LIFO);每次函数调用时分配栈帧,函数返回时弹出栈帧。

C语言内存分配

在C语言中,内存分配通常分为两种方式:静态内存分配动态内存分配。这两种方式的主要区别在于内存分配的时间和方式。

1. 静态内存分配

静态内存分配是指在程序编译时就已经确定了内存的大小和位置,通常在数据段中进行。

1.1 栈内存分配

栈内存分配用于存储函数的局部变量。栈内存分配是自动的,内存大小在编译时已确定。当函数调用时,局部变量会在栈上分配内存,函数返回时,栈上的内存会被自动释放。

void example() {
    int local_var = 10;  // local_var在栈上分配内存
}
1.2 数据段内存分配

数据段用于存储全局变量、静态变量和常量。数据段内存的大小和位置在程序编译时已确定,且内存通常在程序的生命周期内存在。

int global_var = 100;  // 全局变量,在数据段分配内存

void example() {
    static int static_var = 200;  // 静态变量,在数据段分配内存
}

2. 动态内存分配

动态内存分配是指在程序运行时,根据需要动态地分配和释放内存。动态内存分配主要通过标准库中的malloccallocreallocfree函数来进行。

2.1 malloc(Memory Allocation)

malloc用于分配指定大小的内存块,返回一个指向该内存块的指针。该内存块的内容未初始化,可能包含随机数据。

int *ptr = (int *)malloc(sizeof(int) * 10);  // 分配10个整数的内存
if (ptr == NULL) {
    // 内存分配失败,处理错误
}
2.2 free(Free Memory)

free用于释放之前分配的动态内存。释放后,指针仍然存在,但它不再指向有效的内存块。因此,释放后应该将指针设置为NULL,以避免悬空指针的错误。

free(ptr);  // 释放之前分配的内存
ptr = NULL;  // 防止悬空指针

动态内存分配的流程

  1. 使用malloccalloc分配内存。
  2. 检查返回的指针是否为NULL,以确认内存是否分配成功。
  3. 使用动态分配的内存进行计算或存储数据。
  4. 使用完毕后,通过free释放内存,以避免内存泄漏。

例子

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

int main() {
    int *arr;
    int n = 5;

    // 动态分配内存
    arr = (int *)malloc(n * sizeof(int));
    if (arr == NULL) {
        printf("内存分配失败\n");
        return 1;
    }

    // 使用动态分配的内存
    for (int i = 0; i < n; i++) {
        arr[i] = i * 10;
    }

    // 打印内容
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    // 释放内存
    free(arr);
    arr = NULL;  // 防止悬空指针

    return 0;
}

野指针

野指针是指向一个已经释放或未初始化的内存区域的指针。

野指针的原因:

  1. 未初始化的指针:
    在使用指针之前没有给它分配有效的内存地址,指针的值是随机的,可能指向一个无效的位置。

    int *ptr;  // ptr未初始化
    *ptr = 10; // 错误,野指针
    
  2. 释放内存后继续使用指针:
    释放指针所指向的内存后,如果继续访问该内存,指针就变成了野指针。

    int *ptr = malloc(sizeof(int)); // 动态分配内存
    free(ptr);  // 释放内存
    *ptr = 10;  // 错误,ptr变为野指针
    
  3. 指针指向的内存已被回收:
    当一个局部变量的作用域结束时,其内存会被释放。如果指针指向该局部变量的地址,它就成为了野指针。

    int *ptr;
    {
        int x = 10;
        ptr = &x;  // ptr指向局部变量x
    }  // x的内存被回收
    *ptr = 20;  // 错误,ptr成为野指针
    

防止野指针的做法:

  1. 初始化指针:
    指针在声明时应该初始化,避免指向随机内存。

    int *ptr = NULL;  // 初始化为NULL
    
  2. 避免使用已释放的内存:
    在调用free释放内存后,应将指针设置为NULL,防止指针继续访问无效内存。

    free(ptr);
    ptr = NULL;  // 防止野指针
    
  3. 检查指针的有效性:
    在使用指针之前,检查其是否指向有效的内存地址,特别是动态分配内存时。

    if (ptr != NULL) {
        *ptr = 10;
    }
    

通过这些方法,可以有效地避免和处理野指针问题,提升程序的稳定性和安全性。

大小端

大端是指数据的高字节存储在低地址处,低字节存储在高地址处。即,数据的高位字节在前低位字节在后

小端是指数据的低字节存储在低地址处,高字节存储在高地址处。即,数据的低位字节在前高位字节在后

如何检测当前机器的字节序?

指针法

在C++中,可以通过以下方法检测当前机器是大端还是小端:

#include <iostream>

int main() {
    int num = 1;
    char *ptr = (char *)&num;
    if (*ptr == 1) {
        std::cout << "小端\n";
    } else {
        std::cout << "大端\n";
    }
    return 0;
}
联合体法
#include <stdio.h>

union EndianTest {
    int num;
    unsigned char byte;
};

int main() {
    union EndianTest test;
    test.num = 0x12345678;  // 设置一个整数值

    // 查看bytes数组的第一个字节
    if (test.byte == 0x78) {
        printf("小端 (Little Endian)\n");
    } else if (test.byte== 0x12) {
        printf("大端 (Big Endian)\n");
    }

    return 0;
}


http://www.kler.cn/a/529550.html

相关文章:

  • 想品客老师的第天:类
  • 汽车中控屏HMI界面,安全和便捷是设计的两大准则。
  • 【二叉搜索树】
  • Day31-【AI思考】-关键支点识别与战略聚焦框架
  • 理解神经网络:Brain.js 背后的核心思想
  • Xposed-Hook
  • 【LeetCode: 598. 区间加法 II + 脑筋急转弯】
  • 我的Go+语言初体验——环境搭建并用命令行和 VScode 输出 “Hello World”_gop windows helloworld
  • 一些常用的HTML结构
  • 使用 EXISTS 解决 SQL 中 IN 查询数量过多的问题
  • C++ 哈希封装详解
  • E. Money Buys Happiness
  • UE5 蓝图计划 - Day 2-3:执行流与事件
  • 大模型能力评估数据集都有哪些?
  • 贪吃蛇实现
  • SpringBoot的配置(配置文件、加载顺序、配置原理)
  • UE5 蓝图学习计划 - Day 11:材质与特效
  • 大模型训练(5):Zero Redundancy Optimizer(ZeRO零冗余优化器)
  • 操作系统和中间件的信息收集
  • 踏入编程世界的第一个博客
  • 在 Ubuntu 中使用 Conda 创建和管理虚拟环境
  • 使用朴素贝叶斯对散点数据进行分类
  • 5分钟在本地PC上使用VLLM快速启动DeepSeek-R1-Distill-Qwen-32B
  • Github 2025-02-02 php开源项目日报 Top10
  • Windows程序设计11:文件的查找与遍历
  • PyTorch数据建模