-1

我刚刚被介绍给 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]);(我试过了,所以我知道它没有。)

4

5 回答 5

4

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);
}

使用 range-based for,上面的代码可以写得更简洁(并且执行得更高效):

for (auto& c: string)
    c = std::toupper(c);
于 2016-02-13T21:36:35.830 回答
2

文档中看,字符是按值传递的。
因此,答案是否定的,它不应该

的原型toupper是:

int toupper( int ch );

如您所见,字符是按值传递、转换和按值返回的。
如果不将返回的值赋给变量,肯定会丢失。
这就是为什么在您的示例中它被重新分配以便替换原来的。

于 2016-02-13T21:33:58.990 回答
1

正如许多其他答案已经说过的那样,std::toupper传递给的参数并按返回结果,这是有道理的,因为否则,您将无法调用std::toupper('a'). 您不能'a'就地修改文字。您也可能将输入放在只读缓冲区中,并希望将大写输出存储在另一个缓冲区中。所以按价值的方法要灵活得多。

另一方面,多余的是检查isalphaand 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 != '\0'; ++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';
}
于 2016-02-13T21:46:25.840 回答
0

toupper接受一个int值并返回该大写字符的int值。char每次函数不将指针或引用作为参数时,参数将按值传递,这意味着无法从函数外部查看更改,因为参数实际上是传递的变量的副本对于函数,您捕获更改的方式是保存函数返回的内容。在这种情况下,字符大写。

于 2016-02-13T21:35:00.947 回答
0

请注意,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 的值不能表示为 unsigned char 并且不等于 EOF,则行为未定义。”

于 2016-02-13T22:28:24.653 回答