C将动态字符数组转换为字符数组数组

C将动态字符数组转换为字符数组数组,c,arrays,multidimensional-array,dynamic-memory-allocation,C,Arrays,Multidimensional Array,Dynamic Memory Allocation,我正在研究一个函数,它必须获取一个动态字符数组,在空格处将其分隔,然后将每个单词放入一个字符数组中。代码如下: char** parse_cmdline(const char *cmdline) { char** arguments = (char**)malloc(sizeof(char)); char* buffer; int lineCount = 0, strCount = 0, argCount = 0; int spaceBegin = 0;

我正在研究一个函数,它必须获取一个动态字符数组,在空格处将其分隔,然后将每个单词放入一个字符数组中。代码如下:

char** parse_cmdline(const char *cmdline)
{
    char** arguments = (char**)malloc(sizeof(char));
    char* buffer;
    int lineCount = 0, strCount = 0, argCount = 0;
    int spaceBegin = 0;
    while((cmdline[lineCount] != '\n'))
    {
        if(cmdline[lineCount] == ' ')
        {
            argCount++;
            arguments[argCount] = (char*)malloc(sizeof(char));
            strCount = 0;
        }
        else
        {
            buffer = realloc(arguments[argCount], strCount + 1);
            arguments[argCount] = buffer;
            arguments[argCount][strCount] = cmdline[lineCount];
            strCount++;
        }
        lineCount++;
    }
    arguments[argCount] = '\0';
    free(buffer);
    return arguments;   
}
问题是,在这个过程中的某个地方,我遇到了一个分割错误,我不知道具体在哪里。
此外,当前版本的函数假定字符串不以空格开头,即对于下一个版本,我可以处理它,但我找不到seg的原因。错误

我的一些建议是,在打电话给malloc之前,你可能想先数一数你的单词数。然后调用malloc作为
char**charArray=malloc(参数*sizeof(char*))。这将是字符**字符的空间。然后,charArray中的每个元素都应该根据您试图存储在该元素中的单词的大小进行mallocate。然后您可以将该单词存储在该索引中。
例如,
*charArray=malloc(sizeof(word))
然后您可以将其存储为
**charArray=word

但是,要小心指针运算


分段错误肯定是由于您试图在未定义的空间中访问数组中的元素引起的。这是因为您没有为数组正确地分配空间。

此代码肯定不是您想要的:

char** arguments = (char**)malloc(sizeof(char));
它分配一个足够容纳一个字符的内存块,并设置一个类型为字符**
参数
)的变量来指向它。但是,即使您只想在
参数中为单个
字符*
分配足够的空间,您分配的空间也不够(无论如何,在任何您可能遇到的C系统上都不够)。对于多个指针来说,它肯定不够长

假设C系统上的指针确实比单个
char
s更宽,那么程序一旦取消引用
参数
,就会调用未定义的行为。分割错误是更可能的结果之一

最简单的方法可能是扫描输入字符串两次:一次是计算存在的各个参数的数量,以便为指针分配足够的空间,另一次是创建各个参数字符串并在数组中记录指向它们的指针

还要注意的是,返回值不包含任何关于分配了多少空间的可访问信息,因此也不包含您提取了多少参数字符串。解决这类问题的通常方法是为一个额外的指针分配空间,并将最后一个指针设置为
NULL
,作为哨兵。这与使用null
char
标记C字符串的结尾非常相似,但并不相同

编辑以添加:

参数所需的分配更像是这样:

arguments = malloc(sizeof(*arguments) * (argument_count + 1));
char** parse_cmdline( const char *cmdline )
{
也就是说,为一个比参数多的对象分配空间,每个对象的大小与
参数
要指向的对象类型相同。
sizeof
无法访问
arguments
的值,因此在该点不确定并不重要

编辑以添加:

最后的
free()
调用也有问题:

free(buffer);

此时,变量
buffer
指向与
arguments
的最后一个元素指向(或打算指向)相同的已分配块。如果释放它,那么指向该内存的所有指针都将失效,包括您将要返回给调用方的指针。与在任何其他分配之后释放缓冲区所需的时间相比,您不需要在该点释放缓冲区。

这可能就是出现分段错误的原因:

char**参数=(char**)malloc(sizeof(char))
,您已经使用了
malloc(sizeof(char))
,这只为单个字节分配空间(足够一个
char
)。这不足以在
参数中保存单个
字符*

但即使是在某些系统中,所以
参数[argCount]
也只是读取
argCount=0
的分配内存。对于
argCount
的其他值,数组索引超出范围-导致分段错误


例如,如果您的输入字符串是这样的-
“你好吗?”
,那么在到达
\n
之前,它有
4个字符,并且
argCount
的值将上升到
3
您想做的事情如下所示:

arguments = malloc(sizeof(*arguments) * (argument_count + 1));
char** parse_cmdline( const char *cmdline )
{
为参数指针数组分配长度为1的指针,并用0初始化它

char** arguments = malloc( sizeof(char*) );
arguments[0] = NULL;
char*
指针设置为yor命令行中的第一个
char
,并记住 第一个论点的开始

int argCount = 0, len = 0;
const char *argStart = cmdline;
const char *actPos = argStart;
继续,直到到达命令行的末尾。 如果您发现一个空参数,则有一个新参数,该参数由
argStart
actPos
之间的th个字符组成。从命令行分配和复制参数

while( *actPos != '\n' && *actPos != '\0' )
{
    if( cmdline[lineCount] == ' ' && actPos > argStart )
    {
        argCount++; // increment number of arguments
        arguments = realloc( arguments, (argCount+1) * sizeof(char*) ); // allocate argCount + 1 (NULL at end of list of arguments)
        arguments[argCount] = NULL; // list of arguments ends with NULL
        len = actPos - argStart;
        arguments[argCount-1] = malloc( len+1 ); // allocate number of characters + '\0'
        memcpy( arguments[argCount-1], actPos, len ); // copy characters of argument
        arguments[argCount-1] = 0; // set '\0' at end of argument string
        argStart = actPos + 1; // next argument starts after blank
    }
    actPos++;
}
return arguments;  

}

char*
char**
不是数组!指针不是数组!使用调试器找出位置。并且不要将
malloc()
强制转换为目标指针类型。阅读第一个问题的frequents选项卡。另外,
malloc(sizeof(char))
将只分配一个字节。@Olaf虽然指针不是数组,但如果它是malloced,并且有足够的空间,它可以用作数组。(指针运算可以用括号来完成,我相信这就是我认为这个人想要做的事情。)@JonathanSmit:我想你指的是订阅操作符。这只是因为在大多数情况下,数组都会衰减为指针,包括此运算符。即使指针指向同一类型的变量序列,指针也不是数组。请尝试
sizeof(char*)
char*=
&(char[4])`(类型表达式)。而
char**
仍然不是一个“数组数组”