Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > не правильный тип возвращаемого значения функции


Автор: n199a 27.1.2014, 04:13
При компиляции вылазит:
error: expected primary-expression before '=' token
error: 's' was not declared in this scope
warning: deprecated conversion from string constant to 'char*'


Но если obr и showword сделать отдельно, то всё нормально компилируется.
Ошибка кроется в типах возвращаемых значений для функций...


Код

void showword(char *s, char *divider){
    char* word;
    if(s = strtok(s, divider)){
        //дублирование строки
        word = strdup(s);
        showword('\0', divider);
        cout << word << " ";
        free(word);    //освобождаем память
    }
}

void obr() {
    char s[N];
    gets(s);
    
   // Переменная, в которую будет помещен указатель на дубликат строки
   char *istr;
   // Дублирование строки
   istr = strdup(s);
   
   showword(istr, " ");
   cout << endl;
}

int main(void) {
   obr();

return 0;
}

Автор: 586 27.1.2014, 06:38
Первых двух ошибок в коде нет.
Третью ошибку (точнее не ошибку, а warning) можно убрать, объявив функцию так:
void showword(char *s, const char *divider){

Еще компилятор может выдавать предупреждение на строчку №3. Исправить можно так:
if((s = strtok(s, divider))!=NULL){

Строчка №6 несовсем корректно написана, замени «'\0'» либо на «NULL» либо на «0».
showword(NULL, divider);

В функции obr не хватает вызова функции free.

Автор: n199a 27.1.2014, 11:26
Цитата(586 @  27.1.2014,  06:38 Найти цитируемый пост)
Первых двух ошибок в коде нет.

Вот, глянь, весь код:
Код

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE str.length()-1    //length() - возвращает длину строки
#define N = 255
using namespace std;
/*---------(1)---------*/
void perevod() { 
    char word;
    
    cout << "Enter word: ";
    cin >> word;
                
    word = toupper(word);
        
    cout << "Big word: " << word << endl;

};
/*---------(2)---------*/
int pks(const char *s, char c){
    int n = 0;
    while(*s != '\0'){
        if(*s==c) ++n;
            ++s;
     }
     return n;
}

int kol(void) {
    int all;
    char *s, c;
    cout << "Enter string: ";
    cin >> s;
    cout << "Search: ";
    cin >> c;
    all = pks(s, c);
    cout << "Result: " << all << endl;
    return 0;
}
/*---------(3)---------*/
void showword(char *s, char *divider){
    char* word;
    if(s = strtok(s, divider)){
        //дублирование строки
        word = strdup(s);
        showword('\0', divider);
        cout << word << " ";
        free(word);    //освобождаем память
    }
}

void obr() {
    char s[N];
    gets(s);
    
   // Переменная, в которую будет помещен указатель на дубликат строки
   char* istr;
   // Дублирование строки
   istr = strdup(s);
   
   showword(istr, " ");
   cout << endl;
}
/*-------------------*/
int main(void){
    int key;
    
    cout << "Menu:" << endl
         << "1. Перевести все символы введенной строки в верхний регистр" << endl
         << "2. Подсчитать количество вхождений символа в строку" << endl
         << "3. Переставить слова предложения в обратном порядке" << endl
         << "4. Exit" << endl;
    
    label:
    cout << "Press the key: ";
    cin >> key;
    
    switch(key) {
        case 1: perevod();    goto label;
        case 2:    kol();        goto label;
        case 3: obr();        goto label;
        case 4:                break;
    }
        
    return 0;
}



Автор: xvr 27.1.2014, 12:20
Ошибка тут -
Код

#define N = 255
тут явно что то лишнее  smile 

А вообще код ужасен - дикая помесь С и С++, и goto в придачу  smile 

Автор: n199a 27.1.2014, 12:25
Цитата(xvr @  27.1.2014,  12:20 Найти цитируемый пост)
А вообще код ужасен - дикая помесь С и С++, и goto в придачу 

Ну да. Дают материал на Си, а я С++ читаю. Вот приходится смешивать, брать кусками, что знаю smile
С текстом материал просто не внимательно читал, пришлось в просторах интернета искать решение.
А чего goto так недолюбливают?  smile 

Код действительно плох, ещё в придачу вылазит:
Код

program too big to fit in memory


Почему #define лишний? Без его нормально скомпилировалось....

P.S. Читаю Хенкеманс, Ли - Программирование на С++, может стоит другое почитать?

Добавлено через 5 минут и 35 секунд
Цитата(xvr @  27.1.2014,  12:20 Найти цитируемый пост)
А вообще код ужасен - дикая помесь С и С++, и goto в придачу 

Что посоветуешь изменить? Не оставлять же его в таком виде  smile 

Автор: xvr 27.1.2014, 12:47
Цитата(n199a @  27.1.2014,  12:25 Найти цитируемый пост)
Почему #define лишний? Без его нормально скомпилировалось....

Лишний не он, а знак '=' в нем  smile 

Цитата(n199a @  27.1.2014,  12:25 Найти цитируемый пост)
А чего goto так недолюбливают?

А того, что его надо использовать только там, где без него никак не обойтись. В данном случае классический цикл (for(;;) ) и без goto точно обойтись можно


Цитата(n199a @  27.1.2014,  12:25 Найти цитируемый пост)
Что посоветуешь изменить?

Ну либо С либо С++. И уж точно не std::cout и malloc/free/strdup вместе!

А рекурсивный showword по заданию требовался? Такой метод разбиения на слова не самый лучший, мягко говоря  smile 

Автор: n199a 27.1.2014, 14:11
Цитата(xvr @  27.1.2014,  12:47 Найти цитируемый пост)
А рекурсивный showword по заданию требовался? Такой метод разбиения на слова не самый лучший, мягко говоря

Нет, не надо была рекурсия. Это просто был самый понятный для меня способ из найденных. Вот я его и взял.
Какой есть по-проще ?

Автор: n199a 27.1.2014, 15:00
Вот написал новый. Почему, когда нажимаю 3, то сразу выскакивает "Press the key ", без предложения ввода строки "Enter stroku: " ?
Код

int obr(void)
{
    int nmb = 0;
    char str[80], *words[nmb];
    const char sim[] = " ";

    cout << "Enter stroku: ";
    gets(str);
    
    words[nmb] = strtok(str, sim);
    
    while(words[nmb] != NULL) {
        nmb ++;
        words[nW] = strtok(NULL, sim);
    }
    
    for(int i = nmb; i >= 0; i--)
        puts(words[i]);
    
    return 0;
}

Автор: xvr 27.1.2014, 17:21
Цитата(n199a @  27.1.2014,  15:00 Найти цитируемый пост)
Вот написал новый.

Можно еще проще:
Код

int obr(void)
{
    int nmb = 0;
    char str[80], *words[nmb];

    cout << "Enter stroku: " << flush;
    cin.getline(str,sizeof(str));
    
    for(char* p=strtok(str," ");p;p=strtok(NULL," "))
     words[nmb++]=p;

    for(int i = nmb-1; i >= 0; i--)
        cout << words[i] << " ";
    cout << endl;
    
    return 0;
}

Цитата(n199a @  27.1.2014,  15:00 Найти цитируемый пост)
Почему, когда нажимаю 3, то сразу выскакивает "Press the key "

Нельзя смешивать ввод вывод через потоки С++ и С FILE на одном и том же файле (в вашем случае на STDIN/STDOUT)

Кстати, вашу функцию можно сделать и рекурсивной - тогда массив на слова не понадобится (но и strdup вкупе с free тоже не нужен)

Код

void real_obr(char* buf)
{
 if (char* p=strtok(buf," "))
  {
   real_obr(NULL);
   cout << p << " ";
  }
}

int obr(void)
{
    char str[80];

    cout << "Enter stroku: " << flush;
    cin.getline(str,sizeof(str));
    
    real_obr(str);
    cout << endl;
    
    return 0;
}

Собственно очень похоже на ваш первоначальный вариант, но без лишних манипуляций с динамической памятью. 
PS. Я просмотрел, что вам надо было развернуть слова в обратном порядке - тут рекурсивная версия выглядит вполне ничего  smile 

Автор: trinitr0 27.1.2014, 17:38
Цитата

А чего goto так недолюбливают? 


Потому что:

1. Нарушает парадигму структурного программирования (последовательность выполнения)
2. Препятствует оптимизации компиляторами управляющих структур
3. Может нарушать логику программ
4. Может приводит к деградации производительсности (из-за сброса и переинициализации конвейров CPU)
5. Непредсказумое значение иницилизированных переменных до их применения
6. Пропуск инициализации при входе в цикл
7. Пропуск пролога при выходе из функции

Ещё в далёком 1968г Эдсгер Дейкстра написал
http://khpi-iip.mipk.kharkiv.edu/library/extent/dijkstra/pp/ewd215.html

Автор: n199a 27.1.2014, 18:26
Цитата(xvr @  27.1.2014,  17:21 Найти цитируемый пост)
Кстати, вашу функцию можно сделать и рекурсивной - тогда массив на слова не понадобится (но и strdup вкупе с free тоже не нужен)

Использовал вашу функцию, всё равно сразу вылазил Press the key ...

Добавлено через 1 минуту и 28 секунд
Цитата(xvr @  27.1.2014,  17:21 Найти цитируемый пост)
Можно еще проще:


Цитата(xvr @  27.1.2014,  17:21 Найти цитируемый пост)
flush;


Цитата(xvr @  27.1.2014,  17:21 Найти цитируемый пост)
;p;p=


Я ещё такого не изучал.

Автор: xvr 27.1.2014, 21:32
Цитата(n199a @  27.1.2014,  18:26 Найти цитируемый пост)
Использовал вашу функцию, всё равно сразу вылазил Press the key ...

Enter stroku: даже не выводит? Или все же выводит, но строку не вводит? Если второе, то это правильно - предыдущий cin >> key прочел число, а вот перевод строки в буфере остался, вот он пустую строку и вводит

Автор: n199a 27.1.2014, 23:37
Цитата(xvr @  27.1.2014,  21:32 Найти цитируемый пост)
Enter stroku: даже не выводит? Или все же выводит, но строку не вводит? Если второе, то это правильно - предыдущий cin >> key прочел число, а вот перевод строки в буфере остался, вот он пустую строку и вводит

Enter stroku выводит.
А что тогда делать с буфером?

Автор: akizelokro 28.1.2014, 00:25
Чё это у вас?

Код

#define SIZE str.length()-1    //length() - возвращает длину строки

при столкновении с ARRAYSIZE приводит к забавным эффектам (фикх отыщещь). например. Да и -1 может возвратить
Код

void showword(char *s, char *divider){
    char* word;
    if(s = strtok(s, divider)){


никто так не пишет. можно

Код

if(word = strtok(s, divider) )

а предыдущий вариант может относиться только к трюкам, либо к непредсказуемым последствиям и противоречит логике функции 'strtok'. Не говоря уже, что лучше s получить в стеке в порядке разбора аргументов функции showword и оставить временно в покое.
Потом же у функции showword идёт рекурсивный вызов.

Код

   istr = strdup(s);
   
   showword(istr, " ");

здесь рисуется memory leak. Неделю пил, но strdup, походу, программер должен подчищать самостоятельно. Так что istr переобозначать не надо. "Шоб було" и "этапы большого пути".

Автор: xvr 28.1.2014, 08:36
Цитата(n199a @  27.1.2014,  23:37 Найти цитируемый пост)
А что тогда делать с буфером?

Очищать. cin.ignore(1000,'\n')

Автор: n199a 28.1.2014, 09:13
Цитата(xvr @  28.1.2014,  08:36 Найти цитируемый пост)
Очищать. cin.ignore(1000,'\n')

Не работал просто с таким. И по этому возникает сопутствующий вопрос - в какое место в коде вставлять?

Автор: xvr 28.1.2014, 12:25
Цитата(n199a @  28.1.2014,  09:13 Найти цитируемый пост)
в какое место в коде вставлять? 

Перед  cin.getline()

Автор: n199a 28.1.2014, 12:29
Цитата(xvr @  28.1.2014,  12:25 Найти цитируемый пост)
Перед  cin.getline()

Нету такого в коде.

Автор: xvr 28.1.2014, 12:30
Цитата(n199a @  28.1.2014,  12:29 Найти цитируемый пост)
Нету такого в коде. 

У меня в примере есть. У вас стоит gets() - это работать нормально не будет

Автор: n199a 28.1.2014, 12:46
Сделал так, но теперь не меняет местами:
Код

int obr(void)
{
    int nW = 0;
    char str[80], *words[100] = {NULL};
    const char sim[] = ".,/";

    cout << "Vvedite stroku: ";
    cin.ignore(1000,'\n');
    cin.getline(str, 80);
    
    words[nW] = strtok(str, sim);
    
    while(words[nW] != NULL) {
        nW ++;
        words[nW] = strtok(NULL, sim);
    }
    
    for(int i = nW; i >= 0; i--)
        puts(words[i]);
        
    return 0;
}

Автор: akizelokro 29.1.2014, 00:38
int obr()
{
  cout << "Vvedite stroku: ";
  string s;
  cin >> s;
  char * word = s.data();
  vector <char *> for_reverse; 
  const char delimiter[] = ".,";  // не попадёт /n
  while(word = strtok(word, delimiter)
  {
     for_reverse.push_back(word);
  }
  for(auto  rit = for_reverse.rbegin(); rit!= for_reverse.rend(); ++rit)
    cout >> *rit  >> " ";
  cout >> endl;
}

// звязывайте уже с этим
// первоначально шёл и такой коад как 
// char * s;
// cin >> s. но код был реально плох.

Автор: n199a 29.1.2014, 00:45
Цитата(akizelokro @  29.1.2014,  00:38 Найти цитируемый пост)
int obr()
{
  cout << "Vvedite stroku: ";
  string s;
  cin >> s;
  char * word = s.data();
  vector <char *> for_reverse; 
  const char delimiter[] = ".,";  // не попадёт /n
  while(word = strtok(word, delimiter)
  {
     for_reverse.push_back(word);
  }
  for(auto  rit = for_reverse.rbegin(); rit!= for_reverse.rend(); ++rit)
    cout >> *rit  >> " ";
  cout >> endl;
}

А без векторов обойтись можно?

Автор: akizelokro 29.1.2014, 00:45
ах, да, 
сin >> ругается на два char* подряд.

Добавлено @ 00:59
можно. используя вообще Сшниый стиль.

const char delimiter[] = ".,";
puts("Taschi stroku:");
char * str = gets();

char * pointers = calloc((strlen(str) + 1) * sizeof(char *)); // а, лень free делать. и sizeof надо по трезвяни вспомнить
char * word = str;
int i = 0;
while(word = strtok(word, delimiter))
{
    (pointers + i * sizeof(char *)) = word;
    i++;
}
for(int q = (strlen(pointers)/sizeof(char *)); q > 0; q--)
{
    printf("%s ", pointers + (q - 1) * sizeof(char *));
//  puts(pointers + (q - 1) * sizeof(char *));
//  puts(" ");
}

Пару раз откомпильнуть, а так пример кажисть работоспособный.
Мне тут понравилось самому как я у указателей стал длину строки брать  smile 

Автор: akizelokro 29.1.2014, 01:11
Ну, тут малость намутил, но после пары компиляций (и правки ошибок) работать должно.  smile 

Автор: xvr 29.1.2014, 10:33
Цитата(n199a @  28.1.2014,  12:46 Найти цитируемый пост)
Сделал так, но теперь не меняет местами:

Потому что у вас теперь разделитель не пробел, а набор запятых (строка 5 в листинге). Так что у вас получается ровно 1 слово (во всю строку). И менять местами просто нечего.

Автор: n199a 29.1.2014, 14:37
Цитата(xvr @  29.1.2014,  10:33 Найти цитируемый пост)
Потому что у вас теперь разделитель не пробел, а набор запятых (строка 5 в листинге). Так что у вас получается ровно 1 слово (во всю строку). И менять местами просто нечего.

Точно, забыл, что менял на запятую, точку и слэш  smile 
Благодарю всех за участие  smile 

Автор: akizelokro 31.1.2014, 02:00
разоврался с пойнтерами, ещё вчера хотел заметить.
но пример работосопсобный, и ненамного длиньше, чем с С++

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)