使用动态分配内存后所有值均相同的问题原因排查
Let's break down the root cause of this issue and how to fix it in a straightforward way:
The Core Problem: Pointer Assignment Instead of String Copying
Looking at your code, here's the critical mistake that's causing duplicate outputs:
list.words[list.length - 1] = (char*)malloc(sizeof(char) * 30); list.words[list.length - 1] = str;
You're doing two things here:
- Allocating a new block of memory for each word (great start!)
- Immediately overwriting that new pointer with the address of the local array
str(this breaks everything)
Why This Causes Duplicate Outputs
stris a fixed-size array declared inmain(). Every time you callfgets(str, 30, stdin), you're writing the new word into the exact same chunk of memory.- When you assign
list.words[...] = str, you're storing the address ofstrin every element of your words array. So every entry inlist.wordspoints to the same memory location. - By the end of the loop,
strcontains the last word you entered. Since all pointers inlist.wordspoint tostr, printing them all will show that last word repeatedly.
Bonus Issue: Memory Leak
The malloc call for each word is wasted—you allocate memory but never use it (since you overwrite the pointer). This creates a memory leak because that allocated memory is never freed.
How to Fix the Code
Step 1: Copy the String Instead of Assigning the Pointer
Replace the pointer assignment with strcpy to copy the contents of str into the allocated memory. You'll need to include <string.h> for this function.
Step 2 (Optional): Trim the Newline Character
fgets includes the newline character (\n) when the user presses Enter. To remove it, you can find the newline and replace it with a null terminator for cleaner output.
Fixed Code Example
#include <stdio.h> #include <stdlib.h> #include <string.h> // Add this for strcpy struct my_struct { char** words; int length; }; int main(void) { struct my_struct list = {NULL, 0}; int choice = 1, i = 0; char str[30]; printf("Enter 0 to exit or any other number to continue: "); scanf("%d", &choice); while (choice) { list.length += 1; // Reallocate the words array (check for failure!) list.words = realloc(list.words, sizeof(char*) * list.length); if (list.words == NULL) { fprintf(stderr, "Memory allocation failed\n"); return 1; } // Allocate memory for the new word (check for failure!) list.words[list.length - 1] = malloc(sizeof(char) * 30); if (list.words[list.length -1] == NULL) { fprintf(stderr, "Memory allocation failed\n"); return 1; } printf("Enter a word: "); getchar(); // Clear the newline left by scanf fgets(str, 30, stdin); // Trim the newline character if present size_t len = strlen(str); if (len > 0 && str[len-1] == '\n') { str[len-1] = '\0'; } // Copy the string into the allocated memory strcpy(list.words[list.length - 1], str); printf("Enter 0 to exit or any other number to continue: "); scanf("%d", &choice); } printf("Values:\n"); for (i = 0; i < list.length; i++) { printf("%s\n", list.words[i]); // Clean up output with newlines free(list.words[i]); // Free each word's memory to avoid leaks } free(list.words); // Free the main words array getchar(); getchar(); return 0; }
Key Fixes Explained
- Used
strcpyto copy the content ofstrinto the allocated memory block for each word, so each entry points to its own unique data. - Added checks for
malloc/reallocfailure to prevent crashes from out-of-memory scenarios. - Trimmed the newline from
strso your output doesn't have extra line breaks. - Freed each individual word's memory before freeing the words array to eliminate memory leaks.
内容的提问来源于stack exchange,提问作者Omer

