【问题标题】:Redirection input in C: fgets() end of line "\n" interfering with strcmp()C 中的重定向输入:fgets() 行尾“\n”干扰 strcmp()
【发布时间】:2014-03-09 15:54:08
【问题描述】:

这是我的代码:

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

int individualAverage(int data[][20],int j)
{
    int k,average=0;
    for(k=0;k<10;k++)
    {
        average += data[k][j];
    }
    return average;
}

int main()
{
    int var,indAvg=0;
    int i=0,j,k;
    char *experiments[20];
    int data[10][20];
    char str[100],str2[100];
    char *ptr, *token;
    int no_line=1;


    while(fgets(str,100,stdin) != NULL && (strcmp(str,"*** END ***") && strcmp(str,"*** END ***\n")))
    {
        if(no_line % 2 == 0)
        {
            k=0;
            token = strtok (str," ");
            while (token != NULL)
            {
                sscanf (token, "%d", &var);
                data[k++][i] = var;
                token = strtok (NULL," ");
            }
            i++;
        }
        else
        {
            ptr = strdup(str);
            experiments[i] = ptr;
        }
        no_line++;
    }

    fgets(str,100,stdin);
    token = strtok(str," ");
    while(token != NULL && (strcmp(token,"4") && strcmp(token,"4")))
    {
        sscanf (token, "%d", &var);
        printf("DATA SET ANALYSIS\n1.\tShow all the data\n2.\tCalculate the average for an experiment\n3.\tCalculate the average across all experiments\n4.\tQuit\nSelection: %d\n\n",var);
        switch(var)
        {
        case 1 :
            for(j=0;j<i;j++)
            {
                printf("%s",experiments[j]);
                for(k=0;k<10;k++)
                {
                    printf("%d ",data[k][j]);
                }
                printf("\n");
            }
            printf("\n");
            break;
        case 2 :
            printf("What experiment would you like to use?\n");
            token = strtok (NULL," ");
            sscanf (token, "%s", &str);
            for(j=0;j<i;j++)
            {
                if(strcmp(experiments[j],str) == 0)
                {
                    indAvg = individualAverage(data,j); 
                    printf("Experiment: %s",experiments[j]);
                    printf("The individual average of the experiment is %d\n",indAvg);
                    break;
                }
            }
        }
        token = strtok(NULL," ");
    }
}

好的,所以我有一个接受重定向输入行的方法。这些线成对出现。第一行是实验的名称,第二行包含该实验的 10 个值,用空格分隔。在这些对之后,有一个结束行"*** END ***"

在这一行之后,最后一行包含如何处理数据的说明。

我目前遇到一个问题,我使用fgets() 将第一对行的字符串存储到我声明为char *experiments[20]; 的变量中

由于fgets(),该数组指向的每个字符串的末尾都有'\n'

回到最后一行指令。您的值是 1-4。现在我在看指令2。它告诉了一个实验的平均值。所以在最后一行的 2 之后,必须有一个实验的名称。我用过:

char str[100];
int var;
char *token;
token = strtok(str, " ");
sscanf (token, "%d", &var);

将行上的第一个值放入var(假设它是2)。所以在那之后将是一个字符串。说是Test 1,我会用

token = strtok (NULL," ");
sscanf (token, "%s", &str);

将值放入str,然后我会将其与experiments 进行比较以获得所有可能的索引。
但是,因为fgets() 在行尾给出'\n',所以所有实验字符串的末尾都会有'\n',而str 只会有实验的名称而没有'\n',因此它们永远不会即使'\n' 是字符串之间的唯一区别,也要相等。

有什么解决办法吗?

【问题讨论】:

  • 您能否提供您的工作代码,并用评论标记您遇到问题的地方?你是说你使用fgets(),但我没有看到fgets()在任何地方使用......
  • 我已经用我的代码更新了它。正如你所看到的,实验基本上是从str 直接输入的,它来自fgets();
  • 为什么不喜欢删除'\n' 解决方案?
  • 我并不讨厌它,只是我在 getline 的手册页中读到了这个,并认为它会更简单:从is 提取字符并将它们存储到str 直到找到分隔符 delim (或换行符,'\n',用于 (2))。
  • 根据this pagegetline 确实包含\n,而getdelim 将包含您指定的分隔符...并不是我个人了解这些功能。跨度>

标签: c string fgets strtok


【解决方案1】:

由于您知道字符串末尾可能有一个\n,因此您可以检查它,如果存在则将其删除:

size_t len = strlen(str);
if (len != 0 && str[len-1] == '\n') {
    str[len-1] = '\0';
}

这将终止\n 处的行,因此您的strcmp 将成功。另一种方法是使用strncmp,并传递目标字符串的长度。但是,当有更长的后缀 \n 时,这存在误报的风险。

你也可以这样读取你的数据:

fscanf(f, "%99[^\n]", str);

【讨论】:

  • 有没有比 fgets() 更好的函数不会保留\n
  • 我刚刚找到了 getline(),我认为这可以让一切变得更简单?
  • @user32542 是的,它会的。您还可以使用 fscanf(f, "%99[^\n]", tmp) 来读取您的字符串。 99 是缓冲区的长度减去 null 终止符的长度。
  • 我不太明白这一点。究竟什么是代币?我看不到令牌是一个数组
  • 我没有在我的程序中打开文件,而是在命令行中重定向它:program
【解决方案2】:

您可以制作自己的fgets 版本,它在遇到换行符时不存储换行符,并将其命名为myfgets。我认为,这样的事情会复制fgets 的行为,这与description given in MSDN 有关:

char * myfgets( char * str, int n, FILE * stream ) {
    if ( n <= 0 ) return NULL;  // won't accept less than or equal to zero length

    int currentPos = 0;
    while ( n-- > 0 ) {
        int currentChar = fgetc( stream );
        if ( currentChar == EOF ) return NULL;
        if ( currentChar == '\n' ) break;
                    // if these two lines were in reversed order, 
                    // it would behave same as the original fgets
        str[currentPos++] = currentChar;
    }
    return str;
}

不过当然另一种方案更简单,呵呵……

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-05
    • 2016-04-05
    • 2014-04-12
    • 2022-01-05
    相关资源
    最近更新 更多