为什么我的char函数不能正常工作?

时间:2019-03-07 05:02:42

标签: c++

所以我还是C ++的新手,我正在尝试制作一个程序,让用户输入一个字符串,然后我的函数以相反的大小写返回字符串,所有字母均小写,然后全部大写。相反,我只是一直收到字符串的第一个字母,总是大写。不知道我在做什么错。有什么建议吗?

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

char answer[255] = "";
int max = strlen(answer);

void reverse() {
    for (int i = 0; i < max; i++) {
        if (islower(answer[i])) {
            isupper(answer[i]);
        }
        else if (isupper(answer[i])) {
            islower(answer[i]);
        }
        else if (isspace(answer[i])) {
            isspace(answer[i]);
        }
    }
    cout << answer[max];
}

void lower() {
    for (int i = 0; i < max; i++) {
        if (isupper(answer[i])) {
            islower(answer[i]);
        }
        else {
            answer[i] = answer[i];
        }
    }
    cout << answer[max];
}

void upper() {
    for (int i = 0; i < max; i++) {
        if (islower(answer[i])) {
            isupper(answer[i]);
        }
        else {
            answer[i] = answer[i];
        }
    }
    cout << answer[max];
}

int main() {

    cout << "Please enter a word, or a series of words: " << endl;
    cin >> answer[max];

    reverse();
    lower();
    upper();

    system("pause");
    return 0;
}

2 个答案:

答案 0 :(得分:0)

islower(char)只是一个内置功能,用于检查 char是否小写。 isupper也是如此。字符的大小写不变

要转换为小写/大写,请使用tolower / toupper。这将在转换后的情况下返回字符。但是,重要的是您需要将返回值分配给角色本身

有关islowerisuppertolowertoupper的更多说明,请参见this answer

  • 现在到了为什么只打印第一个字符的地步:正如@ user4581301在其评论中提到的
  

cin >> answer [max];将只读取一个字符,因为answer [max]只是一个字符,第一个字符。在C ++中,您必须按顺序进行操作。例如,int max = strlen(answer);将根据当时字符串中的内容提供答案。由于该字符串早于一行的初始化且包含一个空字符串,因此max为0。

因此,您的cin应该是cin >> answer,它将接受您句子中的第一个单词。为了接受包括空格在内的所有单词,请改用getline()。为了使用它,answer应该声明为string answer而不是char数组。

这是您接受完整句子的方式:getline(cin,answer);

  • 您的变量max在一些编译器中会因为模棱两可而出现错误。这是因为using namespace std;。为避免这种情况,请将max重命名为其他名称,例如maxlen
  • 并找到answer的长度:最好是在接受用户的字符串后调用answer.length(),而不是全局执行。

您的工作代码应如下所示:

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

string answer;
int maxlen;

void reverse() {
    for (int i = 0; i < maxlen; i++) {
        if (islower(answer[i])) {
            answer[i] = toupper(answer[i]);
        }
        else if (isupper(answer[i])) {
            answer[i] = tolower(answer[i]);
        }
        else if (isspace(answer[i])) {
            answer[i]=' '; 
        }
    }
    cout << "Reversed string: " + answer << endl;
}

void lower() {
    for (int i = 0; i < maxlen; i++) {
        if (isupper(answer[i])) {
            answer[i] = tolower(answer[i]);
        }
        else {
            answer[i] = answer[i];
        }
    }
    cout << "Lower case string: " + answer << endl;
}

void upper() {
    for (int i = 0; i < maxlen; i++) {
        if (islower(answer[i])) {
            answer[i] = toupper(answer[i]);
        }
        else {
            answer[i] = answer[i];
        }
    }
    cout << "Upper case string: " + answer << endl;
}

int main() {

    cout << "Please enter a word, or a series of words: " << endl;
    getline(cin,answer);
    cout << "Original string: " + answer << endl;
    maxlen = answer.length();
    reverse();
    lower();
    upper();
    return 0;
}

输出:

Please enter a word, or a series of words:
ReVeRsAl UPPER aNd lower
Original string: ReVeRsAl UPPER aNd lower
Reversed string: rEvErSaL upper AnD LOWER
Lower case string: reversal upper and lower
Upper case string: REVERSAL UPPER AND LOWER

答案 1 :(得分:0)

cin >> answer[max];

将只读取一个字符,因为answer[max]恰好是一个字符,即数组中位置max处的字符。

max为0,因为您必须按顺序进行操作。例如,

int max = strlen(answer);

将在到达此行时提供answer的长度。由于该字符串早已初始化了一行

char answer[255] = "";

并包含一个空字符串,max将为0。这意味着answer[max]answer[0]代码中的任何内容都不会更改max,因此它将保持为0。 / p>

好的,假设我们稍作改动,而不是读成一个字符,而是读成一个字符串answer。您将需要

cin.getline(answer, sizeof(answer));

因为

cin >> answer; 

将读取一个以空格分隔的令牌。一个词。您陈述的目标是阅读多个单词。 istream::getline会将在第一个参数中找到的所有内容读到行尾,或者在第二个参数中找到的字符数减去1(以为字符串的空终止符保留空间)。 sizeof(answer)实际上是answer数组的大小,以字节为单位。我们使用字节大小的字符进行操作,因此字符数和字节数相同。如果使用多字节字符,则必须格外小心。

这似乎是推荐使用std::stringstd::getline的好地方。它们会带来很多问题,例如在大多数情况下无法读取的最大字符数。

我不会在这里使用它们,因为该分配可能具有“无string s”政策。

因此,既然我们已经cin.getline(answer, sizeof(answer));读取了用户的输入,我们就可以获取max的大小。我们可以strlen,但也可以使用istream::gcount来获取getline读取的字符数。

main现在看起来像

int main() {

    cout << "Please enter a word, or a series of words: " << endl;
    cin.getline(answer, sizeof(answer));
    max = cin.gcount();

    reverse();
    lower();
    upper();

    system("pause");
    return 0;
}

此时,整堆东西都可能出错。

using namespace std;可能会对max造成严重破坏,因为可能与std::max发生冲突。通常,避免using namespace std;可以节省您经常键入的几个字母,而这可以避免浪费在调试它可能引起的奇怪错误上。

isupper(answer[i]);并没有像其他人在评论中指出的那样有用。您要

answer[i] = toupper(static_cast<unsigned char>(answer[i])); 

请参阅Do I need to cast to unsigned char before calling toupper(), tolower(), et al.?,以了解为何可能需要疯狂而毫无意义的演员表。谢谢HolyBlackCat引起我的注意。

之类的自我分配
answer[i] = answer[i];

毫无意义,因为一旦您停下来想一想,原因就会很明显。

类似

else if (isspace(answer[i])) {
    isspace(answer[i]);
 }

可能不是特别有用。如果answer[i]是空格,将其设置为空格吗?已经是一个空间了。它将用空格替换其他形式的空格,制表符和回车符。换行符已被getline选中。还可能需要与上述toupper示例中使用的转换类似的转换。我仍在阅读。

如上所述,

cout << answer[max];

无效。它输出一个字符,如果max已被修复,则answer[max]将是终止的null。而是打印出整个数组。

cout << answer;

一般建议:

不要一次写太多代码。在编译和测试之前,写几行,最多一个函数。如果您已经测试过

int main() {

    cout << "Please enter a word, or a series of words: " << endl;
    cin >> answer[max];
    cout << answer;
}

您将立即看到未正确读取数据。并在继续之前修复它。通过允许错误累积,您将很难发现任何一个错误。您可能正确地修复了一个错误,只是找到了被另一个错误撤消或隐藏的修复程序。

避免使用全局变量。尝试将变量放在尽可能小的范围内。在这种情况下,将answermax移至main并将它们作为参数传递给其他函数。这使得跟踪谁设置什么变量以及何时设置变得容易得多。它还有助于防止意外的Variable Shadowing