Пример обратной строки Head First C - PullRequest
0 голосов
/ 19 февраля 2019

Я проходил 'Head First C' и нашел упражнение для создания метода реверсирования строк.

Это было мое решение:

void reverse_string(char s[]) {
    for (int i = strlen(s) - 1; i > -1; i--) {
       printf("%c", s[i]);
   }
}

И это было решение откнига:

void reverse_string(char *s) {
    size_t len = strlen(s);
    char *t = s + len - 1;

    while (t >= s) {
     printf("%c", *t);
     t = t - 1;
    }

    puts("");
}

Я понимаю решение из книги, но мое выглядит чище.Является ли более позднее решение предпочтительным, и если да, то почему?

Ответы [ 3 ]

0 голосов
/ 19 февраля 2019

Подводя итог сделанным комментариям:

Во-первых, имя функции reverse_string() вводит в заблуждение, поскольку оно не переворачивает строку, а только печатает ее в обратном порядке.

Функцияследует взять указатель на const char, а не указатель на char.Некоторые также могут утверждать, что использование [] в списке параметров несколько вводит в заблуждение, поскольку это может заставить людей, не очень знакомых с C, поверить, что массив передается вместо указателя на его первый элемент.

Обе функциииспользуйте printf() для печати одного символа.Это включает в себя ненужную работу синтаксического анализа строки формата только для вывода по одному символу за раз.Вместо этого используйте ´putchar () or fputc () `.

Функциональное различие между двумя функциями: ваша версия не печатает символ новой строки после обратной строки.Версия из книги делает это, но, подобно использованию printf() для одного символа, она делает это скрытно, используя puts("") вместо putchar('\n').

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

Ваша версия использует int eger для хранения результата strlen(), который имеет тип size_t.Возможно, что int eger переполнится для очень длинных строк.

Два возможных решения:

#include <string.h>  // strlen()
#include <stdio.h>   // putchar()

void print_reverse(char const *str)
{
    for (char const *p = str + strlen(str); p != str; putchar(*--p)); 
    putchar('\n');
}

или использование индекса:

#include <string.h>  // strlen()
#include <stdio.h>   // putchar()

void print_reverse(char const *str)
{
    for (size_t i = strlen(str); i; putchar(str[--i])); 
    putchar('\n');
}
0 голосов
/ 19 февраля 2019

Решение из книги имеет неопределенное поведение, потому что оно уменьшает t после начала строки.Сравнение t, указывающего вне массива, и s имеет неопределенное поведение.Это не сработает на архитектурах с сегментированными указателями, где >= проверяет только смещенную часть указателя.По той же причине произойдет сбой пустой строки.

Переносимое решение с указателями будет выглядеть так:

void reverse_string(const char *s) {
    const char *t = s + strlen(s);

    while (t > s) {
        t--;
        putchar(*t);
    }
    putchar('\n');
}

Ваша версия использует индекс, который в порядке, ноимеет небольшую проблему: он не обрабатывает строки длиннее INT_MAX.Длина строки имеет тип size_t, который может быть больше, чем int, даже на архитектурах, где int и size_t имеют одинаковый размер, а size_t без знака может иметь значения больше INT_MAX.

Изменение типа i недостаточно, потому что вы полагаетесь на i, становящимся отрицательным.Вот элегантный способ проверки перед уменьшением индекса:

void reverse_string(char s[]) {
    for (size_t i = strlen(s); i-- > 0;) {
        putchar(s[i]);
    }
    putchar('\n');
}

Некоторые шутливые программисты пишут это сравнение i --> 0 и вызывают --> оператор downto ... Этошутка, выражение анализируется как i -- > 0, пробелы не имеют значения.

0 голосов
/ 19 февраля 2019

Прежде всего, ни одно из решений не переворачивает строку.Они печатают его в обратном порядке, но это не то же самое, что реверсирование.

Ваше решение выглядит лучше и лаконично без потери читабельности, что хорошо.

Я бы не сказал, что решение откнига предпочтительнее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...