使用 gets() 按空格分隔字符串

Separating Strings by Spaces Using gets()

今天我有一个关于使用 gets() 函数用空格分隔字符串的问题。我有一个接受用户输入并按字母顺序排序的程序。我的问题出在 main 函数中,我在其中接收字符串。如果遇到行首的单个点或 EOF,程序应停止读取用户输入和 return 排序的链表。我正在使用 gets() 因为它是项目要求的一部分,但是我的问题是当我使用 gets 时它只是将整个字符串发送到我的排序函数而不是用空格分隔它。我的问题是:有没有办法用空格分隔 gets() 捕获的字符串?请在下面找到我的实现以及示例输入。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//defining node structure
typedef struct node
{
    char data[255];//can store upto 255 characters
    struct node *next;
}Node;
Node *head=NULL;//initially linked list is empty
//method to insert in sorted order
void insert_dictionary_order(char *a)
{
    Node *n = (Node*)malloc(sizeof(Node));//creating new node
    strcpy(n->data,a);//reading data
    n->next=NULL;
    Node *temp=head,*prev=NULL;
    if(temp==NULL)
    {
        head=n;
    }
    else
    {//inserting in right position
        while(temp!=NULL)
        {
            if(0<strcmp(temp->data,a))
                break;
            prev=temp;
            temp=temp->next;
        }
        if(prev==NULL)
        {
            n->next=head;
            head=n;
        }
        else
        {
            n->next=prev->next;
            prev->next=n;
        }
    }
}
//method to print all words in list
void print_list()
{
    Node *temp=head;
    while(temp!=NULL)
    {
        printf("%s ",temp->data);
        temp=temp->next;
    }
    printf("\n");
}
int main()
{
    printf("Enter words seperated by spaces:(. or EOF to stop):\n");

    do
    {
        char s[255];
        //scanf("%s",s);
        gets(s);
        if(strcmp(s,".")==0  || strcmp(s,"EOF")==0)
        {
            insert_dictionary_order(s);//adding to list
            break;
        }

        else
        {
            while((strcmp(s,'[=10=]') !=0) && (strcmp(s,' ') !=0))
            {
                insert_dictionary_order(s);//adding to list
            }
        }

    }
    while(1);
    //printf("The string: %s\n", s);
    //now printing list
     print_list();
    return 0;
}
This is a sample text.
The file will be terminated by a single dot: .
The program continues processing the lines because the dot (.)
did not appear at the beginning.
. even though this line starts with a dot, it is not a single dot.
The program stops processing lines right here.
.
You won't be able to feed any more lines to the program.

编辑:也允许使用 sscanf,但不允许使用 scanf

首先,一些其他的东西。

Don't use gets。让我们使用 fgets。一切都会一样,只是更安全。

您不应该使用全局 head。应将指向字典的指针传递给函数。我不打算在这里更正。

strcpy(n->data,a)不安全,你不知道a有多大。与其拥有浪费的静态缓冲区,不如存储 char * 并使用 strdup 复制和分配所需的内存。

typedef struct node
{
    char *data;
    struct node *next;
} Node;

Node *n = malloc(sizeof(Node));
n->data = strdup(word);

strcmp 比较整个字符串,因此 strcmp(s,".")==0 仅当 s 恰好是一个点时才会匹配。 strcmp(s,'[=23=]')strcmp(s,' ') 都不起作用,因为它们是单个字符,而不是字符串。编译器可以就此向您发出警告,但不幸的是它们在默认情况下处于关闭状态。打开它们。

strcmp(s,"EOF")==0 正在寻找字符串 EOF。这不是您检测文件结尾的方式。相反,请使用 feof(stdin) 检查您是否已到达文件末尾。

但是,checking for EOF is unnecessary 并会引起错误。正常的 fgets 循环是这样的:

// Allocate a large buffer and reuse it.
char line[BUFSIZ];

// `fgets` returns NULL on error or end-of-file, which is false.
while( fgets(line, sizeof(line), stdin) ) {
    // Put processing the line into a function to keep things simple.
    if( add_line(line) ) {
        // We saw a dot, exit the loop.
        break;
    }
}

Is there a way to separate the string captured by gets() by white spaces?

读取行后,我们可以使用 strtok (STRing TOKenize) 拆分行。 strtok 是一个有趣的函数,它有自己的内部状态。第一次调用时,它会记住调用的内容。然后用 NULL 调用它以继续在字符串中查找更多标记。

strtok 通过将分隔符替换为空字节来工作,这样您就可以读取每个标记而无需复制它。它确实修改了原始字符串,但是我们不关心line是否被修改了。

bool add_line(char *line) {
    char *token;
    for(
      token = strtok(line, " \t\n");  // split on spaces or tabs
      token;                          // stop when there's nothing more
      token = strtok(NULL, " \t\n")   // continue splitting line
    ) {
        printf("token: %s\n", token);
        if( strcmp(token, ".") == 0 ) {
            // We saw a lone dot, stop reading.
            return true;
        }

        insert_dictionary_order(token);
    }

    // Continue reading.
    return false;
}

在 space 和换行符上拆分很重要,否则换行符将成为每个标记的一部分。这会弄乱字典,并且行尾的点将是 ".\n" 而不是匹配。