C++ 语法
C++ toupper Syntax
我刚刚接触了 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]);
(我试过了,所以我知道不行。)
从documentation开始,字符按值传递。
因此,答案是 不,不应该。
toupper
的原型是:
int toupper( int ch );
可以看到,字符是按值传递,按值转换,按值返回。
如果不把返回值赋值给变量,肯定会丢失。
这就是为什么在你的例子中它被重新分配以取代原来的。
toupper
按值取 int
,returns 取该大写字符 char
的 int
值。每次函数不将指针或引用作为参数时,参数将按值传递,这意味着无法从函数外部查看更改,因为参数实际上是传递的变量的副本对于函数,捕获更改的方法是保存函数 returns 的内容。在这种情况下,字符大写。
toupper
是一个按值获取参数的函数。 可以 定义为引用字符并就地修改它,但这会使编写仅检查字符大写变体的代码变得更加尴尬,如本例所示:
// compare chars case-insensitively without modifying anything
if (std::toupper(*s1++) == std::toupper(*s2++))
...
换句话说,toupper(c)
不会改变 c
,原因与 sin(x)
不会改变 x
的原因相同。
为了避免在赋值的左右两边重复像 string[i]
这样的表达式,取一个 reference 到一个字符,并用它来读写字符串:
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);
正如许多其他答案已经说过的那样,std::toupper
的参数被传递并且结果返回 by-value 这是有道理的,否则,你不会'不能打电话,说 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 != '[=10=]'; ++s)
*s = std::toupper(*s);
std::cout << text << '\n';
}
如果您觉得这样更漂亮,您可以使用 algorithm 进一步消除原始循环。
#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';
}
请注意,isalpha() 中有一个棘手的陷阱,如下所示:函数 仅 对 0-255 + EOF 范围内的输入有效。
那又怎样,你想。
嗯,如果你的 char 类型恰好是有符号的,并且你传递的值大于 127,这被认为是一个负值,因此传递给 isalpha 的 int 也将是负数(因此超出了0-255 + EOF)。
在 Visual Studio 中,这会使您的应用程序崩溃。我已经向微软投诉过这个问题,理由是一个对所有输入都不安全的字符分类函数基本上是没有意义的,但收到的答复是这完全符合标准,我应该写更好的代码。好吧,很公平,但是 标准中的其他地方 没有人关心 char 是有符号的还是无符号的。只有在 isxxx 函数中,它作为地雷,可以在没有任何人注意的情况下轻松通过测试。
以下代码崩溃 Visual Studio 2015(据我所知,所有早期版本):
int x = toupper ('é');
因此,您的代码中的 isalpha() 不仅是多余的,而且实际上是有害的,因为它会导致任何包含值大于 127 的字符的字符串使您的应用程序崩溃。
参见http://en.cppreference.com/w/cpp/string/byte/isalpha:"The behavior is undefined if the value of ch is not representable as unsigned char and is not equal to EOF."
我刚刚接触了 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]);
(我试过了,所以我知道不行。)
从documentation开始,字符按值传递。
因此,答案是 不,不应该。
toupper
的原型是:
int toupper( int ch );
可以看到,字符是按值传递,按值转换,按值返回。
如果不把返回值赋值给变量,肯定会丢失。
这就是为什么在你的例子中它被重新分配以取代原来的。
toupper
按值取 int
,returns 取该大写字符 char
的 int
值。每次函数不将指针或引用作为参数时,参数将按值传递,这意味着无法从函数外部查看更改,因为参数实际上是传递的变量的副本对于函数,捕获更改的方法是保存函数 returns 的内容。在这种情况下,字符大写。
toupper
是一个按值获取参数的函数。 可以 定义为引用字符并就地修改它,但这会使编写仅检查字符大写变体的代码变得更加尴尬,如本例所示:
// compare chars case-insensitively without modifying anything
if (std::toupper(*s1++) == std::toupper(*s2++))
...
换句话说,toupper(c)
不会改变 c
,原因与 sin(x)
不会改变 x
的原因相同。
为了避免在赋值的左右两边重复像
string[i]
这样的表达式,取一个 reference 到一个字符,并用它来读写字符串:
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);
正如许多其他答案已经说过的那样,std::toupper
的参数被传递并且结果返回 by-value 这是有道理的,否则,你不会'不能打电话,说 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 != '[=10=]'; ++s)
*s = std::toupper(*s);
std::cout << text << '\n';
}
如果您觉得这样更漂亮,您可以使用 algorithm 进一步消除原始循环。
#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';
}
请注意,isalpha() 中有一个棘手的陷阱,如下所示:函数 仅 对 0-255 + EOF 范围内的输入有效。
那又怎样,你想。
嗯,如果你的 char 类型恰好是有符号的,并且你传递的值大于 127,这被认为是一个负值,因此传递给 isalpha 的 int 也将是负数(因此超出了0-255 + EOF)。
在 Visual Studio 中,这会使您的应用程序崩溃。我已经向微软投诉过这个问题,理由是一个对所有输入都不安全的字符分类函数基本上是没有意义的,但收到的答复是这完全符合标准,我应该写更好的代码。好吧,很公平,但是 标准中的其他地方 没有人关心 char 是有符号的还是无符号的。只有在 isxxx 函数中,它作为地雷,可以在没有任何人注意的情况下轻松通过测试。
以下代码崩溃 Visual Studio 2015(据我所知,所有早期版本):
int x = toupper ('é');
因此,您的代码中的 isalpha() 不仅是多余的,而且实际上是有害的,因为它会导致任何包含值大于 127 的字符的字符串使您的应用程序崩溃。
参见http://en.cppreference.com/w/cpp/string/byte/isalpha:"The behavior is undefined if the value of ch is not representable as unsigned char and is not equal to EOF."