使用malloc()初始化C中方法内的cstring数组

使用malloc()初始化C中方法内的cstring数组,c,arrays,string,C,Arrays,String,我试图用C语言创建一个简单的shell程序作为赋值。不幸的是,我还没有涉足C,只有C++,所以我对这些东西的工作原理没有很好的理解。 它应该至少持有5个令牌(1个命令和4个参数) #包括 #包括 #包括 #包括 #包括 int main(int argc,const char*argv[]{ bool=false; char*in=“ls-l”; char*parsedInput[6]; parseUserInput(in,parsedInput); 返回0; } void parseUserI

我试图用C语言创建一个简单的shell程序作为赋值。不幸的是,我还没有涉足C,只有C++,所以我对这些东西的工作原理没有很好的理解。 它应该至少持有5个令牌(1个命令和4个参数)

#包括
#包括
#包括
#包括
#包括
int main(int argc,const char*argv[]{
bool=false;
char*in=“ls-l”;
char*parsedInput[6];
parseUserInput(in,parsedInput);
返回0;
}
void parseUserInput(常量字符*输入,字符*用户输入[]){
int i=0;
int j=0;//表示用户输入的当前索引
userInput[j]=malloc(8);//8是任意的
while(输入[i]!='\0'){
printf(“字符%d:%c\n”,i,输入[i]);//调试信息
如果(输入[i]=''){//如果遇到空格,则在的下一个索引中启动新令牌
//字符串数组
j++;
用户输入[j]=malloc(8);
}否则{
strlcat(userInput[j],&input[i],1);//输入中标记末尾的Concat字符
}
i++;
}
}
调试器在
char*
类型的
parsedInput
数组中清楚地显示了6项,但是局部变量
userInput
(由于通过引用传递,因此应该是相同的数组)在调试器中没有索引

我不明白发生了什么事

p、 我曾尝试寻找解决方案,但一直未能找到

我希望该方法使用与每个“令牌”对应的字符串初始化数组
parsedInput


谢谢

您可以完全执行您正在尝试的操作,但是如果您声明了一个具有自动存储持续时间的指针数组,那么您必须确保将分配给您声明的数字的令牌数量限制为保护数组边界。你还应该考虑分配1个额外的指针,让你把<代码> null <代码>作为下一个指针,在你最后一个有效的令牌之后,作为一个前哨代码<代码> null >代码>标记你的数组中有效指针的结束。(与使用
*argv[]
一样,
execv
execvp
execve
功能需要)

要对字符串文字进行操作,不能修改
输入
字符串。处理
''
(空格)上的分隔字的最简单方法是使用一对指针(开始和结束指针),将结束指针沿字符串向下移动,直到找到一个空格,然后为开始和结束之间的字符数分配存储(+1表示nul终止字符)然后只需将字符复制到新分配的存储中,然后nul终止字符串

当循环将结束指针前进一步,使其指向空格后的下一个字符时,将开始指针设置为结束指针,使其位于下一个标记的开头。将指针索引数组前进到下一个指针,并在复制每个单词后将sentinel设置为
NULL

此外,您需要保留一个状态变量,一个简单的
int
,用作
1(true)/0(false)
标记,以跟踪您是在字读取字符中还是在读取空间外。这允许您跳过前导空格、标记之间的多个包含空格或最后一个标记后的尾随空格。这允许您将
“ls-l”
“ls-l”
拆分为相同的两个令牌
“ls”
“-l”

您的
parseUserInput()
可以写成:

#define MAXARG 6

void parseUserInput (char **userInput, const char *input)
{
    int i = 0, in = 0;                      /* index, and in/out of word flag */
    const char *p = input, *ep = p;         /* pointer and end-pointer */

    while (i < MAXARG) {                    /* loop while pointers remain */
        if (!*ep || *ep == ' ') {           /* if at nul-char or space */
            size_t len = ep - p;            /* get length of token */
            if (in && len) {                /* in-word and chars in token */
                /* allocate/validate storage for token */
                if (!(userInput[i] = malloc (len + 1))) {
                    perror ("malloc-userInput[i]");
                    break;
                }
                memcpy (userInput[i], p, len);  /* copy len chars to storage */
                userInput[i++][len] = 0;        /* nul-terminate, advance index */
                userInput[i] = NULL;        /* set next pointer NULL */
            }
            if (!*ep)                       /* if at end, break */
                break;
            in = 0;                         /* set in-word flag 0 (false) */
        }
        else {  /* normal word char */
            if (!in)                        /* if not in-word */
                p = ep;                     /* update start to end-pointer */
            in = 1;                         /* set in-word flag 1 (true) */
        }
        ep++;   /* advance to next character */
    }
}
注意:别忘了
释放()
您分配的存储空间)

示例使用/输出

$ ./bin/splitinput
ls
-l

仔细检查一下,如果您还有其他问题,请告诉我。

在函数中将类型更改为
char**
是否可以解决问题?因为如果它是指针数组,它可能不是通过引用。我记不清它是怎么工作的了。@SamiKuhmonen我最初将类型设置为该类型,但问题仍然存在。事实上,我把它改成了现在的样子,以便修复它。哈哈,你也可以尝试将尚未初始化的字符连接到内存中,这样就可以发生任何事情,因为内存中没有指定null。@SamiKuhmonen我以为使用malloc可以初始化字符串。您可以看到,在我进入while循环之前,我使用它只分配的malloc(8)初始化了数组中的第一个元素。未指定该内存包含的内容。我认为您应该引用
execv()
execve()
execvp()
函数,而不是
l
-等效函数。
l
-等价物不能在通用shell中使用,因为传递给它们的参数数量必须在编译时已知,而shell不知道将出现多少个参数。有时,您可以通过将额外参数作为空指针传递而避开
execl()
execlp()
,但是
execle()
会被混淆;它期望环境在第一个NULL之后。您是最正确的。我很匆忙,检查了手册页上的帽子,并键入了错误的变体。非常感谢。惊人的反应!为什么是memcpy()而不是strlcpy()?因为在结束指针处没有
'\0'
。(对于笔直的strcpy,您只需一英寸一英寸地向下移动
input
,将字符括在起始指针
p
和结束指针
ep
之间,并在它们之间复制字符。您可以使用
strncpy
,但是
strlcpy
不是标准的C。为了便于携带,每个人都有
memcpy
,并且您已经用
ep-p
计算了长度,因此无需传递到另一个函数重新计数。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXARG 6

void parseUserInput (char **userInput, const char *input)
{
    int i = 0, in = 0;                      /* index, and in/out of word flag */
    const char *p = input, *ep = p;         /* pointer and end-pointer */

    while (i < MAXARG) {                    /* loop while pointers remain */
        if (!*ep || *ep == ' ') {           /* if at nul-char or space */
            size_t len = ep - p;            /* get length of token */
            if (in && len) {                /* in-word and chars in token */
                /* allocate/validate storage for token */
                if (!(userInput[i] = malloc (len + 1))) {
                    perror ("malloc-userInput[i]");
                    break;
                }
                memcpy (userInput[i], p, len);  /* copy len chars to storage */
                userInput[i++][len] = 0;        /* nul-terminate, advance index */
                userInput[i] = NULL;        /* set next pointer NULL */
            }
            if (!*ep)                       /* if at end, break */
                break;
            in = 0;                         /* set in-word flag 0 (false) */
        }
        else {  /* normal word char */
            if (!in)                        /* if not in-word */
                p = ep;                     /* update start to end-pointer */
            in = 1;                         /* set in-word flag 1 (true) */
        }
        ep++;   /* advance to next character */
    }
}

int main (void) {

    char *in = "ls -l",
        *parsedInput[MAXARG + 1] = { NULL };    /* add +1 for sentinel NULL at end */

    parseUserInput (parsedInput, in);           /* note: parameter order change */

    for (char **p = parsedInput; *p; p++) {     /* loop over filled pointers */
        puts (*p);
        free (*p);      /* don't forget to free what you allocate */
    }
}
$ ./bin/splitinput
ls
-l