我刚刚被介绍到toupper,我对语法有点困惑;它似乎在重复自己。我一直使用它的目的是对于字符串的每个字符,如果可能的话,它会将字符转换为大写字符。
for (int i = 0; i < string.length(); i++)
{
if (isalpha(string[i]))
{
if (islower(string[i]))
{
string[i] = toupper(string[i]);
}
}
}
为什么你必须列出两次string[i]
?这不应该行吗? toupper(string[i]);
(我试过了,所以我知道它没有。
toupper
是一个按值获取参数的函数。它可以被定义为接受对字符的引用并就地修改它,但这会使编写仅检查字符的大写变体的代码变得更加尴尬,如以下示例所示:
// compare chars case-insensitively without modifying anything
if (std::toupper(*s1++) == std::toupper(*s2++))
...
换句话说,toupper(c)
不会改变c
,原因与sin(x)
不会改变x
的原因相同。
若要避免在赋值的左侧和右侧重复表达式(如
string[i]
(,请引用字符并使用它来读取和写入字符串:
for (size_t i = 0; i < string.length(); i++) {
char& c = string[i]; // reference to character inside string
c = std::toupper(c);
}
使用基于范围的for
,上述内容可以更简短地编写(并更有效地执行(为:
for (auto& c: string)
c = std::toupper(c);
从文档中看,字符是按值传递的。
正因为如此,答案是否定的,不应该。
toupper
的原型是:
int toupper( int ch );
如您所见,字符按值传递、转换和返回。
如果不将返回值分配给变量,它肯定会丢失。
这就是为什么在您的示例中重新分配它以替换原始示例的原因。
正如许多其他答案已经说过的那样,传递给std::toupper
的参数并且结果返回了按值返回,这是有意义的,因为否则,您将无法调用,例如std::toupper('a')
。不能就地修改文本'a'
。您也可能将输入存储在只读缓冲区中,并希望将大写输出存储在另一个缓冲区中。因此,按价值计算方法要灵活得多。
另一方面,多余的是你检查isalpha
和islower
.如果该字符不是小写字母字符,toupper
无论如何都会保留它,因此逻辑简化为此。
#include <cctype>
#include <iostream>
int
main()
{
char text[] = "Please send me 400 $ worth of dark chocolate by Wednesday!";
for (auto s = text; *s != ' '; ++s)
*s = std::toupper(*s);
std::cout << text << 'n';
}
如果您发现这更漂亮,则可以通过使用算法进一步消除原始循环。
#include <algorithm>
#include <cctype>
#include <iostream>
#include <utility>
int
main()
{
char text[] = "Please send me 400 $ worth of dark chocolate by Wednesday!";
std::transform(std::cbegin(text), std::cend(text), std::begin(text),
[](auto c){ return std::toupper(c); });
std::cout << text << 'n';
}
>toupper
按值获取int
,并返回该大写字符char
的int
值。每次函数不将指针或引用作为参数时,参数都将按值传递,这意味着无法从函数外部查看更改,因为参数实际上是传递给函数的变量的副本,您捕获更改的方式是通过保存函数返回的内容。在本例中,字符大写。
请注意,isalpha(( 中有一个令人讨厌的陷阱,如下所示:该函数仅适用于 0-255 + EOF 范围内的输入。
那又怎样,你觉得。
好吧,如果你的 char 类型碰巧是有符号的,并且你传递的值大于 127,这被认为是负值,因此传递给 isalpha 的 int 也将是负值(因此超出了 0-255 + EOF 的范围(。
在Visual Studio中,这将使您的应用程序崩溃。我已经向Microsoft抱怨过这个问题,理由是对所有输入都不安全的字符分类函数基本上毫无意义,但得到的答复指出这完全符合标准,我应该写更好的代码。好吧,很公平,但是标准中的其他地方没有人关心char是有符号还是无符号。只有在 isxxx 函数中,它才能充当地雷,可以在没有人注意到的情况下轻松通过测试。
以下代码使Visual Studio 2015崩溃(据我所知,所有早期版本(:
int x = toupper ('é');
因此,代码中的 isalpha(( 不仅是多余的,而且实际上是有害的,因为它会导致任何包含值大于 127 的字符的字符串使应用程序崩溃。
请参阅 http://en.cppreference.com/w/cpp/string/byte/isalpha:"如果 ch 的值不能表示为无符号字符且不等于 EOF,则行为未定义。