如何将 cstring 作为函数传递 parameter/argument

How to pass a cstring as a function parameter/argument

我有一个小程序可以打印出单词中每个字母的大写形式,但是当我编译它时出现错误 signed/unsigned mismatch 因为我将 cstring 作为正常传递 string 在这个程序中。如何正确传递它以便我仍然可以使用 text.length()?这是我得到的错误“Tester.cpp(22,23):警告 C4018:'<':signed/unsigned 不匹配”。在 for (int i = 0; i < text.length(); i++)

#include <iostream>
using namespace std;

string capitalizeFirstLetter(string text);

int main() {
    char sentence[100];
    for ( ; ; )
    {
        cin.getline(sentence, 100);
        if (sentence != "0")
            capitalizeFirstLetter(sentence);
    }

    return 0;
}

string capitalizeFirstLetter(string text) {

    for (int i = 0; i < text.length(); i++)
    {
        if (i == 0)
        {
            text[i] = toupper(text[i]);
        }
        if (text[i] == ' ')
        {
            ++i;
            text[i] = toupper(text[i]);
        }
    }
    cout << text;

    return text;
}

由于您将 cstring 作为正常 string 传递给函数,因此未生成错误,但这是因为您正在尝试使用 != 运算符比较 c 样式字符串在声明中

if (sentence != "0")
    capitalizeFirstLetter(sentence);

为此尝试使用 strcmp()

您的代码有问题:

  1. if (sentence != "0"):非法比较。如果您想中断获取 0 作为输入,请尝试使用 strcmp(包括 <cstring>)作为 if (strcmp(sentence, "0")。 (请注意,当两个字符串 相等 时,strcmp returns 0。)或者简单地执行 if (!(sentence[0] == '0' and sentence[1] == 0))。此外,此条件应伴随 else break; 以防止 for 循环永远 运行。

  2. for (int i = 0; i < text.length(); i++) :由于有符号和无符号类型之间的比较而生成警告。将 i 的 data-type 更改为 string::size_type 以防止警告。

  3. <string>(对于std::string)和<cctype>(对于std::toupper)不包括在内。

  4. 感谢 @john 指出这一点。如果字符串的最后一个字符是 space,则您的代码具有未定义的行为。在使用 text[i].

    之前添加检查 i 是否仍然小于 text.length()
  5. 另一种错误情况是 space 在 0 之后。将 getline 移动到 for 的条件来解决这个问题。现在不需要输入 0 来终止程序。此外,我建议为此使用 while 循环而不是 for.

  6. 您可能还需要打印换行符来分隔句子。此外,我更喜欢使用 capitalizeFirstLetter.

    返回的字符串在 main() 函数中打印修改后的句子
  7. 代码短(beginner-level)没关系,但要避免养成每写代码都把using namespace std;放在最前面的习惯。 Refer this.

固定码:

#include <cctype>
#include <cstring>
#include <iostream>
#include <string>
using namespace std;

string capitalizeFirstLetter(string text);

int main() {
  char sentence[100];
  while (cin.getline(sentence, 100))
    cout << capitalizeFirstLetter(sentence) << '\n';
}

string capitalizeFirstLetter(string text) {
  for (string::size_type i = 0; i < text.length(); i++) {
    if (i == 0)
      text[i] = toupper(text[i]);
    if (text[i] == ' ')
      if (++i < text.length())
        text[i] = toupper(text[i]);
  }
  return text;
}

Sample Run :

输入:

hello world
foo bar

输出:

Hello World
Foo Bar

我的版本(需要 C++20):

#include <cctype>
#include <iostream>
#include <string>

auto capitalizeFirstLetter(std::string text) {
  for (bool newWord = true; auto &&i : text) {
    i = newWord ? std::toupper(i) : i;
    newWord = std::isspace(i);
  }
  return text;
}

int main() {
  std::string sentence;
  while (std::getline(std::cin, sentence))
    std::cout << capitalizeFirstLetter(sentence) << std::endl;
}

Sample Run

这里有几件事困扰着我。

首先,不要使用using namespace std,在这种情况下它是“好的”,但不要习惯它,它会引起相当大的麻烦。 参见 Why is “using namespace std;” considered bad practice?

下一步是,这里只使用 std::string 而不是 cstrings,它更容易编写和读取,并且不会产生任何可测量的性能损失或其他问题。而且这样更难产生错误。 所以只需使用

std::string sentence;

getline(std::cin, sentence);

为什么要在转换字符串的函数中处理输出?只需让 main 打印转换后的字符串即可。 所以您的主要内容可能如下所示:

int main() {
    std::string sentence;
    
    while(true)
    {
        getline(std::cin, sentence);
        auto capitalized = capitalizeFirstLetter(sentence);
        std::cout << capitalized;
    }

    return 0;
}

PS:您得到的 'error' 是一个警告,因为您将 int itext.length() 进行比较,后者属于 size_t 类型 [=18] =] 或 unsigned long int.

处理将 sentence 作为字符串传递的最简单方法是将其包含在花括号集中,以便为参数 std::string text 提供 直接初始化 例如..

    for ( ; ; )
    {
        std::cin.getline(sentence, 100);
        if (*sentence)
            capitalizeFirstLetter({sentence});
    }

这允许字符串 sentence 用作 Direct initialization 以在您的 capitalizeFirstLetter() 函数中初始化 std::string text:

std::string capitalizeFirstLetter (std::string text) {

    for (size_t i = 0; i < text.length(); i++)
    {
        if (i == 0)
        {
            text[i] = toupper(text[i]);
        }
        if (text[i] == ' ')
        {
            ++i;
            text[i] = toupper(text[i]);
        }
    }
    std::cout << text;

    return text;
}

阅读 Why is “using namespace std;” considered bad practice? 后,您的完整代码将是:

#include <iostream>

std::string capitalizeFirstLetter (std::string text) {

    for (size_t i = 0; i < text.length(); i++)
    {
        if (i == 0)
        {
            text[i] = toupper(text[i]);
        }
        if (text[i] == ' ')
        {
            ++i;
            text[i] = toupper(text[i]);
        }
    }
    std::cout << text;

    return text;
}

int main (void) {
    
    char sentence[100];
    
    for ( ; ; )
    {
        std::cin.getline(sentence, 100);
        if (*sentence)
            capitalizeFirstLetter({sentence});
    }

    return 0;
}

(注意: 取消引用 sentence 提供第一个字符,然后确认为 nul-terminating[=46 以外的字符=] 字符 (ASCII 0))

更好的 CapitalizeFirstLetter()

一种更简单的大写方法是包含 <cctype> 和一个 int 来保存最后读取的字符。然后逻辑简单地遍历每个字符,如果第一个字符是 alpha-character,则将其大写,否则仅当当前字符是 alpha-character 且最后一个字符是空格时才将字母大写,例如

std::string capitalizeFirstLetter (std::string text)
{
    int last = 0
    
    for (auto& c : text)
    {
        if (isalpha(c))
        {
            if (!i || isspace (last))
                c = toupper(c);
        }
        last = c;
    }
    std::cout << text;

    return text;
}

(注:上面使用了一个range-basedfor循环)

两种方法都行。