我如何从c中的一行中取出单词?

时间:2013-06-14 16:50:20

标签: c string pointers scanf

我使用此代码但无效。

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

int main() {
    char line[120], *word;
    int o, row, col, letter, i;
    o = scanf("%s", line);
    row = 0;
    while(o != -1) {
        col = 0;
        while(isprint(line[col])) {
            word = (char *) malloc(sizeof(char)*20);
            for(i=0; i<20; i++) *(word + i) = 0;
            letter = 0;
            while(isalpha(line[col])) {
                *(word + letter) = line[col];
                col++;
                letter++;
            }
            col++;
            printf("%s\n", word);
            free(word);
        }
        row++;
        o = scanf("%s", line);
    }
return 0;
}

例如,我提供输入:

can you take a string?

我作为输出:

can
you
take
a
ke
string

我找不到错误,但输出距离我想要的距离不远意味着错误很小。请帮帮我... :)

3 个答案:

答案 0 :(得分:2)

这相当复杂。为什么不用空格字符分隔所有连续的非空格子串呢?

char buf[LINE_MAX];
fgets(buf, sizeof(buf), stdin);

char *end;
const char *seps = " \t\r\n\f\v";
char *p = strtok_r(buf, seps, &end);
printf("%s\n", p);
while (p = strtok_r(NULL, seps, &end))
    printf("%s\n", p);

更多建议:

  • 不要重新发明轮子。使用标准库而不是滚动自己的字符串处理(等)函数。它们可以促进您的生活,保证它们是正确的(至少在合理的高质量实现的情况下)并且它们使您的代码更短,从而更具可读性。

  • 当只需要本地(功能范围)存储时,更喜欢自malloc()以上的自动数组。可变长度数组是自C99以来的标准数组,因此在指定数组大小时,您甚至不需要将自己约束为常量整数表达式。

  • 但如果您决定使用malloc(),那么至少don't cast its return value

答案 1 :(得分:1)

我可以建议您稍微改进一下代码吗?

一种已知的安全方式来获取输入而不会使事情变得复杂的是使用fgets(已经指出)。

fgets允许您指定从控制台获取的字符数,以便不超过缓冲区的限制。

您可以使用fgets进行用户输入(使用stdin指针)或从文件中读取(通过提供文件句柄代替stdin)。

以下是如何简化逻辑的示例:

#include <stdio.h>

int main()
{
    char input [100];

    /* the [0] bit checks if only a newline has been entered thereby ignoring empty lines */
    /* we also check if fgets returns NULL, which may lead to undefined behavior if ignored */
    while(fgets(input, 100, stdin) != NULL && input[0] != '\n') 
    {
        int i = 0;                       /* this counter keeps track of the current char in the input */
        int w = 0;                       /* keep track if we are in a word, fixes printing newline for each white line */
        while(input[i] != '\0')          /* while we're not at the end of the string */
        {
            switch(input[i])
            {
                case ' ':                /* if the character is any of the below then print newline */
                case '\t':
                case '\r':
                case '\f':
                case '\v':
                case '\n':
                if (w) { w = 0; printf("\n"); } 
                break;
                default:
                if (!w) { w = 1; }
                printf("%c", input[i]);  /* otheriwse print the character itself */
            }
            i++;
        }
    }

    return 0;
}

答案 2 :(得分:0)

您似乎认为o = scanf("%s", line);会引入整行。这是不正确的,它只会读取第一个单词。除了缓冲区溢出和样式问题之外,您的整个程序基本上可以压缩为:

#include <stdio.h>

int main() 
{
    char line[120];
    while(scanf("%s", line) != -1)
    {
        printf("%s\n", line);
    }
    return 0;
}

输入:

can you take a string?

输出:

can
you
take
a
string?

如果您真的只想要字母字符,则必须描述其他非空白字符是否也被视为字分隔符,或者是否也被忽略。例如,word1word打印为word两次还是wordword


编辑:

假设你想完全忽略非字母,试试这个:

#include <stdio.h>
#include <ctype.h>

void PrintOnlyLetters(char word[])
{
    int i;
    int count = 0;

    for(i = 0; word[i] != '\0'; i++)
    {
        if(isalpha(word[i]))
        {
            count++;
            printf("%c", word[i]);
        }
    }

    if(count > 0)
    {
        printf("\n");
    }
}

int main() 
{
    char word[120];

    while(scanf("%119s", word) > 0)
    {
        PrintOnlyLetters(word);
    }

    return 0;
}

输入:

can yo4u t@ke one (/1) or more string(s)?

输出:

can
you
tke
one
or
more
strings

请注意,虽然这很简单并且无需读取未初始化的内存即可实现您想要的功能,但它仍然很脆弱。例如,它将分解超过119个字符的单词(更改以从代码中删除缓冲区溢出)。