为什么我会出现分段故障?当我使用SANITIZE=ADDRESS进行编译时,我得到了一个释放后堆使用,这是我不太理解的(原因). 我在地址xyz上得到了释放后的堆使用.

阅读尺寸为8英寸的……Test.c:22(打印部件的行[i])

...位于此处释放的8字节区域内的0个字节(字符串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中,参数是通过值传递的,这意味着在返回str_explode()时,对parts的更改本身就会丢失(并泄漏).这也意味着您最终在str_explore()中将parts作为reallocarray()的一部分,并在main()中使用相同的(未更改的)变量进行两次释放.

最小的修复是传入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, ';');
    // ....
}

以及产生的输出:

Inside the function
Inside check; current char is: ;
About to add current part (apple) to the pile
About to check current part from the pile: 6U
Inside check; current char is: ;
About to add current part (orange) to the pile
About to check current part from the pile: UfHAWAVAUL-DZ
Inside check; current char is: ;
About to add current part (banana) to the pile
About to check current part from the pile: apple;orange;banana;grape
Inside check; current char is: 
About to add current part (grape) to the pile
About to check current part from the pile: 
Original string: apple;orange;banana;grape
Number of parts: 4
About to print part #1:
Part 1: apple
About to print part #2:
Part 2: orange
About to print part #3:
Part 3: banana
About to print part #4:
Part 4: grape

这会让你被贴上三星级程序员的标签.两个好的重新设计是返回parts,并使用哨兵NULL来表示不再有元素.或者创建一个 struct 来保存两个结果值:

struct result {
   char **parts;
   int partCount;
}

可以返回它,也可以使用一个输出参数.

我建议您初始化char **parts = NULL,并让str_explode()分配您需要的值.释放一个常数parts[0] = "\0";...free(parts[i])是有缺陷的.无论如何,当您更改它时,不要一开始就对其进行初始化.

"\0"表示{ '\0', '\0' },因此我建议 Select '\0'""(但请参阅上文).

如果reallocarray()失败,则parts=reallocarray(parts, ...)会泄漏原始parts.将结果分配给Temporary.

C++相关问答推荐

C:fopen是如何实现二进制模式和文本模式的?

使用C时,Windows CMD中的argc参数是否包含重定向命令?

在 struct 中强制转换空指针

在为hashmap创建加载器时,我的存储桶指向它自己

X64:并发写入布尔数组

如何在C++中处理按键

tick.q中的Kdb+键控表语法

在另一个函数中使用realloc和指针指向指针

强制转换变量以在 struct 中蚕食

使用TCL C API导航到列表中的元素

在编写代码时,Clion比vscode有更多的问题指示器

通过描述符查找文件路径时出现问题

如何使用calloc和snprintf

C: NULL>;NULL总是false?

在同一范围内对具有相同类型的变量执行的相同操作在同一C代码中花费的时间不同

execve 不给出which命令的输出

'printf("%s", user_input)' 危险吗?

全局变量 y0 与 mathlib 冲突,无法编译最小的 C 代码

Zig 中 C 的system函数的惯用替代方案

如何在C中以0x格式打印十六进制值