如何处理CS50首字母之前或之间的多个空格(更舒适)?

时间:2017-07-01 04:28:04

标签: c cs50

问题:http://docs.cs50.net/problems/initials/more/initials.html 正如我在标题中所说,如果用户在名称前输入额外的空格或在名字和姓氏之间输入额外的空格,我似乎无法让程序输出没有空格的首字母。

现在,它只有在我输入我的名字时才有效:First Last在名称前没有空格,两个单词之间只有一个空格。它将打印出FL而不需要任何额外的空格。我希望它能够做到这一点,无论我在名字和名字之前或之间有多少额外的空间。

我目前的代码:

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

int main(void) {
    printf("Name: ");
    string s = get_string();

    printf("%c", toupper(s[0]));

    for (int i = 0; i < strlen(s); i++) {
        if (s[i] == ' ') {
            printf("%c", toupper(s[i +1]));
        }
}

    printf("\n");
}

3 个答案:

答案 0 :(得分:2)

虽然您已经有了一个很好的答案,但假设string s = get_string();世界中的cs50.h仅使用以空字符结尾的字符串填充s,并且{{ 1}}是字符数组指向已分配内存的指针有几个区域可供您考虑改进。

首先,请勿使用s打印单个字符。这就是printf(或putchar)的用途。 (授予智能优化编译器应该为你做,但不要依赖编译器来解决你的低效问题)例如,而不是

fputc

简单地

printf("%c", toupper(s[0]));

此外,您可能还需要考虑一些逻辑问题。您想知道的是(1)&#34; 当前字符是否为字母?&#34; (例如putchar (toupper(s[0])); ,(2)&#34; 这是第一个字符(例如索引isalpha (s[x])),还是跟在空格后面的字符?&#34 ;(例如0)。除了信息之外,您可以使用单个s[x-1] == ' '输出首字母。

此外,如果putchar是一个字符串,您只需使用指针算术(例如s),当您到达 nul-terminator时结束 em>,或者如果您想将while (*s) {.. do stuff with *s ..; s++;}保留为指向第一个字符的指针,或者如果它是数组,那么s并对char *p = s;进行操作)

将这些部分组合在一起,您可以执行以下操作而不依赖p(您可以使用简单的string.h和第6位的位操作来消除对if的依赖功能也适用于以后):

ctype.h

示例使用/输出

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

int main (void) {

    char *p = NULL;

    printf ("Name: ");
    string s = get_string();    /* assuming this works as it appears */

    for (p = s; *p; p++)
        /* if current is [a-zA-Z] and (first or follows space) */
        if (isalpha (*p) && (p == s || (*(p - 1) == ' ')))
            putchar (toupper (*p));

    putchar ('\n');    /* tidy up */

    return 0;
}

答案 1 :(得分:0)

不要在strlen - 循环的条件下使用for,它将在每一步执行,更好地保存变量中的值并在条件中使用变量代替。

我会在这种情况下使用strtok,它会处理像Tom marvolo riddle这样的输入,其中名称之间有多个空格。

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


int main(void)
{

    char line[1024];

    fgets(line, sizeof line, stdin);

    char *token, *src = line;

    while(token = strtok(src, " \t"))
    {
        src = NULL; // subsequent calls of strtok must be called
                    // with NULL

        printf("%c", toupper(*token));
    }

    printf("\n");

    return 0;
}

使用strtok时,您必须记住不要传递字符串文字("this is a string literal"),因为它们是只读的,而strtok会在\0处写入malloc找到分隔符。如果您不知道您是否具有缓冲区的写入权限,则必须复制(在具有足够长度的静态缓冲区中,或使用strtok),然后使用{{1}中的副本}。

在我的示例中,我知道line不是只读变量,因此我可以安全地在strtok中使用(前提是我不再使用它,否则就是副本是必需的。)

strtok的一个问题是,它不是可重入的,而是使用strtok_r代替它。

char *token, *src = line, *saveptr;

while(token = strtok_r(src, " \t", &saveptr))
    ...

答案 2 :(得分:0)

为了使您的代码有效,一个简单的方法是添加一个标志,告诉前一个字符是否为空格。类似的东西:

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

int main(void) 
{
    int wasSpace = 1;   // Add a flag.
    printf("Name: ");
    string s = get_string();

    for (int i = 0; i < strlen(s); i++) 
    {
        if (wasSpace && s[i] != ' ')  // Only print if previous was a space and this isn't
        {
            wasSpace = 0;
            printf("%c", toupper(s[i]));
        }
        else if (s[i] == ' ')
        {
            wasSpace = 1;    // Update the flag
        }
    }
    printf("\n");
    return 0;
}