Передача параметра в Си++

Тема в разделе "LANGS.C", создана пользователем REASY, 14 апр 2008.

  1. REASY

    REASY New Member

    Публикаций:
    0
    Регистрация:
    24 дек 2007
    Сообщения:
    108
    Здравствуйте.
    У меня такая проблема, я хочу передать в функцию параметр const char **, но компилятор выдает ошибку, на Си это проходит без проблем, а на Си++ пишет "cannot conver parametr 1 from 'char **' to 'const char **'. В чем проблема, что я делаю не так ?

    Вот исходник:

    #include <iostream>
    using namespace std;

    int sumoflen(const char **words, const int N);

    int main(int argc, char **argv)
    {
    const int size = 256;

    int N;
    int i = 0;
    cin >> N;
    cin.get();

    char **mywords = new char*[N];

    for (i = 0; i < N;i++)
    mywords = new char[size-1];

    while(i < N)
    cin.getline(mywords[i++],size - 1);

    cout << sumoflen(mywords, N) << endl;

    return 0;
    }

    int sumoflen(const char **words,const int N)
    {
    int i;
    int sum = 0;
    for (i = 0; i < N; i++ )
    sum += strlen(words);

    return sum;
    }
     
  2. censored

    censored New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2005
    Сообщения:
    1.615
    Адрес:
    деревня "Анонимные Прокси"
    Код (Text):
    1. #include <iostream>
    2. #include <string>
    3. #include <vector>
    4.  
    5. size_t sumoflen(const std::vector<std::string> & v) {
    6.   size_t retval = 0;
    7.   for (std::vector<std::string>::const_iterator it = v.begin(), end = v.end();
    8.        it < end; ++it) {
    9.     retval += (*it).size();
    10.   }
    11.   return retval;
    12. }
    13.  
    14. int main(int argc, char ** argv) {
    15.   enum { size = 256 };
    16.   size_t N;
    17.   std::cin >> N;
    18.   std::cin.get();
    19.   std::vector<std::string> v(N);
    20.   for (size_t i = 0; i < N; ++i) {
    21.     char array[size];
    22.     std::cin.getline(array, size - 1);
    23.     std::string s(array);
    24.     v.push_back(s);
    25.   }
    26.   std::cout << sumoflen(v);
    27. }
    28.  
    29. /* [EOF] */
    Ы? Ж)
     
  3. REASY

    REASY New Member

    Публикаций:
    0
    Регистрация:
    24 дек 2007
    Сообщения:
    108
    censored
    Ну интересная версия, тогда можно было передать и const string[], но меня интересует, можно ли именно const char ** :)
     
  4. Com[e]r

    Com[e]r Com[e]r

    Публикаций:
    0
    Регистрация:
    20 апр 2007
    Сообщения:
    2.624
    Адрес:
    ого..
    эээээхм.. а разве нейтрализация "const" не решаед? =\\
     
  5. censored

    censored New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2005
    Сообщения:
    1.615
    Адрес:
    деревня "Анонимные Прокси"
    REASY
    Код (Text):
    1. void foo(const char**) {}
    2. void main() { char a[1][1]; foo(reinterpret_cast<const char**>(&a[0][0])); }
     
  6. REASY

    REASY New Member

    Публикаций:
    0
    Регистрация:
    24 дек 2007
    Сообщения:
    108
    Comer_
    Что за "нейтрализация" ?
     
  7. REASY

    REASY New Member

    Публикаций:
    0
    Регистрация:
    24 дек 2007
    Сообщения:
    108
    censored
    После вызова sumoflen(reinterpret_cast<const char **>(&mywords[0][0]), N);
    получается так, что const char **words указывает на адреса, и если мы набрали допустим 12345, то i-тый элемент указывает на ячейку по адресу 0x34333231. Т.е. words[0] = значение по адресу 0x34333231.
     
  8. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    REASY
    Это разные типы. В случае char* => const char* возможно неявное преобразование (char => const char), а в случае char** => const char** это уже нельзя, т.к. типы разные.

    Нагляднее разница видна здесь:
    Код (Text):
    1. typedef char* LPSTR;
    2. typedef const char* LPCSTR;
    3.  
    4. void f(const LPCSTR*);
    5. void g(const LPSTR*);
    6.  
    7. void test()
    8. {
    9.   LPSTR pp = 0;
    10.   f(pp);  // cannot convert LPSTR* to LPCSTR*
    11.   g(pp); // ok
    12. }
     
  9. REASY

    REASY New Member

    Публикаций:
    0
    Регистрация:
    24 дек 2007
    Сообщения:
    108
    IceStudent
    Так как быть? Как передать фу-и массив слов, чтобы их нельзя было изменить ?
     
  10. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    const char не запрещает изменения. Компилер просто выдает варнинги при компиляции в отлад целях. По стандарту. Если реализовано. Если стоит нужный уровень варнингов. А в случае const char ** вы, скорей всего, и варнингов не увидите.
     
  11. probka

    probka New Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    170
    REASY, если ты перед переменной поставил const, то все, это значит, что переменная ВСЕГДА будет иметь тот параметр, который ты ей передал в момент объявления.
    Код (Text):
    1. const int size = 256;
    2. ...
    3. mywords[i] = new char[size-1];
    сдесь ты пытаешься изменить то, что не изменяемо. Раз ошибка. То же самое, как объявить:
    Код (Text):
    1. #define x 5
    x теперь всегда будет 5. И все попытки изменения, вызовут ошибку.

    Давай разберемся.
    1. Объявил функцию, которая принимает два параметра типа const: сhar и int.
    2. Вызываешь ее и передаешь ей в качестве параметров два значения, mywords и N.
    3. mywords - указатель на вновь создаваемый динамический тип (не const с позиции компилятора). Два ошибка.

    И что - то мне подсказывает, что есть еще ошибки, я не стал смотреть дальше.
     
  12. REASY

    REASY New Member

    Публикаций:
    0
    Регистрация:
    24 дек 2007
    Сообщения:
    108
    probka
    Код:
    const int size = 256;
    mywords = new char[size-1];
    Здесь я только выделяю память 255 байт для слова, причем тут "ы пытаешься изменить то, что не изменяемо", что то я не пойму.
    Я тут пошел по методу, когда передают фу-и const char *,но вместо этого я захотел передать фу-и массив слов(char **), но мне уже сказали, что "В случае char* => const char* возможно неявное преобразование (char => const char), а в случае char** => const char** это уже нельзя, т.к. типы разные".
     
  13. REASY

    REASY New Member

    Публикаций:
    0
    Регистрация:
    24 дек 2007
    Сообщения:
    108
    _basmp_
    Вот что пишет С. Прата в примечании к одной из программ:
    Код (Text):
    1. int c_in_str(const char *str, char ch)
    2. {
    3. int count = 0;
    4. whie(*str)
    5. {
    6. if (*str == ch)
    7. count ++;
    8. str++;
    9. }
    10. return count;
    11. }
    Поскольку фу-я c_in_str не должна вносить изменения в исходную строку, она использует спецификатор const при описании формального параметра str....
     
  14. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    _basmp_
    Именно запрещает, на уровне языка. Правда, это можно обойти приведением типа, но тогда кодер - сам себе злобный буратино, ибо данные могут быть в RO-памяти.

    C2166 в случае VC мало похож на предупреждение. Как и "error: expression must be a modifiable lvalue" в случае Comeau.
     
  15. probka

    probka New Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    170

    Ну ты же изменяешь значение НЕИЗМЕНЯЕМОЙ переменной " size-1 ":
    Код (Text):
    1. mywords[i] = new char[size-1]
    Как можно это делать, если явно, в самом начале, сказал компилятору: значение переменной size - постоянно " const int size = 256 ; ", ВСЕГДА!

    И зачем у тебя - ' ** '?
    Что, нельзя просто передать массив по ссылке - ' * '?
    Зачем понадобилась ссылка на ссылку?

    И еще, объявляешь массив динамически, и не говоришь, какой объем выделить.

    Интересная запись:
    Код (Text):
    1. char **mywords = new char*[N];
    Вот так правильнее:
    Код (Text):
    1. char *mywords = new char;
     
  16. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Нельзя приводить const к не const, обратное можно.
    Константность это свойство переменной. Компилятору пофиг будут или нет изменять неконстантную переменную, он просто не даёт присвоить неконстантной константную.
    Конечно константные могут быть оптимизированы, то есть заранее зашиты в секцию данных ReadOnly.
     
  17. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    probka
    Там выделяется N элементов типа "char*". А ты предлагаешь один элемент типа "char".
     
  18. diamond

    diamond New Member

    Публикаций:
    0
    Регистрация:
    21 май 2004
    Сообщения:
    507
    Адрес:
    Russia
    REASY
    Если вкратце - объяви функцию sumoflen следующим образом:
    Код (Text):
    1. int sumoflen(const char * const*words, const int N);
    Подробнее - http://www.parashift.com/c++-faq-lite/const-correctness.html
    probka
    Код корректен, строка "mywords = new char[size-1]" не изменяет size, ссылка на ссылку понадобилась потому, что mywords - это не одна строка, а массив строк, то есть массив массивов, запись "char **mywords = new char*[N];" в этом контексте абсолютно правильна.
     
  19. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    Возможно. Никогда не придавал этому большого значения. Просто привожу типы и все. кстати говоря const char ** это что:
    (const char) **
    (const (char *)) *
    const (char **)
    Заранее прошу прощения за свою тупость и безграмотность.

    Все это так. Но только на бумаге (см замечание от IceStudent).

    нет. такой гарантии нет. Те (const int i=5;) != (#define i 5).
     
  20. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    _basmp_
    Первое. Для последнего нужно писать либо "char** const", либо "typedef char** LPPSTR; const LPPSTR".