fgets读取非预期换行符问题及矩阵文件读取代码求助
Hey Nick, let's work through that newline issue you're facing with your matrix file loader code. The core problems here are how you're handling empty lines, not validating fgets returns properly, and not accounting for newline characters that fgets includes in the buffer. Let's break down fixes step by step:
First, Fix the Empty Line Handling Loop
Your inner loop skips blank lines but doesn't check if fgets returns NULL (which happens at the end of the file). This can lead to unexpected behavior or crashes when you hit EOF mid-skip. Update it to:
// Skip empty lines (including those with only whitespace) while (fgets(buffer, MAX_CHAR, file) != NULL) { current_line++; bool is_empty = true; for (int i = 0; buffer[i] != '\0'; i++) { if (!isspace((unsigned char)buffer[i])) { is_empty = false; break; } } if (!is_empty) break; // Found a non-empty line, exit the skip loop } if (buffer == NULL) { // Hit EOF while skipping lines, exit the main loop break; }
This handles lines with spaces/tabs (not just pure \n) and stops safely at the end of the file.
Clean Up Newline Characters from fgets
fgets reads the trailing newline character into your buffer, which can mess up string comparisons and parsing. Add this line right after a successful fgets call to strip it:
// Replace the newline character with a null terminator buffer[strcspn(buffer, "\n")] = '\0';
strcspn finds the first occurrence of \n, so we overwrite it to truncate the string cleanly.
Refine Your Flag Logic
Your flag variable is a bit vague—rename it to something like expecting_matrix_header to make the code intent clearer. This helps you track whether the next non-empty line is a matrix description or part of matrix data.
Updated Code Snippet
Here's how your function might look with these fixes, plus some safety checks for file opening and memory allocation:
#include <ctype.h> // For isspace #include <string.h> #include <stdlib.h> #include <stdio.h> typedef struct maps { // Define your maps structure here (e.g., matrix dimensions, data, next pointer) int rows, cols; int** data; struct maps* next; } maps; // Helper to check if a line is empty (only whitespace) bool is_empty_line(const char* line) { for (; *line != '\0'; line++) { if (!isspace((unsigned char)*line)) { return false; } } return true; } void loadfile(char *filename, maps **head, maps **tail){ FILE *file; maps *aux; char buffer[MAX_CHAR]; bool expecting_matrix_header = true; int current_line = 1; int current_matrix_row = 0; int target_rows = 0, target_cols = 0; /* Open file with error checking */ file = fopen(filename, "r"); // Assuming openfile is a wrapper for fopen if (!file) { perror("Failed to open file"); return; } while(fgets(buffer, MAX_CHAR, file) != NULL){ current_line++; // Skip empty lines if (is_empty_line(buffer)) { continue; } // Strip trailing newline buffer[strcspn(buffer, "\n")] = '\0'; if (expecting_matrix_header) { // Parse matrix metadata (adjust this to match your description line format) if (sscanf(buffer, "%d %d", &target_rows, &target_cols) != 2) { fprintf(stderr, "Invalid matrix header at line %d\n", current_line); continue; } // Allocate new maps node aux = malloc(sizeof(maps)); if (!aux) { perror("Failed to allocate memory for map"); fclose(file); // Add cleanup for existing nodes here if needed return; } aux->rows = target_rows; aux->cols = target_cols; aux->next = NULL; // Allocate matrix data aux->data = malloc(target_rows * sizeof(int*)); for (int i = 0; i < target_rows; i++) { aux->data[i] = malloc(target_cols * sizeof(int)); } current_matrix_row = 0; expecting_matrix_header = false; } else { // Parse matrix row data (adjust format to match your file) int* row = aux->data[current_matrix_row]; int parsed = sscanf(buffer, "%d %d %d", &row[0], &row[1], &row[2]); // Example for 3 columns if (parsed != target_cols) { fprintf(stderr, "Invalid matrix row at line %d\n", current_line); // Handle error (free allocated memory, etc.) continue; } current_matrix_row++; if (current_matrix_row == target_rows) { // Matrix is complete, add to linked list if (!*head) { *head = aux; *tail = aux; } else { (*tail)->next = aux; *tail = aux; } expecting_matrix_header = true; // Prepare for next matrix } } } fclose(file); }
Key Notes for Your Use Case
- Adjust the
sscanfcalls to match your actual file format (e.g., if your matrix description line has more metadata, or matrix rows use commas instead of spaces). - Add error handling for memory allocation failures to avoid leaks.
- If your matrix end isn't defined by fixed rows (from the header), you'll need another condition to detect when one matrix ends and the next begins (e.g., a specific marker line).
内容的提问来源于stack exchange,提问作者NickProg36

