假设我们在C文件中有以下结构体定义:
typedef struct {
char *name;
int id;
int last_cpu;
} thread_t;
(这是我为OS类编写的不同调度算法的模拟)。每次我创建一个新的thread_t
结构体,我如何处理其中一个变量是char*
的事实?例如,我的代码中有以下方法:
thread_t **get_starting_thread_list() {
thread_t **threads = (thread_t **) malloc(MAX_NUM_THREADS * sizeof(thread *));
int next_id = 0;
for (int th_num = 0; th_num < MAX_NUM_THREADS; th_num++) {
thread_t *new_thread = (thread_t *) malloc(sizeof(thread_t));
new_thread->name = "New thread";
new_thread->id = ++next_id;
new_thread->last_cpu = 0;
threads[th_num] = new_thread;
}
return threads;
}
如果new_thread
的name
字段曾经"太大",我可能会得到分割故障吗?也就是说,在分配线程名之前,我应该为它分配额外的内存吗?我试着运行这个,它似乎表现得很好,但我担心它可能会在以后打破。
如果
new_thread
的名称字段曾经"太大",我可能会得到分割错误吗?
不,不管字符串有多长,你都不会得到段错误,因为字符串字面量的内存是静态分配的,并且永远不会复制。
也就是说,我应该在分配线程名之前为它分配额外的内存吗?
除非您计划使名称可更改。如果您希望保持名称指向字符串字面值,您的代码完全没问题。如果您想为名称使用非文字数据,请执行以下操作:
char buf[32];
sprintf(buf, "New thread %d", next_id);
new_thread->name = malloc(strlen(buf+1));
strcpy(new_thread->name, buf);
现在你需要在释放threads
之前调用free(threads[i]->name)
我试着运行这个,它似乎表现得很好,但我担心它可能会在以后崩溃。
你的代码很好。您总是可以使用内存分析器,比如valgrind,来检查无效的访问。
在代码片段中,您将name
指向一个文字字符串。如果你不打算改变它,它将永远工作。如果你想做像ptr->name[0] = 'X';
这样的事情,你现在试图修改一个固定的字符串,我认为这是未定义的行为(观看语言律师确认或否认的评论;-)。
在代码中,文字字符串"New thread"是静态分配的,而不是动态分配的。(这意味着该文本在应用程序启动时就存在,而不是使用malloc()
之类的函数从堆中动态分配。)因此,这永远不会太大或导致段故障。这个字符串在静态内存中,现在你的thread_t
结构将指向那个内存。
但是,在这种情况下,每个结构的值是相同的。所以我怀疑这是不是你代码的真实样子
结构体定义了char *name;
,无论它指向什么字符串,指针的大小都不会改变。
所以这个问题的答案:我可能会得到一个分割错误,如果new_thread的名称字段曾经"太大"?为NO,字符串的大小没有影响。
但是,如果您定义了一个字面值字符串,则该字符串不能更改。尝试更改字面值字符串的内容将导致seg错误事件,