【问题标题】:Fully dynamical string arrays in CC中的完全动态字符串数组
【发布时间】:2014-05-20 19:24:40
【问题描述】:

我目前正在开发一个用 C 编写的非常基本的 shell。为此,我需要能够将输入字符串分解为“单词”,以便将其发送到 execvep()。为此,我创建了一个函数shishell(),它需要一个未知长度的字符串,并在内部创建一个字符串数组。由于事先不知道单词的大小和数量,因此字符串数组是完全动态的。

我的主要问题是,这个函数适用于字符串中的 1 或 2 个“单词”,但一旦超过 3 个“单词”,它就会开始崩溃,导致分段错误和双重免费损坏错误。

这是一个测试程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

int main(int argc, const char *argv[])
{
    shishell(argv[1]);
    return 0;
}

int fakexec(char** e_input_arr) {
    int c = 0;
    while(*e_input_arr) {
        char* x = *e_input_arr++; c++;
        printf(" >%d - %s\n", c, x);
    }
}

int shishell(char* e_input) {
    int n = 0,
    cur_i = 0,
    cur_w = 0;
    char tmp;
    char** input = malloc(sizeof(char*));
    input[n] = malloc(sizeof(char));

    while ((tmp = e_input[cur_i]) == ' ') {
        cur_i++;
    }
    while ((tmp = e_input[cur_i]) != '\0') {
        switch (tmp) {
            case ' ':
                if (cur_i) {
                    if (e_input[cur_i-1] != ' ') {
                        n++;
                        input = realloc(input, (n+1) * sizeof(char));
                        input[n] = malloc(sizeof(char));
                    }
                }
                cur_w = 0; cur_i++;
                break;
            default:
                input[n] = realloc(input[n], sizeof(char)*cur_w+2);
                input[n][cur_w] = e_input[cur_i];
                input[n][cur_w+1] = '\0';
                cur_w++; cur_i++;
                break;
        }
        printf(">%d - '%c'\n", n, tmp);
    }
    printf("Pre execuction\n");
    fakexec(input);

    printf("Post execuction\n");

    int j;
        for (j = 0; j < n; j++)
        free(input[j]);
    free(input);
}

这个程序需要一个字符串参数。

这里有一些示例输出:

% ./test test                              
>0 - 't'
>0 - 'e'
>0 - 's'
>0 - 't'
 >1 - test

% ./test "hello world" 
>0 - 'h'
>0 - 'e'
>0 - 'l'
>0 - 'l'
>0 - 'o'
>1 - ' '
>1 - 'w'
>1 - 'o'
>1 - 'r'
>1 - 'l'
>1 - 'd'
 >1 - hello
 >2 - world

对那些人来说一切都很好,但是:

% ./test "hello world foo"
>0 - 'h'
>0 - 'e'
>0 - 'l'
>0 - 'l'
>0 - 'o'
>1 - ' '
>1 - 'w'
>1 - 'o'
>1 - 'r'
>1 - 'l'
>1 - 'd'
>2 - ' '
>2 - 'f'
>2 - 'o'
>2 - 'o'
 >1 - hello
 >2 - world
 >3 - foo
zsh: segmentation fault (core dumped)  ./test "hello world foo"

我认为问题可能来自我对reallocmallocfree 的调用,但是,我并不是真的做错了什么,因为我正在根据需要进行重新定位。

【问题讨论】:

    标签: c arrays string shell multidimensional-array


    【解决方案1】:

    您的fakexec 函数包括while(*e_input_arr)

    这只有在您包含一个空终止条目时才能正常工作。但是您不这样做,因此它会读取分配空间的末尾,从而导致分段错误。

    实际上,您没有正确分配inputchar** input = malloc(sizeof(char*)); 行只为input[0] 分配空间。但是你增加n 并继续访问input[1] 等。

    【讨论】:

    • 我想补充一点,当他分配每一行时,他分配char*而不是分配char。做这种类型的功能,需要事先统计字数,才能分配一个包含足够内存的数组。
    • 好收获。使用 p = malloc( N * sizeof *p); 成语可以避免这些错误。
    • 在 @JulienFouilhé 和 @MattMcNabb cmets 之后,我修改了源代码以添加 input = realloc(input, sizeof(char*)*n+1); 以正确重新分配 input 并改变我重新分配线路的方式。我真的不明白while(*e_input_arr) 的问题,因为我对一两个词的想法没有任何问题。
    • @Marneus68 当您以这种方式浏览时,您必须确保在数组末尾放置一个 NULL,因为您不知道内存中的数组后面会是什么。如果有一个 NULL(就像当你有一两个单词时那样),它会起作用,否则你可能会进入未经授权的内存区域,你也会遇到分段错误。
    • realloc(input, sizeof(char*)*n+1); 错误,+1 需要与n 一起使用。同样,您可以通过使用成语 realloc(input, (n+1) * sizeof *input) 来避免这种情况
    猜你喜欢
    • 2017-10-03
    • 2017-08-27
    • 2021-12-29
    • 2013-03-09
    • 1970-01-01
    • 2011-10-21
    • 2012-02-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多