用于从char类型中减去的简单C语法,小写

use*_*214 0 c syntax lowercase char

我得到一个段.当我尝试从char类型中减去32时(尝试在C中转换为小写而没有tolower())我已经完成了错误.我已经完成了前提条件搜索相关的Q/A线程而没有运气.我也试过'a' - 'A'对于转换值,'32',将其转换为(char*)以及我能想到的任何其他内容.例如:

char* s1 = "Bob";

if (*s1 >= 97 && *s1 <= 122)
     *s1 -= 32;
}
Run Code Online (Sandbox Code Playgroud)

有什么建议?

编辑:

在按照下面的帮助后,我仍然得到错误.(对于此示例,我只是尝试将名称的第一个字母更改为小写.)以下是我正在尝试的内容:

 char* s1 = "Bob";
 printf("\n %s before", s1);

 // below I call my string length function to get actual size instead of 100
 char* temp = malloc(100);   
 temp = s1;

 if (*temp >= 'A' && *temp <= 'Z'){
    *temp -= 32;
 }

 printf("\n%s after", temp);
 free(temp);
Run Code Online (Sandbox Code Playgroud)

另外,为什么我需要为已经在内存中的字符串分配内存?

Ric*_*dle 7

你不能像这样改变文字字符串 - 它们(通常)在只读存储器中.您需要制作字符串文字的可写副本:

char* name = "Bob";
char* s1 = strdup(name);

...

free(s1);  // And you also need this to avoid a memory leak!
Run Code Online (Sandbox Code Playgroud)


Kei*_*son 5

您的代码存在许多问题.

char* s1 = "Bob";
Run Code Online (Sandbox Code Playgroud)

字符串文字创建一个只读数组char; 这个数组是静态的,意味着它在程序的整个生命周期中都存在.由于历史原因,它不是const,因此如果您尝试修改它,编译器不一定会警告您,但您应该小心避免这样做.

s1指向该数组的第一个字符.你可能不会修改*s1.为安全起见,您应将指针声明为const:

const char *s1 = "Bob";
Run Code Online (Sandbox Code Playgroud)

如果你想要一个可修改的字符数组,你可以像这样创建它:

char s1[] = "Bob";
Run Code Online (Sandbox Code Playgroud)

现在让我们看看剩下的代码:

if (*s1 >= 97 && *s1 <= 122)
     *s1 -= 32;
}
Run Code Online (Sandbox Code Playgroud)

97122对于数字ASCII码'a''z'.32是小写字母和相应的大写字母之间的区别 - 再次,用ASCII.

C语言不保证字符以ASCII或与其兼容的任何字符集表示.例如,在IBM大型机上,字符以EBCDIC表示,其中字母的代码不连续(有间隙),相应的小写字母和大写字母之间的差异为64,而不是32.

EBCDIC系统现在很少见,但即便如此,便携式代码往往比非可移植代码更清晰,即使代码是否适用于所有系统的任何实际问题也是如此.

我相信你知道,最好的方法是使用这个tolower功能:

*s1 = tolower((unsigned char)*s1);
Run Code Online (Sandbox Code Playgroud)

请注意演员表unsigned char.由于历史原因,声明的to*()is*()函数<ctype.h>表现得很奇怪.他们不参与char辩论; 相反,他们研究int范围内的论点unsigned char.(他们也接受EOF,这通常是-1).如果plain char是有符号的,那么传递一个char恰好为负值的值会导致未定义的行为.是的,这很烦人.

但是你说你不想用tolower.(这很好;学会自己做这样的事情是一个很好的练习.)

如果你愿意假设大写字母是连续的,并且小写字母是连续的,那么你可以这样做:

if (*s1 >= 'a' && *s1 <= 'z') {
    *s1 -= 'a' - 'A';
}
Run Code Online (Sandbox Code Playgroud)

这仍然不能移植到非ASCII系统,但如果您没有记住ASCII表,它会更容易阅读.

它也让你的逻辑向后变得更加明显.你说你想转换为小写,但你的代码从小写转换为大写.

或者,您可以使用将小写字母映射到大写字母的查找表:

char to_lower[CHAR_MAX] = { 0 }; /* sets all elements to 0 */
to_lower['A'] = 'a';
to_lower['B'] = 'b';
/* ... */
to_lower['Z'] = 'z';
Run Code Online (Sandbox Code Playgroud)

或者,如果您的编译器支持复合文字:

const char to_lower[CHAR_MAX] = {
    ['A'] = 'a',
    ['B'] = 'b',
    /* ... */
};
Run Code Online (Sandbox Code Playgroud)

我会留给你填写剩下的代码来使用它.

现在你可以看到为什么tolowertoupper函数存在 - 所以你不必处理所有这些东西(除了unsigned char你需要的奇数演员).

更新:

回答您问题的新部分:

char* temp = malloc(100);   
temp = s1;
Run Code Online (Sandbox Code Playgroud)

该赋值temp = s1;不会复制分配的字符串; 它只是复制指针.temp指向100个字节的已分配空间,但随后您temp指向(只读)字符串文字,并且您丢失了对分配空间的任何引用,从而造成内存泄漏.

您无法在C中分配字符串或数组.要复制字符串,请使用以下strcpy()函数:

char *temp = malloc(100);
if (temp == NULL) {     /* Don't assume the allocation was successful! */
    fprintf(stderr, "malloc failed\n");
    exit(EXIT_FAILURE);
}
strcpy(temp, s1);
Run Code Online (Sandbox Code Playgroud)

另外,为什么我需要为已经在内存中的字符串分配内存?

它在内存中,但它是你不允许修改的内存.如果要修改它,则需要将其复制到可修改的位置.或者,正如我上面建议的那样,你可以把它放在读/写内存中:

char s[] = "Bob";
Run Code Online (Sandbox Code Playgroud)

该初始化将字符串复制到数组中s.

  • 代码中的问题非常多,您可能希望将此答案分成几部分并标记每个部分(与"##"或"###"标记一样). (2认同)