繁体   English   中英

strtok和fgets的奇数数组行为

[英]Odd array behaviour with strtok and fgets

我正在开发一个程序,它充当外壳解释程序,该程序读取带参数的命令并创建一个通过execvp()执行命令的子级。 我一直在做一些字符串操作来收集char数组*args[] ,特别是使用fgetsstrtok

这是我的代码的MCVE。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

#define MAX_LINE 80

int main(void){
    //initialize variables
    char *args[MAX_LINE/2 + 1];
    char input[MAX_LINE];
    //char input[MAX_LINE] = "some sentence unknown"; // <-- this line works fine..

    int counter = 0;
    printf("COMMANDER>");
    fflush(stdout);

    //receive input
    fgets(input,MAX_LINE,stdin);

    //parse input
    char *parser;
    parser = strtok(input," \r\t");

    //parse line
    while(parser != NULL){
                args[counter] = parser;
        counter++;  
        parser = strtok(NULL," ");
    }

    //print results
    int i = 0;
    for(i = 0; i < counter + 1;i++){
        printf("1");
        printf(" - %d: %s\n",i,args[i]);    
    } 

    return 0;
}

这里的问题是输出。 当我尝试运行此命令时,得到以下输出:

COMMANDER>some sentence unknown
1 - 0: some
1 - 1: sentence
1 - 2: unknown

1 - 3: (null)

我的问题是空白。 无论我做什么,我都无法分辨它的来源。

据我所知,它可能是字符串末尾的\\ n字符,但将其作为execvp(args[0],args)传递给execvp会产生错误,因为它将空行解释为“”的参数。

我注释掉了一行,这只是main开头的字符串分配。 如果使用此分配而不是fgets ,程序将运行,并且我将获得所需的输入:

COMMANDER>some sentence unknown
1 - 0: some
1 - 1: sentence
1 - 2: unknown
1 - 3: (null)

谢谢阅读。 我对C有点生疏,所以我独自坚持了几个小时,但仍然找不到解决方案。

如果您阅读例如fgets参考,您会看到它说

如果出现文件结尾或找到换行符,则分析停止,在这种情况下,str 将包含该换行符

[强调我的]

您所看到的“空白处”是fgets在字符串末尾添加的换行符。


但是,您的代码中存在一个更糟糕的问题。

char *args[MAX_LINE/2 + 1];

您定义了一个指针数组,但是未初始化该数组。 在C语言中,未初始化的局部(和非静态)变量实际上未初始化的。 它们的内容将不确定,并且几乎是随机的。

更具体地说,碰巧在args[counter]处获得一个空指针仅仅是运气。

尝试以任何方式使用该指针而不进行初始化将导致未定义的行为

简单的解决方案是将数组显式初始化为充满空指针:

char *args[MAX_LINE/2 + 1] = { NULL };

上面的代码将所有元素“零初始化”,这对于指针意味着它们将为NULL

fgets()读取的行包含尾随换行符'\\n' 您必须将其包含在strtok()识别为定界符的字符列表中。 此外,您必须将相同的列表传递给两个呼叫。

您还忘记将偏移量count项设置为NULL 具有自动存储功能的本地对象未初始化。 还要注意,您不应该将%s转换说明符的null指针传递给printf :尽管某些实现测试该参数并输出特定的字符串,但它具有未定义的行为。

这是更正的版本:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

#define MAX_LINE 80

int main(void){
    char *args[MAX_LINE/2 + 1];
    char input[MAX_LINE];
    int counter;

    printf("COMMANDER>");
    fflush(stdout);

    //receive input
    if (fgets(input, sizeof input, stdin)) {
        //parse input
        char *parser;
        parser = strtok(input, " \f\n\r\t");

        //parse line
        count = 0;
        while (parser != NULL) {
            args[counter] = parser;
            counter++;  
            parser = strtok(NULL, " \f\n\r\t");
        }
        args[counter] = NULL;

        //print results
        int i;
        for (i = 0; i <= counter; i++) {
            printf("1 - %d: %s\n", i, args[i] ? args[i] : "(null)");
        } 
    }
    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM