Передача строки типа C в стиле char * в аргумент функции - PullRequest
0 голосов
/ 05 июня 2019

Я хочу изменить символы в строке, переданной пользователем, преобразованной в строку в стиле C и переданной в качестве аргумента функции с аргументом char *:

#include <string>
#include <cstring>
#include <iostream>
#include <stdlib.h>

void functoupper(char *myString)
{
    int i=0;
    char z;
    do {
        z= myString[i];
        myString[i]=toupper(z);
        ++i;
    } while(myString[i]!=0);
}

int main() {

    std::string name;

    std::cout << "Please, enter your full name in small caps: ";
    std::getline (std::cin,name);
    const char *myString = name.c_str();
    std::cout << "Hello, " << functoupper(myString) << "!\n";

    return 0;   
}

Я получаю сообщение об ошибке: неверное преобразование из 'const char *' в 'char *' [-fpermissive] при вызове функции functoupper (myString) в main ().

Ответы [ 2 ]

3 голосов
/ 05 июня 2019

Метод std::string::c_str() возвращает указатель на данные const char, но ваша функция ожидает указатель на неконстантные char данные.Вот почему вы получаете ошибку.

Вы можете использовать const_cast, чтобы отбросить const (но это не очень рекомендуется):

char *myString = const_cast<char*>(name.c_str());
functoupper(myString);
std::cout << "Hello, " << name << "!\n";

Вы можете использовать неконстантный std::string::operator[] для доступа к базовым символьным данным строки (просто будьте осторожны, потому что до C ++ 11 символы не требовались для хранениянепрерывно в памяти, но большинство std::string реализаций сделали):

functoupper(&name[0]);
std::cout << "Hello, " << name << "!\n";

В C ++ 17 и более поздних версиях вы можете использовать неконстантные std::string::data() метод вместо:

functoupper(name.data());
std::cout << "Hello, " << name << "!\n";

При этом обратите внимание на это предупреждение при использовании toupper():

Как и все другие функции из <cctype>поведение std::toupper не определено, если значение аргумента не может быть представлено как unsigned char или равно EOF.Чтобы безопасно использовать эти функции с обычными char с (или signed char с), аргумент должен быть сначала преобразован в unsigned char ... Аналогично, они не должны напрямую использоваться со стандартными алгоритмами, когда тип значения итератора равен char или signed char.Вместо этого преобразуйте значение в unsigned char first

. С учетом вышесказанного попробуйте что-то более похожее на это:

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

void functoupper(char *myString)
{
    for (int i = 0; myString[i] != '\0'; ++i) {
        unsigned char z = static_cast<unsigned char>(myString[i]);
        myString[i] = static_cast<char>(std::toupper(z));
    }
}

int main() {

    std::string name;

    std::cout << "Please, enter your full name in small caps: ";
    std::getline(std::cin, name);
    functoupper(&name[0]); // or name.data()
    std::cout << "Hello, " << name << "!\n";

    return 0;   
}

При этом вы должны просто пропустить std::string как есть в вашей функции, а затем вы можете манипулировать ею по мере необходимости, например, с помощью алгоритма std::transform():

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

void functoupper(std::string &myString)
{
    std::transform(myString.begin(), myString.end(), myString.begin(),
      [](unsigned char ch){ return std::toupper(ch); }
    );
}

int main() {

    std::string name;

    std::cout << "Please, enter your full name in small caps: ";
    std::getline(std::cin, name);
    functoupper(name);
    std::cout << "Hello, " << name << "!\n";

    return 0;   
}

В качестве альтернативы:

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

std::string functoupper(std::string myString)
{
    std::transform(myString.begin(), myString.end(), myString.begin(),
      [](unsigned char ch){ return std::toupper(ch); }
    );
    return myString;
}

int main() {

    std::string name;

    std::cout << "Please, enter your full name in small caps: ";
    std::getline(std::cin, name);
    std::cout << "Hello, " << functoupper(name) << "!\n";

    return 0;   
}
2 голосов
/ 05 июня 2019

Как комментируют @Someprogrammerdude и @RemyLebeau, почему бы не просто :

std::transform(std::begin(name), std::end(name), std::begin(name), 
    [](const unsigned char c)
    {
        return std::toupper(c);
    });

Но если вы должны сделать это через char*, тогда вам нужно будет скопироватьданные сначала, что-то вроде:

char myString* = new char[name.size() + 1];
strcpy(myString, name.c_str());

РЕДАКТИРОВАТЬ: благодаря полезным комментариям @ RemyLebeau

Лучше по-прежнему избегать всех проблем управления памятью с помощью вышеупомянутого, просто справившись с std::stringв std::vector:

std::vector<char> myVec(std::begin(name), std::end(name));
myVec.push_back(`\0`);

, а затем вызовите функцию char* с помощью:

functoupper(myVec.data());
...