模拟Shell程序二次输入输出异常及getline换行问题求助
Let's break down your issues step by step, starting with the simpler getline behavior question and then fixing the parsing/memory bugs that cause garbage output.
Is the \n added by getline normal?
Absolutely! This is expected behavior from the getline function. It reads all input characters until the newline character (\n) (triggered when you press Enter) and includes that newline in the returned string. Your approach to replacing it with a space works for your parsing logic, but you should add a safety check to avoid invalid memory access if getline returns -1 (e.g., when the user presses Ctrl+D to send EOF):
if (nbCharacters > 0) { textEntre[nbCharacters - 1] = ' '; }
Fixing Garbage Output & Parsing Bugs
The main issues causing garbage output and unexpected behavior are in your makeArgs function and memory management. Let's address each bug and apply fixes:
1. Missing Null Terminator in Copied Strings
strncpy does not automatically add a null terminator (\0) to the end of the copied string. Since you allocated extra space for the terminator, you need to add it manually to avoid reading uninitialized memory:
strncpy(chptr, &textEntre[j], i-j); chptr[i-j] = '\0'; // Critical: Add this line to terminate the string
Without this, printf will read past your string into random memory, causing garbage output.
2. Memory Leak & Double Allocation of arguments
Every call to makeArgs allocates a new arguments array, but you never free the old array in your main loop. This causes memory leaks and overwrites the pointer to the old array (making it impossible to free later). Fix this by freeing the arguments array itself after freeing its elements:
while (1){ if (getText() != 0) break; // Exit on EOF int nbArguments = makeArgs(); // Print only valid parsed arguments (not a fixed 5) for(int i = 0; i < nbArguments; i++){ printf("Argument %d: %s\n", i, arguments[i]); } // Clean up memory for this iteration for(int i = 0; i < nbArguments; i++){ free(arguments[i]); } free(arguments); // Free the array itself here! }
Remove the final free(arguments); in main since it's now handled in the loop.
3. Broken Quoted Argument Handling
Your current code skips quoted text entirely, meaning arguments like "hello world" are never saved. Modify the logic to capture quoted content as a single argument:
if(textEntre[i] == '"'){ i++; int quoteStart = i; // Loop until closing quote or end of input while(textEntre[i] != '"' && i < nbCharacters){ i++; } // Allocate space and copy the quoted content char *chptr = malloc(i - quoteStart + 1); strncpy(chptr, &textEntre[quoteStart], i - quoteStart); chptr[i - quoteStart] = '\0'; arguments[k] = chptr; k++; j = i + 1; // Move past the closing quote }
4. Incorrect Consecutive Space Handling
Your existing logic leaves leading spaces in arguments. Instead, skip all consecutive spaces before parsing each argument:
// Skip leading spaces at the start of each argument while (i < nbCharacters && textEntre[i] == ' ') { i++; j = i; }
5. Safe Reallocation of arguments
Your current reallocation check only triggers once when i == 20. Instead, check if you're running out of slots for arguments:
if(k >= nbElem - 1){ // Leave space for a NULL terminator (good practice) nbElem *= 2; arguments = realloc(arguments, sizeof(char*)*nbElem); // Always check if realloc succeeded! if (arguments == NULL) { perror("realloc failed"); exit(EXIT_FAILURE); } }
6. Handle EOF in getText
If getline returns -1 (EOF), accessing textEntre[nbCharacters-1] will crash your program. Update getText to signal EOF:
int getText(){ size_t buffersize = 0; nbCharacters = getline(&textEntre, &buffersize, stdin); if (nbCharacters == -1) { return 1; // Return non-zero to signal EOF/error } textEntre[nbCharacters - 1] = ' '; return 0; }
Full Fixed Code
Here's the complete code with all fixes applied:
#include <stdio.h> #include <stdlib.h> #include <string.h> int getText(); int makeArgs(); char *textEntre = NULL; size_t nbCharacters; char **arguments; int main (void) { while (1){ if (getText() != 0) { break; // Exit gracefully on EOF } int nbArguments = makeArgs(); // Print parsed arguments for(int i = 0; i < nbArguments; i++){ printf("Argument %d: %s\n", i, arguments[i]); } // Clean up memory for this iteration for(int i = 0; i < nbArguments; i++){ free(arguments[i]); } free(arguments); } free(textEntre); return 0; } int getText(){ size_t buffersize = 0; nbCharacters = getline(&textEntre, &buffersize, stdin); if (nbCharacters == -1) { return 1; } textEntre[nbCharacters - 1] = ' '; return 0; } int makeArgs(){ int nbElem = 20; arguments = malloc(sizeof(char*) * nbElem); if (arguments == NULL) { perror("malloc failed"); exit(EXIT_FAILURE); } int i = 0; int j = 0; int k = 0; while (i < nbCharacters) { // Skip leading spaces while (i < nbCharacters && textEntre[i] == ' ') { i++; j = i; } if (i >= nbCharacters) break; // Handle quoted arguments if(textEntre[i] == '"'){ i++; j = i; while(textEntre[i] != '"' && i < nbCharacters){ i++; } char *chptr = malloc(i - j + 1); if (chptr == NULL) { perror("malloc failed"); exit(EXIT_FAILURE); } strncpy(chptr, &textEntre[j], i - j); chptr[i - j] = '\0'; arguments[k] = chptr; k++; i++; j = i; continue; } // Reallocate if needed if(k >= nbElem - 1){ nbElem *= 2; arguments = realloc(arguments, sizeof(char*) * nbElem); if (arguments == NULL) { perror("realloc failed"); exit(EXIT_FAILURE); } } // Find end of current argument while (i < nbCharacters && textEntre[i] != ' ') { i++; } // Copy argument char *chptr = malloc(i - j + 1); if (chptr == NULL) { perror("malloc failed"); exit(EXIT_FAILURE); } strncpy(chptr, &textEntre[j], i - j); chptr[i - j] = '\0'; arguments[k] = chptr; k++; j = i + 1; } return k; }
内容的提问来源于stack exchange,提问作者itachi737

