字符串的printf不情愿地下线

时间:2016-11-22 13:36:54

标签: c printf

这是我的程序(学校练习,应该从用户接收字符串,更改它并以特定格式返回原始字符串和新字符串):

#include <stdio.h>
#define MAX_STRING_LENGTH 50

char switchChar(char c) {
    if ((c >= 'A') && (c <= 'Z')) {
        c = c + 32;
    } else
    if ((c >= 'a') && (c <= 'z')) {
        c = c - 32;
    }
    if ((c > '5') && (c <= '9')) {
        c = 56;
    }
    if ((c >= '0') && (c < '5')) {
        c = 48;
    }
    return c;
}

int main(void) {    
    char temp;
    int i = 0;

    char stringInput[MAX_STRING_LENGTH + 1];
    printf("Please enter a valid string\n");
    fgets(stringInput, 50, stdin);
    char newString[MAX_STRING_LENGTH + 1];

    while ((i != MAX_STRING_LENGTH + 1) && (stringInput[i] != '\0')) {
        temp = switchChar(stringInput[j]);
        newString[i] = temp;
        i++;
    }
    printf(  "\"%s\"", stringInput);
    printf("->");
    printf(  "\"%s\"", newString);

    return 0;
}

运行时,输出会在字符串之后和最后一个"字符之前向下移动,尽管它应该全部打印在同一行中。

我会很感激任何指示。

3 个答案:

答案 0 :(得分:3)

您的代码中存在以下几个问题:

  • fgets()在目标数组的末尾读取并保留换行符,如果存在,并且有足够的空间可用。为了与算法保持一致,您应该删除此换行符。您可以使用stringInput[strcspn(stringInput, "\n")] = '\0';安全地执行此操作,或者如果您无法使用<string.h>,请使用更多代码。这个换行符的存在解释了观察到的不良行为。

  • 您使用fgets()读取了一行,但是传递的缓冲区大小可能不正确:当数组大小为50时,硬编码为MAX_STRING_LENGTH + 1。将MAX_STRING_LENGTH定义为50时,这不是问题,但如果您稍后更改宏的定义,则可能忘记将size参数更新为fgets()。使用sizeof stringInput确保一致性

  • 您忘记在newString中设置空终止符。由于i在数组边界内以空值终止,因此无需测试stringInput的边界值。

  • switchChar()中,您不应该对ASCII字符集中的字符值进行硬编码:它会降低可移植性,最重要的是会降低可读性。

以下是更正后的简化版本:

#include <stdio.h>

#define MAX_STRING_LENGTH  50

char switchChar(char c) {
    if ((c >= 'A') && (c <= 'Z')) {
        c = c + ('a' - 'A');
    } else
    if ((c >= 'a') && (c <= 'z')) {
        c = c - ('a' - 'A');
    } else
    if ((c > '5') && (c <= '9')) {
        c = '8';
    } else
    if ((c >= '0') && (c < '5')) {
        c = '0';
    }
    return c;
}

int main(void) {    
    char stringInput[MAX_STRING_LENGTH + 1];
    char newString[MAX_STRING_LENGTH + 1];
    int c;

    printf("Please enter a valid string\n");

    if (fgets(stringInput, sizeof stringInput, stdin) != NULL) {
        // strip the newline character if present
        //stringInput[strcspn(stringInput, "\n")] = '\0';
        char *p;
        for (p = stringInput; *p != '\0' && *p != '\n'); p++)
            continue;
        *p = '\0';

        for (i = 0; stringInput[i] != '\0'; i++) {
            newString[i] = switchChar(stringInput[i]);
        }
        newString[i] = '\0';

        printf("\"%s\"", stringInput);
        printf("->");
        printf("\"%s\"", newString);
        printf("\n");
    }
    return 0;
}

答案 1 :(得分:1)

这是因为如果缓冲区中有空间并且它存储在fgets()中,newString也会读取换行符。

您可以使用以下命令将其删除:

 fgets(stringInput,50,stdin);
 stringInput[strcspn(stringInput, "\n")]  = 0; /* removes the trailing newline if any */

来自fgets()

  

fgets()从流中读取最多一个小于大小的字符   并将它们存储到s指向的缓冲区中。阅读停止后   EOF或换行符。如果读取换行符,则将其存储到
  缓冲。终止空字节('\ 0')存储在缓冲区中的最后一个字符之后。

答案 2 :(得分:0)

您的要求包含:

  • 只获得一个字符串
  • 对空白字符无特殊处理

在这种情况下,scanf可能比fgets更适应,因为前者将清除任何初始空白(空格或制表符)的输入并在第一个尾随空格(空格,制表符)之前停止,cr或换行符)。备注:当scanf在第一个空格之前停止时,该字符串不能包含空格或制表符。如果是问题,请使用fgets

只需更换一行:

fgets(stringInput, 50, stdin);

使用:

i = scanf("%50s", stringInput);
if (i != 1) {   /* always control input function return code */
     perror("Could not get input string");
     return 1;
}

如果您因任何原因优先使用fgets,则应删除(可选)尾随换行符:

if (NULL == fgets(stringInput, 50, stdin)) { /* control input */
     perror("Could not get input string");
     return 1;
}
int l = strlen(stringInput);
if ((l > 0) && (stringInput[l - 1] == '\n')) { /* test for a trailing newline */
    stringInput[l - 1] = '\0';                 /* remove it if found */
}