这是我的程序(学校练习,应该从用户接收字符串,更改它并以特定格式返回原始字符串和新字符串):
#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;
}
运行时,输出会在字符串之后和最后一个"
字符之前向下移动,尽管它应该全部打印在同一行中。
我会很感激任何指示。
答案 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 */
}