当试图格式化像argv这样的字符串时,malloc()不匹配next->prev_size

rdrgkggo  于 2023-04-19  发布在  其他
关注(0)|答案(1)|浏览(192)

我有一个主程序,我用open_memstream把stdin读到一个缓冲区中。现在我试图把字符串的结构做成像argv一样。

char **cli_argv;
char *buf;
size_t len;

void get_args() {
    int c;
    int c_count = 0;
    cli_argc = 0;
    char args[100];

    /* transfer buffer contents to a string, replacing whitespace and determine length */

    FILE *captured = fmemopen(buf,len,"r");

    if (captured == NULL) {
        debug("unable to fmemopen");
    } else {
        while ((c=fgetc(captured)) != EOF) {
            if (!isspace(c)) {
                args[c_count] = c;
            } else {
                args[c_count] = '\0';
                cli_argc++;
            }

            c_count++;
        }
    }
    fclose(captured);
    stop_input_stream();
    success("transfered contents of buf to string");

    /* find sizes of words and malloc enough memory */
    int arg_sizes[cli_argc];
    int argc_size = 0;
    int argc_index = 0;
    for (int i = 0; i < c_count; i++) {
        if (args[i] != '\0') {
            argc_size++;
        } else {
            arg_sizes[argc_index] = argc_size + 1;
            argc_index++;
            argc_size = 0;
        }
    }

    cli_argv = malloc(cli_argc * sizeof(char));
    *cli_argv = args;

    for (int i = 0; i < cli_argc; i++) {
        cli_argv[i] = malloc(arg_sizes[i] * sizeof(char));
    }

    for (int i = 0; i < cli_argc; i++) {
        fprintf(stderr,"%s\n",cli_argv[i]);
    }

}

然而,这段代码给了我一个malloc错误:

我试着把cliargc * sizeof((char))改为ccount*sizeof((char),以为我malloc的太少了。但不幸的是,这并没有使错误消失。此外,我不知道如何将cli_argv[i]设置为正确的指针。有人能帮忙吗?TIA。

h7appiyu

h7appiyu1#

忽略信号处理的问题(因为,从注解中可以看出,参数解析不会发生在信号处理程序中),这是我使用的:

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct
{
    char **argv;    /* Null-terminated vector of argument strings */
    char  *argb;    /* Data that elements of argv point to */
    size_t argc;    /* Number of arguments */
    /* av.argv[av.argc] == 0 */
} ArgVector;

static ArgVector make_argv(const char *buffer)
{
    ArgVector av =
    {
        /* At worst, there is one argument for every two characters */
        .argv = calloc(sizeof(av.argv[0]), (strlen(buffer) + 1) / 2 + 1),
        .argb = strdup(buffer),
        .argc = 0
    };

    if (av.argv == 0 || av.argb == 0)
    {
        free(av.argv);
        free(av.argb);
        av.argv = 0;
        av.argb = 0;
        return av;
    }

    char *s = av.argb;
    while (*s != '\0')
    {
        char c;
        while ((c = *s) != '\0' && isspace((unsigned char)c))
            s++;
        if (c != '\0')
        {
            av.argv[av.argc++] = s;
            while ((c = *s) != '\0' && !isspace((unsigned char)c))
                s++;
            if (c != '\0')
                *s++ = '\0';
        }
    }
    
    return av;
}

static void free_argv(ArgVector *av)
{
    if (av != 0)
    {
        free(av->argv);
        free(av->argb);
        av->argv = 0;
        av->argb = 0;
    }
}

int main(void)
{
    char   *buffer = 0;
    size_t  buflen = 0;
    ssize_t length;

    while ((length = getline(&buffer, &buflen, stdin)) > 0)
    {
        buffer[--length] = '\0';
        ArgVector av = make_argv(buffer);
        printf("line [%s]\n", buffer);
        printf("argc %zu\n", av.argc);
        for (size_t i = 0; i < av.argc; i++)
             printf("%zu = [%s]\n", i, av.argv[i]);
        free_argv(&av);
    }
    free(buffer);
    return 0;
}

ArgVector结构封装了关键信息-指向字符串的指针向量(argv)、输入字符串副本的基(开始)(argb)和参数的数量(argc)。argv的元素指向argb记录的字符串。
函数free_argv()释放分配的内存,使结构可以安全地重用。函数make_argv()对可能有多少空格分隔的参数进行保守估计。如果输入字符串是单个字母,有一个参数,calloc()的长度计算给出值2(允许空终止符)。如果有两个字母由空格分隔,则长度计算给出值3,依此类推。这是可以存在的最大参数数;如果字符串是30个没有空格的字母,那么它将过度分配argv数组。将realloc()数组调整到正确的大小是可能的,但是这样做的好处有限,除非过度分配是非常错误的-比如说,超过128字节(或者16个参数太多)。然后需要捕获argv数组中的条目数,这很容易完成,但是当前的代码没有这样做。代码检查内存分配是否成功,如果有问题,重置结构。它实际上可以调用free_argv()来完成重置-事实上,它可能应该这样做。
假设分配了必要的内存,主循环扫描字符串的副本,跳过白色,然后设置下一个参数指针,然后找到参数的结尾,并重复。
完成后,它返回结构。
主程序使用POSIX getline()来读取输入,因为它使工作变得如此简单。代码应该在删除它之前检查读取的最后一个字符是否是换行符。可以使用buffer[strcspn(buffer, "\n")] = '\0';来避免删除文件中没有以换行符结束的最后一个字符。
代码确实假设calloc()将指针设置为null -这是绝大多数CPU的情况,并且您不太可能遇到这样的系统(但曾经有过这样的系统,它可能是一个问题,曾经有四分之一世纪或更久以前)。
样品运行:

a  b  c
line [  a  b  c]
argc 3
0 = [a]
1 = [b]
2 = [c]
abc def  ghi jkl   
line [abc def  ghi jkl   ]
argc 4
0 = [abc]
1 = [def]
2 = [ghi]
3 = [jkl]

line []
argc 0
    
line [    ]
argc 0
    dddd     eeeee    zzzzz      
line [    dddd     eeeee    zzzzz      ]
argc 3
0 = [dddd]
1 = [eeeee]
2 = [zzzzz]
[ a = b + c ]
line [[ a = b + c ]]
argc 7
0 = [[]
1 = [a]
2 = [=]
3 = [b]
4 = [+]
5 = [c]
6 = []]

这为您提供了一个坚实的基础来适应您的需求。请注意,您需要以某种方式跟踪argvargb。这种机制为您提供了一个自包含的结构。在问题中的代码中,如果允许zap buf字符串,那么你可以使用它来代替复制。argc元素是可选的,但是很方便;argv末尾的空指针也可靠地告诉您有多少个参数。
解析代码可以变得更复杂,以识别带引号的字符串、反斜杠转义符和其他符号--仅白色处进行分割是相当简单的。
这些函数之所以被设置为static,是因为它们不能在源文件外部被访问。如果它们要在源文件外部被访问,则会有一个定义结构类型和两个函数签名的头文件-并且定义函数的文件和使用函数的文件都将包括该头文件以获得对相关信息的访问,当然,函数将不再是static

相关问题