循环输入名字时指针指向同一内存致内容覆盖的C语言问题求解
问题分析与修复方案
你的判断完全正确:问题出在两个指针指向了同一块内存区域。enteredName是循环内部的局部数组,它存储在栈内存中,每次循环迭代时,这块内存的地址会被重复利用。因此first和second最终都指向这块栈内存,最后输入的内容会覆盖之前的,导致打印结果重复。
修复测试程序
要解决这个问题,需要为每个输入的名字分配独立的堆内存,确保每个指针指向不同的内存块。可以通过malloc+strcpy实现,或者用更便捷的strdup(自动分配内存并复制字符串,主流编译器均支持)。
修复后的测试代码(malloc+strcpy版本)
#include <stdio.h> #include <string.h> #include <stdlib.h> int main(void) { char* first = NULL; char* second = NULL; for (int i = 0; i < 2; i++) { char enteredName[20]; printf("Please enter a name: "); scanf("%s", enteredName); // 为名字分配内存(+1是为了存储字符串结束符'\0') char* nameCopy = malloc(strlen(enteredName) + 1); if (nameCopy == NULL) { perror("malloc failed"); // 释放已分配的内存避免泄漏 if (first) free(first); exit(EXIT_FAILURE); } strcpy(nameCopy, enteredName); if (i == 0) { first = nameCopy; } else { second = nameCopy; } } printf("First: %s\n", first); printf("Second: %s\n", second); // 释放堆内存 free(first); free(second); return 0; }
修复后的测试代码(strdup简化版本)
#include <stdio.h> #include <string.h> #include <stdlib.h> int main(void) { char* first = NULL; char* second = NULL; for (int i = 0; i < 2; i++) { char enteredName[20]; printf("Please enter a name: "); scanf("%s", enteredName); // strdup自动分配内存并复制字符串 char* nameCopy = strdup(enteredName); if (nameCopy == NULL) { perror("strdup failed"); if (first) free(first); exit(EXIT_FAILURE); } if (i == 0) { first = nameCopy; } else { second = nameCopy; } } printf("First: %s\n", first); printf("Second: %s\n", second); free(first); free(second); return 0; }
实现完整程序(输入到"done"停止,支持任意数量名字)
要支持任意数量的名字,需要使用动态扩容的指针数组,因为无法提前预知用户输入的数量。以下是完整实现:
#include <stdio.h> #include <string.h> #include <stdlib.h> #define INITIAL_CAPACITY 4 // 数组初始容量 int main(void) { // 动态指针数组,存储每个名字的堆内存地址 char** names = malloc(INITIAL_CAPACITY * sizeof(char*)); if (names == NULL) { perror("malloc failed"); exit(EXIT_FAILURE); } int nameCount = 0; // 已输入的名字数量 int currentCapacity = INITIAL_CAPACITY; char enteredName[20]; printf("Enter names (type 'done' to finish):\n"); while (1) { printf("Name %d: ", nameCount + 1); scanf("%s", enteredName); // 输入"done"则结束循环 if (strcmp(enteredName, "done") == 0) { break; } // 数组容量不足时,扩容为原来的2倍 if (nameCount >= currentCapacity) { currentCapacity *= 2; char** temp = realloc(names, currentCapacity * sizeof(char*)); if (temp == NULL) { perror("realloc failed"); // 清理已分配的所有内存,避免泄漏 for (int i = 0; i < nameCount; i++) { free(names[i]); } free(names); exit(EXIT_FAILURE); } names = temp; } // 为当前名字分配独立内存并复制 char* nameCopy = strdup(enteredName); if (nameCopy == NULL) { perror("strdup failed"); // 清理已分配内存 for (int i = 0; i < nameCount; i++) { free(names[i]); } free(names); exit(EXIT_FAILURE); } names[nameCount++] = nameCopy; } // 打印所有输入的名字 printf("\nAll entered names:\n"); for (int i = 0; i < nameCount; i++) { printf("%d. %s\n", i + 1, names[i]); } // 释放所有堆内存:先释放每个名字的内存,再释放指针数组 for (int i = 0; i < nameCount; i++) { free(names[i]); } free(names); return 0; }
关键要点说明
- 动态数组管理:用
char**类型的指针数组存储每个名字的地址,初始分配固定容量,容量不足时用realloc扩容(通常翻倍,减少扩容次数)。 - 独立内存分配:每个名字都通过
strdup(或malloc+strcpy)分配独立的堆内存,确保指针不会指向同一块内存。 - 内存泄漏防护:所有堆内存都要在程序结束前释放;如果内存分配失败,要先清理已分配的内存再退出程序。
内容的提问来源于stack exchange,提问作者Carsdan Dvorachek
相关产品推荐
相关产品推荐

