Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 11.10.2018, 13:55   #21
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,695
По умолчанию

Цитата:
Сообщение от Sinli Посмотреть сообщение
Когда мы пишем функцию, которая принимает и/или возвращает указатель, то мы всегда должны предусматривать вариант, когда она получает/возвращает нулевой указатель?
В общем случае - да. А так зависит от контракта функции. Возможно, ваша функция всегда будет вызываться для валидного указателя, тогда имеет смысл оставить проверку в ассерте для дебага.
p51x вне форума Ответить с цитированием
Старый 11.10.2018, 14:46   #22
Sinli
Пользователь
 
Регистрация: 10.09.2018
Сообщений: 43
По умолчанию

Большое спасибо.
Sinli вне форума Ответить с цитированием
Старый 11.10.2018, 15:20   #23
Sinli
Пользователь
 
Регистрация: 10.09.2018
Сообщений: 43
По умолчанию

Извините, можете еще с одним кодом помочь. Я думал, что понимание проблем в предыдущем коде мне помогут исправить этот, но оказалось, это не так.

В упражнении сказано, написать функцию, которая заменяет содержимое указанной строки этой же строкой, но в обратном порядке. Функцию, то я написал, но почему-то она при работе с другими функциями выдает разные результаты.

Код:
#include <stdio.h>
#include <string.h>
char * reverse_order(char * st);
char * s_gets(char * st, int n);
int main(void)
{
        char string[81];
        char *string1;
        puts("Введите строку:");
        s_gets(string, 80);
        printf("Ваша строка: %s - имеет %zd символов.\n", string, strlen(string));
        string1 = reverse_order(string);
        if (string1)
        {
                printf("Кручу, верчу, запутать хочу: %s\n", string1);
                puts("Спасибо за внимание");
        }
        else
                printf("Программа завершена\n");
        return 0;
}
char * reverse_order(char * st)
{
        int n, k;
        char * reverse;
        if (st && st[0] != '\0' && st[0] != '\n')
        {
                n = strlen(st);
                k = n - 1;
                for (int i = 0; i < n; i++)
                {
                        reverse[i] = st[k];
                        k--;
                }
                reverse[n] = '\0';
        }
        else
                reverse = NULL;
        return reverse;
}
char * s_gets(char * st, int n)
{
        char * ret_val;
        int i = 0;
        ret_val = fgets(st, n, stdin);
        if (ret_val)
        {
                while(st[i] != '\n' && st[i] != '\0')
                        i++;
                if(st[i] == '\n')
                        st[i] = '\0';
                else
                        while (getchar() != '\n')
                                continue;
        }
        return ret_val;
}
например, вот такой вывод получается при запуске:
Скриншот 2018-10-11 14_57_24.png

Но, например, если я использую вместо s_gets() стандартную библиотечную функцию fgets(), то вывод такой:

Скриншот 2018-10-11 15_00_13.png

Почему при использовании этих почти одинаковых функций, получаются такие разные результаты?
При использовании fgets() строка идет в обратном порядке, но выдает ошибку сегментации. Опытным путем я выяснил, что эта ошибка выпадает, когда символов больше шести.

Еще больше вводит меня в растерянность, когда я вместо того, чтобы получать строку из ввода, я ее просто объявил: char string[81] = "kamboocha". и мне выдало:

Скриншот 2018-10-11 15_06_45.png

P.S. s_gets я не сам смастерил, она взята из книги. по идее должна работать правильно.
Sinli вне форума Ответить с цитированием
Старый 11.10.2018, 15:32   #24
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,695
По умолчанию

Код:
char * reverse;
Память кто выделяет?

Код:
                n = strlen(st);
                k = n - 1;
Почему вы переворачивает с предпоследнего символа?

Код:
for (int i = 0; i < n; i++)
Вы уверены, что надо всю строку пробегать?
p51x вне форума Ответить с цитированием
Старый 11.10.2018, 16:09   #25
Sinli
Пользователь
 
Регистрация: 10.09.2018
Сообщений: 43
По умолчанию

Т.е. все проблемы были из-за того, что я не выделил память для массива обратной строки?
Код:
char * reverse_order(char * st)
{
        int n, k;
        char rev[81];
        char *reverse = rev;
        if (st && st[0] != '\0' && st[0] != '\n')
        {
                n = strlen(st);
                k = n - 1;
                for (int i = 0; i < n; i++)
                {
                        rev[i] = st[k];
                        k--;
                }
                rev[n] = '\0';
        }
        else
                reverse = NULL;
        return reverse;
}
Теперь все описанные выше варианты работают!
Вложение 94429

Цитата:
Сообщение от p51x Посмотреть сообщение
Почему вы переворачивает с предпоследнего символа?
Потому что strlen() считает количество символов в строке без нулевого символа, а элементы массива начинаются считаться с нуля, если я начну заносить символы в массив rev начиная с st[n], то rev[0] получит '\0' и строка при выводе закончится на этом нулевом символе.
Вывод будет таким:
Вложение 94430

Цитата:
Сообщение от p51x Посмотреть сообщение
Вы уверены, что надо всю строку пробегать?
Уверен, хотя несколько менее уверен после вашего вопроса.

По-моему, после выделения памяти под массив программа заработала как следует.
Sinli вне форума Ответить с цитированием
Старый 11.10.2018, 16:15   #26
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,695
По умолчанию

Цитата:
Сообщение от Sinli Посмотреть сообщение
Теперь все описанные выше варианты работают!
Везет, но так делать не надо. Не стоит возвращать указатель на локальные переменные.

Цитата:
Сообщение от Sinli Посмотреть сообщение
Уверен, хотя несколько менее уверен после вашего вопроса.
Тьфу. У меня просто в голове был стандартный алгоритм разворота через обмен соответствующих элементов. Там только до половины. )
p51x вне форума Ответить с цитированием
Старый 11.10.2018, 16:28   #27
Sinli
Пользователь
 
Регистрация: 10.09.2018
Сообщений: 43
По умолчанию

Т.е. мне лучше объявить массив в main() и передать в reverse_order() не один, а два массива?
Код:
char * reverse_order(char * st, char * st2);
char * s_gets(char * st, int n);
int main(void)
{
        char string[81];
        char reverse[81];
        char *string1;
        puts("Введите строку:");
        s_gets(string, 80);
        printf("Ваша строка: %s - имеет %zd символов.\n", string, strlen(string));
        string1 = reverse_order(string, reverse);
        if (string1)
        {
                printf("Кручу, верчу, запутать хочу: %s\n", string1);
                puts("Спасибо за внимание");
        }
        else
                printf("Программа завершена\n");
        return 0;
}
char * reverse_order(char * st, char * st2)
{
        int n, k;
        if (st && st[0] != '\0' && st[0] != '\n')
        {
                n = strlen(st);
                k = n - 1;
                for (int i = 0; i < n; i++)
                {
                        st2[i] = st[k];
                        k--;
                }
                st2[n] = '\0';
        }
        else
                st2 = NULL;
        return st2;
}
Это тоже сработало, проверил уже.
Sinli вне форума Ответить с цитированием
Старый 11.10.2018, 16:31   #28
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,695
По умолчанию

Остался один шаг - сделать по условию:
Цитата:
Сообщение от Sinli Посмотреть сообщение
заменяет содержимое указанной строки этой же строкой, но в обратном порядке
т.е. сделать замену на месте.)
p51x вне форума Ответить с цитированием
Старый 11.10.2018, 17:12   #29
Sinli
Пользователь
 
Регистрация: 10.09.2018
Сообщений: 43
По умолчанию

Скриншот 2018-10-11 16_53_29.png

не, я, конечно, могу сделать так:

Код:
char * reverse_order(char * st, char * st2);
char * s_gets(char * st, int n);
int main(void)
{
        char string[81];
        char reverse[81];
        puts("Введите строку:");
        s_gets(string, 80);
        printf("Ваша строка: %s - имеет %zd символов.\n", string, strlen(string));
        reverse_order(string, reverse);
        if (string[0] != '\0')
        {
                printf("Кручу, верчу, запутать хочу: %s\n", string);
                puts("Спасибо за внимание");
        }
        else
                printf("Программа завершена\n");
        return 0;
}
char * reverse_order(char * st, char * st2)
{
        int n, k;
        if (st && st[0] != '\0' && st[0] != '\n')
        {
                n = strlen(st);
                k = n - 1;
                for (int i = 0; i < n; i++)
                {
                        st2[i] = st[k];
                        k--;
                }
                st2[n] = '\0';
        }
        else
                st2 = NULL;
        for (int i = 0; i <= n; i++)
                st[i] = st2[i];
        return st;
}
Но тогда, пожалуй, лучше будет переменную reverse запрятать обратно в reverse_order() и сделать ее принимающей один указатель, чтобы лишние переменные не мозолили глаза в main()? Все равно она будет возвращать указатель, который принимает. К тому же, если на то пошло, то reverse_order можно вообще сделать возвращающей void.)
Sinli вне форума Ответить с цитированием
Старый 11.10.2018, 17:33   #30
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,695
По умолчанию

Цитата:
Сообщение от Sinli Посмотреть сообщение
не, я, конечно, могу сделать так
Не так. Вот у вас есть строка 1 2 3 4 5 6 и вам надо ее развернуть. Что делать? Взять и поменять местами 1 с 6, ...

Цитата:
Сообщение от Sinli Посмотреть сообщение
Но тогда, пожалуй, лучше будет переменную reverse запрятать обратно в reverse_order() и сделать ее принимающей один указатель, чтобы лишние переменные не мозолили глаза в main()?
Она вообще не нужна, меняйте на месте.

Цитата:
Сообщение от Sinli Посмотреть сообщение
К тому же, если на то пошло, то reverse_order можно вообще сделать возвращающей void.)
Можно.
p51x вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Помогите разобраться с указателями. Sinli Общие вопросы C/C++ 2 04.10.2018 22:47
Помогите пожалуйста разобраться с указателями? седьмой Общие вопросы C/C++ 20 18.04.2017 07:26
помогите разобраться с указателями С++ sasha_14-88 Общие вопросы C/C++ 1 07.12.2014 10:39
Помогите разобраться с указателями igole Общие вопросы C/C++ 1 28.04.2013 16:47
Товарищи, помогите разобраться с указателями scibern Общие вопросы C/C++ 7 11.01.2009 12:28