我尝试编码的是,如果我输入camelcase
,它应该打印出camelcase
,但如果包含任何大写,例如,如果我输入camelCase
,它应打印出camel_case
。
以下是我正在处理的问题,但问题是,如果我输入camelCase
,则会打印出camel_ase
。
有人可以告诉我原因以及如何解决这个问题吗?
#include <stdio.h>
#include <ctype.h>
int main() {
char ch;
char input[100];
int i = 0;
while ((ch = getchar()) != EOF) {
input[i] = ch;
if (isupper(input[i])) {
input[i] = '_';
//input[i+1] = tolower(ch);
} else {
input[i] = ch;
}
printf("%c", input[i]);
i++;
}
}
答案 0 :(得分:4)
首先查看您的代码并考虑当有人输入超过100个字符的单词时会发生什么 - &gt; 未定义的行为。如果您使用缓冲区进行输入,则总是必须添加检查,以便溢出此缓冲区。
但是,当你直接打印字符时,为什么还需要一个缓冲区呢?您展示的方法完全没有必要。试试这个:
#include <stdio.h>
#include <ctype.h>
int main()
{
int ch;
int firstChar = 1; // needed to also accept PascalCase
while((ch = getchar())!= EOF)
{
if(isupper(ch))
{
if (!firstChar) putchar('_');
putchar(tolower(ch));
} else
{
putchar(ch);
}
firstChar = 0;
}
}
附注:我将ch
的类型更改为int
。这是因为getchar()
返回int
,putchar()
,isupper()
和islower()
获取int
并且它们都使用unsigned char
的值1}}或EOF
。由于允许在带有签名char
的平台上对char
进行签名,因此您将获得使用否定char
调用这些函数的未定义行为。我知道,这有点复杂。解决此问题的另一种方法是,在调用将char
的值设为unsigned char
的函数时,始终将unsigned char
强制转换为int
。
当你使用缓冲区时,它现在没用了,你可能会感兴趣 一个可以很好地利用缓冲区的解决方案:一次读取和写入一行。这比为每个单个字符调用函数稍微有效一些。这是一个例子:
#include <stdio.h>
static size_t toSnakeCase(char *out, size_t outSize, const char *in)
{
const char *inp = in;
size_t n = 0;
while (n < outSize - 1 && *inp)
{
if (*inp >= 'A' && *inp <= 'Z')
{
if (n > outSize - 3)
{
out[n++] = 0;
return n;
}
out[n++] = '_';
out[n++] = *inp + ('a' - 'A');
}
else
{
out[n++] = *inp;
}
++inp;
}
out[n++] = 0;
return n;
}
int main(void)
{
char inbuf[512];
char outbuf[1024]; // twice the lenght of the input is upper bound
while (fgets(inbuf, 512, stdin))
{
toSnakeCase(outbuf, 1024, inbuf);
fputs(outbuf, stdout);
}
return 0;
}
此版本还避免了isupper()
和tolower()
,但牺牲了可移植性。如果字符编码按顺序包含字母并且在小写字母之前使用大写字母,则仅有效。对于ASCII,这些假设成立。请注意,被视为(大写)字母的内容也可能取决于区域设置。上述程序仅适用于英文字母A-Z。
答案 1 :(得分:0)
您的代码中存在两个问题:
if
的每个分支中插入一个字符,而其中一个字符应插入两个字符,_
和ch
。您可以通过在i
插入时增加i++
,并在结尾处打印整个字来解决此问题:
int ch; // <<== Has to be int, not char
char input[100];
int i = 0;
while((ch = getchar())!= EOF && (i < sizeof(input)-1)) {
if(isupper(ch)) {
if (i != 0) {
input[i++] = '_';
}
ch = tolower(ch);
}
input[i++] = ch;
}
input[i] = '\0'; // Null-terminate the string
printf("%s\n", input);
答案 2 :(得分:0)
我不知道如何在C中编码,但我认为你应该做这样的事情。
if(isupper(input[i]))
{
input[i] = tolower(ch);
printf("_");
} else
{
input[i] = ch;
}
答案 3 :(得分:0)
您的代码中存在多个问题:
ch
被定义为char
:如果c
未定义为int
,则无法正确测试文件结尾。 getc()
可以返回unsigned char
类型的所有值加上特殊值EOF
,这是负数。将ch
定义为int
。
您将字节存储到数组input
并使用isupper(input[i])
。 isupper()
仅针对getc()
返回的值定义,如果此类型在目标系统上签名,则不会针对char
类型的潜在负值定义。使用isupper(ch)
或isupper((unsigned char)input[i])
。
在将字节存储到i
之前,不检查input[i]
是否足够小,从而导致潜在的缓冲区溢出。请注意,没有必要将字符存储到数组中以解决您的问题。
您应该将'_'
插入数组并转换为小写的字符。这是你的主要问题。
您是希望将Main
转换为_main
,main
还是将Main
转换为规范问题。
这是一个更简单的版本:
#include <ctype.h>
#include <stdio.h>
int main(void) {
int c;
while ((c = getchar()) != EOF) {
if (isupper(c)) {
putchar('_');
putchar(tolower(c));
} else {
putchar(c);
}
}
return 0;
}
答案 4 :(得分:0)
要在显示的表单中输出输入的字符,则无需使用数组。该程序可以采用以下方式
#include <stdio.h>
#include <ctype.h>
int main( void )
{
int c;
while ((c = getchar()) != EOF && c != '\n')
{
if (isupper(c))
{
putchar('_');
c = tolower(c);
}
putchar(c);
}
putchar('\n');
return 0;
}
如果你想使用一个字符数组,你应该为终止零保留一个元素,如果你想要数组包含一个字符串。
在这种情况下,程序看起来像
#include <stdio.h>
#include <ctype.h>
int main( void )
{
char input[100];
const size_t N = sizeof(input) / sizeof(*input);
int c;
size_t i = 0;
while ( i + 1 < N && (c = getchar()) != EOF && c != '\n')
{
if (isupper(c))
{
input[i++] = '_';
c = tolower(c);
}
if ( i + 1 != N ) input[i++] = c;
}
input[i] = '\0';
puts(input);
return 0;
}