整行输入的极端麻烦.C程序设计语言



我正经历着最疯狂的时间,让整行输入工作。我会解释我的问题。我需要得到一整行输入,包括一个空格,从用户在键盘上输入。简单的对吧?错了!

我的目标

将多个带空格的字符串存储到变量中。如果有影响,我想让变量等于一个char指针。一旦我得到了tempString的输入,我想把它设为一个char指针。像这样:

char *variable1, *variable2;
//get user input
variable1 = tempString;
//get more user input
variable 2 = tempString;
//etc etc etc

这是我试过的。

第一次尝试

char tempString[100];
scanf("%s", &tempString);
printf("%s", tempString);

无效:scanf将在空白处停止读取,因此" Example String "将最终成为" Example "。

第二次尝试

所以我做了更多的研究。我以为我找到了神奇的解决办法。

char tempSTring[100];
fgets(tempString, 100, stdin);
printf("%s", tempString);

最初这是可行的。然而,有一个巨大的问题。我需要让用户输入大约8个输入。这意味着我必须使用像这样的命令8次。问题是程序经常跳过fgets命令。如果我之前使用了scanf,不知怎么的,n字符被卡在输入流中,并自动馈送到fgets,满足其stdin input,然后不提示用户输入。

第三次尝试

想到fgets可能是我的解决方案,我尝试了一些技巧。

char tempSTring[100];
getc(stdin);
fgets(tempString, 100, stdin);
printf("%s", tempString);

我试着添加这个getc(stdin)行。这对我的大部分项目都有效。它吸收流中留下的n字符。当它这样做时,很好,它起作用了。但是有时,由于某种原因,n没有留在流中,并且在调试时,看起来getc(stdin)正在请求用户的输入,因此它暂停我的程序以请求输入。

问题

这些不适合我。

  • 我应该如何做这个简单的任务?

要从文件中读取(最多)8行,您可以使用这两种解决方案中的任何一种。我拒绝使用变量char *variable1, *variable2, …; -那是一个寻求转义的数组。

POSIX getline()

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    enum { MAX_LINES = 8 };
    char *lines[MAX_LINES];
    int   index = 0;
    char *buffer = 0;
    size_t buflen = 0;
    while (index < MAX_LINES && getline(&buffer, &buflen, stdin) != -1)
    {
        lines[index++] = buffer;
        buffer = 0;
        buflen = 0;
    }
    free(buffer);  // Space may be allocated before EOF is detected
    for (int i = 0; i < index; i++)
        printf("%d: %s", i, lines[i]);
    return 0;
}

如果getline()分配内存失败,它将报告一个错误,因此不需要做显式的错误检查。

标准C fgets()

代码使用strdup(),另一个POSIX函数。它不是标准C的一部分(尽管它被广泛使用)。实现起来很简单。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
    enum { MAX_LINES = 8 };
    char *lines[MAX_LINES];
    int   index = 0;
    char   buffer[4096];
    while (index < MAX_LINES && fgets(buffer, sizeof(buffer), stdin) != 0)
    {
        if ((lines[index] = strdup(buffer)) == 0)
            break;
        index++;
    }
    for (int i = 0; i < index; i++)
        printf("%d: %s", i, lines[i]);
    return 0;
}

循环中的测试允许strdup()分配内存失败的可能性。

指出

上述两种解决方案都将换行符保留在输入字符串的末尾。如果你不想这样,你可以用:

lines[i][strcspn(lines[i], "rn")] = '';

用空字节覆盖回车符或换行符,转换DOS或Unix的行结束符。然后需要调整打印,它假设字符串包含换行符。请注意,即使字符串中没有回车或换行符,所显示的表达式也能正常工作。

fgets()解决方案将在4095个字符处断行,将其余部分读取为"下一行"。如果这是不可接受的,你有多种策略可供选择。

  1. 您可以检测是否有换行符,并安排分配更多内存,并将该行的下一部分读入额外的内存,重复直到遇到换行符或EOF。
  2. 您可以读取到换行符或EOF的剩余字符:

    int c;
    while ((c = getchar()) != EOF && c != 'n')
        ;
    

实现strdup()

如果由于某种原因您的系统没有strdup()的实现,您可以创建一个代理:

#include <assert.h>
#include <stdlib.h>
#include <string.h>
char *strdup(const char *old_str)
{
    assert(old_str != 0);
    size_t old_len = strlen(old_str) + 1;
    char *new_str = malloc(old_len);
    if (new_str != 0)
        memmove(new_str, old_str, old_len);
    return new_str;
}

我们这些老C程序员是这样做的:

#include <stdio.h>
#define MAX_LEN 100
int main( )
{
    int c;
    char input[MAX_LEN+1];
    int i = 0;
    while ( (c=getchar()) != 'n' && c != EOF && i < MAX_LEN)
        input[i++] = c;
    if (c == EOF || c =='n') {
        /* received input that terminated within buffer limit */
        input[i] = '';
        printf("read in your input string of: %sn", input);
    }
    else {
        printf("don't buffer overflow me dude!n");
        return -1;
    }
    return 0;    
}

但是现在人们会告诉你使用一个库函数。不过我还是个老屁。

EDIT:修正了下面有帮助的评论指出的我的尴尬错误

您可以通过这样写来处理以前的scanf留下的'n' -

scanf("%d%*c", &x);     //<-- example to take int input

%*c将从stdin中读取并丢弃它,因此'n'将从stdin中移除。

您可以像这样使用scanf (为您之前的尝试提供一种方法)-

char tempString[100];
/* As suggested by chqrile it is essential to check return of scanf */
if(scanf("%99[^n]", tempString)!=1){   
                //  ^^ & not required
     tempString[0]='';
}

%99[^n]这将读取99字符,只有在遇到'n'字符时才会停止,因此将读取带有空格的输入。

最新更新