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

为何strncpy无法将字符串复制到结构体的字符串变量中?

问题分析与解决方案

核心问题原因

你定义的totalizer_t结构体中,unit_volume和unit_time是char*类型,初始化时指向的是字符串字面量(如"LT"、"S")。在C语言中,字符串字面量默认存储在只读数据段,直接对其执行写入操作(比如strncpy、strcpy)属于未定义行为——这就是修改后无效果、甚至可能引发程序崩溃的根本原因。


解决方案(保留字符串兼容现有库)

方案1:将指针改为固定大小字符数组

把结构体中的字符串指针改成字符数组,让结构体自身分配可写的存储空间,这是最安全直接的方式。

修改结构体定义:

typedef struct
{
    uint64_t pulse;
    fp_t volume;
    fp_t factor; // Factor en pulsos / unidad de volumen
    char unit_volume[3]; // 双字符+字符串终止符,共3字节
    char unit_time[2];   // 单字符+字符串终止符,共2字节
} totalizer_t;

结构体初始化保持原有形式即可:

static totalizer_t acm_config =
{
    .pulse = 1000,
    .volume.num = 1,
    .volume.res = 1,
    .factor.num = 1000,
    .factor.res = 0,
    .unit_volume = "LT",
    .unit_time = "S",
};

static totalizer_t rate_config =
{
    .pulse = 0,
    .volume.num = 0,
    .volume.res = 1,
    .factor.num = 1000,
    .factor.res = 0,
    .unit_volume = "LT",
    .unit_time = "S",
};

static totalizer_t ttl_config =
{
    .pulse = 12000,
    .volume.num = 1,
    .volume.res = 1,
    .factor.num = 1000,
    .factor.res = 0,
    .unit_volume = "LT",
    .unit_time = "S",
};

修改函数补充字符串终止符,确保字符串合法:

void fm_factory_modify_units_time(char *p_str_time_units)
{
    strncpy(acm_config.unit_time, p_str_time_units, 1);
    acm_config.unit_time[1] = '\0';
    strncpy(rate_config.unit_time, p_str_time_units, 1);
    rate_config.unit_time[1] = '\0';
    strncpy(ttl_config.unit_time, p_str_time_units, 1);
    ttl_config.unit_time[1] = '\0';
}

void fm_factory_modify_units_volume(char *p_str_volume_units)
{
    strncpy(acm_config.unit_volume, p_str_volume_units, 2);
    acm_config.unit_volume[2] = '\0';
    strncpy(rate_config.unit_volume, p_str_volume_units, 2);
    rate_config.unit_volume[2] = '\0';
    strncpy(ttl_config.unit_volume, p_str_volume_units, 2);
    ttl_config.unit_volume[2] = '\0';
}

方案2:直接替换指针指向

如果不想修改结构体定义,可以直接让指针指向新的字符串(需保证新字符串的生命周期足够长,比如全局静态字符串或动态分配内存)。

修改函数为:

void fm_factory_modify_units_time(char *p_str_time_units)
{
    acm_config.unit_time = p_str_time_units;
    rate_config.unit_time = p_str_time_units;
    ttl_config.unit_time = p_str_time_units;
}

void fm_factory_modify_units_volume(char *p_str_volume_units)
{
    acm_config.unit_volume = p_str_volume_units;
    rate_config.unit_volume = p_str_volume_units;
    ttl_config.unit_volume = p_str_volume_units;
}

调用示例:

// 使用全局静态字符串,生命周期贯穿整个程序
fm_factory_modify_units_volume("M3");

// 或动态分配内存(需手动释放避免泄漏)
char *vol_unit = malloc(3);
strcpy(vol_unit, "M3");
fm_factory_modify_units_volume(vol_unit);
// 不再使用时执行 free(vol_unit);

方案3:初始化时分配堆内存

保持指针类型,但初始化时为其分配可写的堆内存,后续可以直接修改内容。

初始化代码(需引入stdlib.h和string.h):

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

static totalizer_t acm_config =
{
    .pulse = 1000,
    .volume.num = 1,
    .volume.res = 1,
    .factor.num = 1000,
    .factor.res = 0,
    .unit_volume = strdup("LT"), // 分配堆内存并拷贝字符串
    .unit_time = strdup("S"),
};

// rate_config、ttl_config 初始化方式同理

修改函数可直接使用strncpy,无需改动:

void fm_factory_modify_units_volume(char *p_str_volume_units)
{
    strncpy(acm_config.unit_volume, p_str_volume_units, 2);
    acm_config.unit_volume[2] = '\0';
    strncpy(rate_config.unit_volume, p_str_volume_units, 2);
    rate_config.unit_volume[2] = '\0';
    strncpy(ttl_config.unit_volume, p_str_volume_units, 2);
    ttl_config.unit_volume[2] = '\0';
}

注意:程序退出前需要手动释放堆内存,避免内存泄漏:

free(acm_config.unit_volume);
free(acm_config.unit_time);
free(rate_config.unit_volume);
free(rate_config.unit_time);
free(ttl_config.unit_volume);
free(ttl_config.unit_time);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 01:47:06