You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

含数组与非数组成员的结构体数组内存布局及指针偏移段错误问题

段错误核心原因

你对C语言指针算术的规则理解有误:对指向具体类型的指针做加法时,编译器会自动按照目标类型的大小计算偏移,不需要手动乘以sizeof(类型)。

你的db1p是db_mold*类型,当你写db1p + n时,编译器实际计算的地址是(char*)db1p + n * sizeof(db_mold),刚好指向数组的第n个元素。但你手动给n乘了sizedb(也就是你测到的28),实际计算出来的地址是(char*)db1p + n * 28 * 28,访问的位置已经远远超出了db1[4]数组的合法内存范围,写入数据时触发非法访问,自然报段错误。
比如你访问第二个员工(下标1)时,实际访问的地址偏移是1*28*28=784字节,而你的db1数组总共才占4*28=112字节,早就越界到未分配给你的内存区域了。

你提到的其他知识点说明
  • 结构体内存填充规则:核心对齐规则有两条
    • 结构体每个成员的起始偏移地址,必须是该成员自身对齐值的整数倍(基本类型的对齐值等于自身大小,数组的对齐值等于数组成员类型的对齐值)
    • 结构体整体的总大小,必须是结构体中最大对齐值的整数倍
      你定义的db_mold大小为28是完全符合规则的:char nombre[20]占0-19字节,char sexo占20字节,之后的unsigned int sueldo对齐值为4,所以编译器会在21-23字节位置插入3个填充字节,让sueldo从24字节位置开始占4字节,总大小28刚好是4的整数倍,填充位置就在sexo和sueldo之间,这部分和你本次的段错误没有关系。
  • 同时包含数组成员与非数组成员的结构体数组(你提到的AoSwAaNA)内存是完全连续的:和普通int数组、char数组的排布逻辑没有区别,每个结构体元素按顺序连续排列,结构体内部的数组成员直接存储在结构体对应的内存空间内,不存在额外的指针跳转,不需要特殊处理。
代码里的其他问题
  • user_load函数中strcpy的参数顺序写反了:strcpy(目标地址, 源地址),你当前写的strcpy(tmp, (db1p+(sizedb*i))->nombre);是把结构体里未初始化的内容拷贝到临时缓冲区tmp里,和你要把用户输入的姓名写入结构体的逻辑完全相反。
  • 你在函数调用时传入sizeof(db_mold)作为参数本身是多余的:只要指针带明确的类型信息,编译器会自动完成指针偏移的计算,不需要手动传入类型大小。
  • 输入逻辑存在换行符残留问题:scanf读取数值后会在输入缓冲区留下换行符,不清理的话下一轮fgets会直接读到空内容。
修正参考

最稳妥的写法是直接用数组下标访问,编译器会自动处理偏移,几乎不会写错:

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

typedef struct {
    char nombre[20];
    char sexo;
    unsigned int sueldo;
}db_mold;

void preload(db_mold *);
void user_load(db_mold *);

int main(){
    db_mold db1[4] = {0};
    preload(db1);
    user_load(db1);
    return 0;
}

void preload(db_mold *db1p){
    strcpy(db1p[0].nombre, "Franco");
    db1p[0].sexo = 'M';
    db1p[0].sueldo = 20000;

    strcpy(db1p[1].nombre, "Romina");
    db1p[1].sexo = 'F';
    db1p[1].sueldo = 23000;
}

void user_load(db_mold *db1p){
    for (int i = 2; i < 4; i++){
        printf("Ingrese el nombre del empleado %d: ", i);
        // 注意fgets会读入换行符,后续如果要做字符串匹配记得处理
        fgets(db1p[i].nombre, sizeof(db1p[i].nombre), stdin);
        printf("Ingrese el Sexo (M o F) del empleado %d: ", i);
        db1p[i].sexo = getchar();
        getchar(); // 吃掉输入性别后的换行
        printf("Ingrese el salaio del empleado %d: ", i);
        scanf("%u", &db1p[i].sueldo);
        getchar(); // 吃掉scanf留下的换行,避免下一轮fgets读空
        printf("Empleado Cargado!\n");
    }
}

如果你一定要用指针算术的写法,直接给指针加下标值即可,不要手动乘sizeof:

strcpy((db1p + i)->nombre, "Romina"); // 正确写法

内容的提问来源于stack exchange,提问作者fpp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 02:15:38