>我正在尝试编写一个函数,将字符串的所有小写字母更改为大写。这是我的代码:
/**
* string_toupper - This function will replace all lowercase letters in
* the string pointed by str to uppercase
* @str: The string that will be checked for lowercase letters
*
* Return: The resulting string str, where all the letters are uppercase
*/
char *string_toupper(char *str)
{
int i;
for (i = 0; *str != ' '; i++)
{
if (str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
}
return (str);
}
我尝试了它:
#include <stdio.h>
int main(void)
{
char str[] = "Hello World!n";
char *ptr;
ptr = string_toupper(str);
printf("%sn", ptr);
printf("%sn", str);
return (0);
}
但是我得到以下输出:
Segmentation fault(core dumped)
我的方法 -->我将检查字符串是否有小写字母。然后,如果它与小写字符匹配,我将从字符中减去 32。我这样做是为了使字符变为大写,通过减去 32,我能够得到我在字符串中找到的相应小写字符的大写字母。
但是我收到一个Segmentation fault
错误,为什么会这样?
将for 循环条件更改为for (i = 0; str[i] != ' '; i++)
,因为它应该检查每个索引。
char *string_toupper(char *str)
{
int i;
for (i = 0; str[i] != ' '; i++)
{
if (str[i] >= 'a' && str[i] <= 'z')
str[i] =(int)str[i] - 32;
}
return (str);
}
根据要求,这是为教育和辩论提供的。
一些工作场所或机构坚持使用特定风格的大括号等。
请注意,函数名称不会在注释块中重现。坏习惯导致通过复制/粘贴错误且肯定具有误导性的评论块来满足主管。最好让代码使用传统的习语和标准库来解释自己。
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
char *string_toupper( char *str ) {
// Uppercase all lowercase letters found in 'str'.
// Return str after processing.
assert( str != NULL ); // Trust no-one, especially yourself
// Alternative for():: for( int i = 0; str[ i ]; i++ )
for( int i = 0; str[ i ] != ' '; i++ )
str[ i ] = (char)toupper( str[ i ] ); // note casting.
return str;
}
int main( void ) {
char str[] = "Hello World!";
// No further use? Don't store return value; just use it.
printf( "%sn", string_toupper( str ) );
printf( "%sn", str );
return 0;
}
Prithvish很好地解释了OP的关键问题:错误的循环测试。
// for (i = 0; *str != ' '; i++)
for (i = 0; str[i] != ' '; i++)
为了帮助OP如何使我的代码在每个环境中工作?,一些想法供以后考虑。
未来名称
"以str
、mem
或wcs
开头的函数名称以及小写字母可以添加到<string.h>
标头中的声明中。" C17dr § 7.31.13
因此,不要对以str<lowercase>
开头的函数名称进行编码,以避免将来发生冲突。
索引类型
int i;
对于长线来说太窄了。 使用size_t
进行数组索引。
或者,只需增加指针。
具有分类is...()
函数的测试用例
str[i] >= 'a' && str[i] <= 'z'
在以下系统上不正确 [a...z] 不是连续的。 (这些天不常见 - 例如EBCDIC)。
用topper()
简化
要将任何字符转换为等效的大写字符,请执行以下操作:
str[i] = toupper(str[i]);
使用未签名的访问权限
is..(x)
和toupper(x)
函数需要unsigned char
字符值(或EOF
)才能x
。
在即将过时的稀有非 2 补码系统上,应unsigned char
访问字符串,以避免在 -0 上停止。
把这个放在一起:
#include <ctype.h>
char *str_toupper(char *str) {
unsigned char *ustr = (unsigned char *) str;
while (*ustr) {
*ustr = toupper(*ustr);
ustr++;
}
return str;
}
您的代码中存在一个重大错误:
-
函数
string_toupper
中for (i = 0; *str != ' '; i++)
中的测试不正确:它只测试str
的第一个字符,而不是测试字符串的结尾。按照编码,您不断修改内存远远超出 字符串的末尾,直到到达无法读取或写入的内存区域,从而导致分段错误。代码具有未定义的行为。你应该写:for (i = 0; str[i] != ' '; i++)
-
另请注意,
if (str[i] >= 'a' && str[i] <= 'z')
假定小写字母在执行字符集中形成一个连续块。虽然 ASCII 是这种情况,但您不应在可移植代码中做出此假设。 -
同样,
str[i] -= 32;
特定于 ASCII 和相关字符集。您应该使用更具可读性的str[i] = str[i] - 'a' + 'A';
或使用<ctype.h>
中的函数。
这是一个修改版本:
#include <stdio.h>
/**
* string_toupper - This function will replace all lowercase letters in
* the string pointed by str with their uppercase equivalent
* @str: The string that will be checked for lowercase letters
*
* Return: The resulting string str, where all the letters are uppercase
*/
char *string_toupper(char *str) {
for (size_t i = 0; str[i] != ' '; i++) {
if (str[i] >= 'a' && str[i] <= 'z')
str[i] = str[i] - 'a' + 'A';
}
return str;
}
int main() {
char str[] = "Hello World!n";
char *ptr;
printf("before: %sn", str);
ptr = string_toupper(str);
printf("result: %sn", ptr);
printf(" after: %sn", str);
return 0;
}
这是string_toupper()
的便携式版本:
#include <ctype.h>
#include <stddef.h>
char *string_toupper(char *str) {
for (size_t i = 0; str[i] != ' '; i++) {
if (islower((unsigned char)str[i]))
str[i] = (char)toupper((unsigned char)str[i]);
}
return str;
}