为什么我会出现分段错误?当我使用 sanitize=address 进行编译时,我得到了一个我不太明白的堆使用后释放(原因)。 我在地址 xyz 上得到堆释放后使用。
在 ... test.c:22 中读取大小 8(打印 parts[i] 的行)
...位于此处释放的 8 字节区域内的 0 字节(strings.c:175,这是 reallocarray 行)
...之前在这里分配(在 main test.c:9 中,即 char **parts=calloc.. 行)
此示例独立编译:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum EXPLODE_FLAGS {
NO_FLAGS=0,
FLAG_TRIM=1, // trim each line of the output
};
typedef enum RESULT {
E_SUCCESS=0, // not a failure but a SUCCESS
E_ERROR=1, // failure due to generic error
E_ARGS=2, // failed due to arguments
E_MALLOC=3
} RESULT;
enum EXP_RESULT {
EXP_ERROR=-E_ERROR, // generic error
EXP_ARGS=-E_ARGS, // generic error with the arguments
EXP_MALLOC=-E_MALLOC, // failure due to generic error
EXP_SEP=-4, // separator is null
EXP_INPUT=-5, // input is a null pointer
EXP_OUTPUT=-6, // output is a null pointer
};
int str_explode(char *input, char **parts, const char separator) {
int partCounter = 0;
int currentPartLength = 0;
char *currentPart = NULL;
// Check for input validity
if (!input) return EXP_INPUT;
if (!parts) return EXP_OUTPUT;
if (separator == '\0') return EXP_SEP;
char *start = input;
char *currentPartStart = input;
char *end = input + strlen(input);
fprintf(stdout,"Inside the function\n");
for (char *thischar = start; thischar <= end; thischar++) {
if (*thischar == separator || *thischar == '\0') {
printf("Inside check; current char is: %c\n",*thischar);
// Allocate memory for the length of the current part + null terminator
currentPart = calloc(1, currentPartLength + 1);
if (!currentPart) {
// Use goto for cleanup
goto cleanup;
}
// Copy the current part into the allocated memory
if (currentPartLength > 0) {
strncpy(currentPart, currentPartStart, currentPartLength);
currentPart[currentPartLength] = '\0'; // Null-terminate the string
} else {
currentPart[0] = '\0'; // Empty string for the case of consecutive separators
}
// Reallocate memory for another char pointer
parts=reallocarray(parts,partCounter+1,sizeof(char*));
if (!parts) {
// Use goto for cleanup
goto cleanup_current_part;
}
printf("About to add current part (%s) to the pile\n",currentPart);
// Add the new string part
parts[partCounter++] = currentPart;
printf("About to check current part from the pile: %s\n",parts[partCounter-1]);
// Reset variables for the next part
currentPart = NULL;
currentPartStart = thischar + 1; // Skip the separator
currentPartLength = 0;
if('\0'==*thischar)
break;
} else {
++currentPartLength;
}
}
free(currentPart);
return partCounter;
// Label for cleanup
cleanup_current_part:
fprintf(stderr,"Unable to allocate memory for another part\n");
free(currentPart);
cleanup:
fprintf(stderr,"Unable to allocate memory for current part\n");
// Free previously allocated memory before returning error
for (int i = 0; i < partCounter; i++) {
free(parts[i]);
}
free(parts);
return EXP_MALLOC;
}
int main(void) {
char *input = "apple;orange;banana;grape";
char **parts = calloc(1,1*sizeof(char*));
parts[0]="\0";
int partCount = str_explode(input, parts, ';');
if (partCount < 0) {
printf("Error code #%d\n", -partCount);
return 1;
}
printf("Original string: %s\n", input);
printf("Number of parts: %d\n", partCount);
for (int i = 0; i < partCount; i++) {
printf("About to print part #%d:\n",i+1);
printf("Part %d: %s\n", i + 1, parts[i]);
free(parts[i]);
}
free(parts);
return 0;
}
请记住,我不是一位经验丰富的 C 程序员。我有指针的工作知识,但我无法理解我在这里做错了什么。 这个小程序的目的是提高我对 C 中字符数组的理解。
在 C 中,参数按值传递,这意味着对
parts
的更改在返回 str_explode()
时会丢失(并泄漏)。最小的修复方法是传入 parts
的地址并将参数更改为 char ***parts
并将所有用途更新为 (*parts)
。
int str_explode(char *input, char ***parts, const char separator) {
int partCounter = 0;
int currentPartLength = 0;
char *currentPart = NULL;
// Check for input validity
if (!input) return EXP_INPUT;
if (!*parts) return EXP_OUTPUT;
if (separator == '\0') return EXP_SEP;
char *start = input;
char *currentPartStart = input;
char *end = input + strlen(input);
fprintf(stdout,"Inside the function\n");
for (char *thischar = start; thischar <= end; thischar++) {
if (*thischar != separator && *thischar != '\0') {
currentPartLength++;
continue;
}
printf("Inside check; current char is: %c\n",*thischar);
currentPart = calloc(1, currentPartLength + 1);
if (!currentPart)
goto cleanup;
if (currentPartLength > 0) {
strncpy(currentPart, currentPartStart, currentPartLength);
currentPart[currentPartLength] = '\0';
} else
currentPart[0] = '\0';
*parts=reallocarray(*parts,partCounter+1,sizeof(char*));
if (!*parts)
goto cleanup_current_part;
printf("About to add current part (%s) to the pile\n",currentPart);
// Add the new string part
(*parts)[partCounter++] = currentPart;
printf("About to check current part from the pile: %s\n",parts[partCounter-1]);
// Reset variables for the next part
currentPart = NULL;
currentPartStart = thischar + 1; // Skip the separator
currentPartLength = 0;
if('\0'==*thischar)
break;
}
free(currentPart);
return partCounter;
cleanup_current_part:
fprintf(stderr,"Unable to allocate memory for another part\n");
free(currentPart);
cleanup:
fprintf(stderr,"Unable to allocate memory for current part\n");
for (int i = 0; i < partCounter; i++)
free((*parts)[i]);
free(*parts);
return EXP_MALLOC;
}
int main(void) {
// ...
int partCount = str_explode(input, &parts, ';');
// ....
}
这会让你被贴上三星级程序员的标签(不是正面的)。两个好的重新设计是返回
parts
并使用哨兵 NULL
来表示没有更多元素。另一个不错的选择是创建一个结构体来保存指针和计数:
struct result {
char **parts;
int partCount;
}
您可以返回或用作输出参数(即传递它的地址)。