为何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
相关产品推荐
相关产品推荐

