解析类Excel格式CSV文件时触发Segmentation Fault(C语言)
Fixing Segmentation Fault & Fgets Issues in Your CSV Column Calculation Code
Hey there! I can tell you’ve been stuck on this for a while—let’s unpack the problems in your code and get you past that segmentation fault and the fgets reading issue. You’ve already narrowed down the trouble spot to the header parsing loop, so let’s start there.
Key Issues in Your Current Code
- Uninitialized
tokenvariable: In your first loop, you checkwhile(token != NULL)before ever assigning a value totoken. This means the loop won’t run at all, so you never parse the header row to find your target column. - Incorrect
feof()usage: Usingfeof(inFile)as the loop condition leads to off-by-one errors.feof()only triggers after you’ve tried to read past the end of the file, so you might end up processing invalid data (or trying to read from a failed fgets call). - Broken
strseplogic: You’re modifying the stack-allocatedToprowarray directly withstrsep(&Toprow, ","), which shifts the pointer to the array’s start. After the first call,Toprowno longer points to the original beginning of the buffer, leading to memory chaos. Also, your loop order is reversed—you need to callstrsepfirst, then check if the token is NULL. - Type mismatches & invalid conversions: Your
minis anintbut the function returnsdouble. Worse,atoi(*token)is wrong—*tokenis a singlechar, so you’re converting the ASCII value of the first character instead of the entire string. It should beatoi(token). - Missing file open error check: If
fopen("array.csv","r")fails (e.g., file not found),inFilestays NULL, and any subsequent operations on it will cause a segmentation fault.
Fixed Code with Explanations
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <float.h> double getMin(char csvfile[], char column[]) { int target_col = -1; // Track the index of our target column char type; int chap, sec; char activity[50]; // Increased size to avoid overflow char header[100]; // Larger buffer for the header string char row[3000]; FILE* inFile = NULL; // Parse the column specifier (e.g., "C1.2") if (sscanf(column, "%c%d.%d", &type, &chap, &sec) != 3) { return -2.0; // Invalid format } type = toupper(type); // Normalize to uppercase to simplify checks if (type != 'P' && type != 'C' && type != 'L') return -2.0; if (chap <= 0 || sec <= 0) return 0.0; // Build the header string we're looking for if (type == 'C') { snprintf(activity, sizeof(activity), "challenge"); // Fixed typo: "challange" → "challenge" } else if (type == 'P') { snprintf(activity, sizeof(activity), "participation"); } else { // 'L' snprintf(activity, sizeof(activity), "lab"); // Fixed: "%cab" → "lab" (assumed typo) } snprintf(header, sizeof(header), "%d.%d - %s", chap, sec, activity); // Open the file with error checking inFile = fopen(csvfile, "r"); // Use the passed csvfile parameter instead of hardcoding! if (inFile == NULL) { perror("Failed to open file"); return -3.0; // Indicate file open failure } // Read and parse the header row to find our target column if (fgets(row, sizeof(row), inFile) == NULL) { fclose(inFile); return -4.0; // Empty file or read error } char* row_ptr = row; // Use a separate pointer to avoid modifying the original array char* token; int col_index = 0; while ((token = strsep(&row_ptr, ",")) != NULL) { // Trim any leading/trailing whitespace/newlines from the token token[strcspn(token, "\n\r")] = '\0'; if (strcmp(token, header) == 0) { target_col = col_index; break; } col_index++; } if (target_col == -1) { fclose(inFile); return -5.0; // Column not found } // Now read data rows to find the minimum value double min_val = DBL_MAX; // Use a large initial value for double while (fgets(row, sizeof(row), inFile) != NULL) { char* data_ptr = row; col_index = 0; while ((token = strsep(&data_ptr, ",")) != NULL) { token[strcspn(token, "\n\r")] = '\0'; // Trim newlines if (col_index == target_col) { // Convert token to double (supports decimals too) double curr_val = strtod(token, NULL); if (curr_val < min_val) { min_val = curr_val; } break; // Move to next row once we get the target column } col_index++; } } fclose(inFile); // If no valid values were found, return an error if (min_val == DBL_MAX) { return -6.0; } return min_val; }
Key Improvements Made
- Proper header parsing: We use a separate pointer (
row_ptr) withstrsepso we don’t modify the original stack array. We also trim newlines from tokens to avoid mismatches. - Fixed file handling: We use the passed
csvfileparameter instead of hardcoding "array.csv", add error checks forfopenandfgets, and always close the file before returning. - Type consistency: Switched to
doubleformin_valto match the function’s return type, and usestrtodinstead ofatoito support decimal values. - Cleaner loop logic: Replaced
feof()with checking the return value offgetsdirectly—this is the correct way to loop through a file line by line. - Normalized input: Converted the
typecharacter to uppercase so "c1.2" and "C1.2" both work. - Fixed typos: Corrected "challange" to "challenge" and fixed the "L" case to use "lab" instead of "%cab" (which was producing invalid strings like "Lab").
Additional Tips for Beginners
- Always initialize variables before using them—uninitialized variables lead to unpredictable behavior (like segmentation faults).
- Avoid modifying stack-allocated arrays directly with functions like
strsepthat alter the pointer. Use a temporary pointer instead. - When working with files, always check if
fopensucceeds, and remember to close the file when you’re done to avoid resource leaks.
内容的提问来源于stack exchange,提问作者Stephen Carson
相关产品推荐
相关产品推荐

