1

我使用此代码,但它不能正常工作。

#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

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

4

3 回答 3

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(),那么至少不要转换它的返回值

于 2013-06-14T16:56:44.090 回答
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;
}
于 2013-06-14T17:08:23.593 回答
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 个字符的单词(从代码中删除缓冲区溢出的更改)。

于 2013-06-14T17:14:45.247 回答