C - выключен одной ошибкой - PullRequest
1 голос
/ 18 апреля 2011

в следующей простой функции реверса я всегда выключен на единицу, то есть первый передаваемый символ никогда не печатается последним, как должно быть:

  void reverse(char * c)
{
    if(*c != '\0')
    {
        reverse(++c);
        printf("%c", *c);
    }
    else {
        return;
    }
}

пока я меняю вызов на обратныйбыть с + 1, все работает отлично.Любые идеи относительно того, почему унарный оператор предварительного инкремента должен работать точно так же, как и c + 1. Я знаю, что рекурсивная функция - не самый эффективный способ решения этой проблемы, но сейчас я просто экспериментирую.Спасибо!

Ответы [ 6 ]

7 голосов
/ 18 апреля 2011

Потому что c+1 делает не меняет c, тогда как ++c делает.

Подумайте об этом, когда c указывает на адрес 1234:

reverse(++c);      // c is now 1235 and you pass that.
printf("%c", *c);  // so we print the second character at 1235.

С версией c+1:

reverse(c+1);      // c is still 1234 but you pass 1235.
printf("%c", *c);  // so we print the first character at 1234.

Для чего бы то ни было, ваша функция reverse неоправданно сложна. else return избыточнаи я лично предпочитаю рекурсивные вызовы, которые сначала проверяют условия завершения, так как я часто обнаруживал, что компиляторам обычно проще выполнять хвостовую оптимизацию рекурсии.

Следующая полная тестовая программа показывает, как ясделайте это:

#include <stdio.h>

void reverse (char *c) {
    if (*c == '\0') return;
    reverse (c + 1);
    putchar (*c);
}

int main (int argc, char *argv[]) {
    int i;
    for (i = 1; i < argc; i++) {
        reverse (argv[i]);
        putchar ('\n');
    }
    return 0;
}

Запуск этого с testprog hello goodbye даст вам:

olleh
eybdoog
4 голосов
/ 18 апреля 2011

Нет, одинарное предварительное приращение - не то же самое, что сложение на единицу.

f(++c) эквивалентно

c = c + 1
f(c);

, тогда как f(c+1) эквивалентно

auto d = c + 1;
f(d);

И просто для полноты: f(c++) такой же, как

f(c);
c = c+1;

Однако точки последовательности имеют значение, например, if(c++ > 0 && c++ < 10) будет оцениваться как

auto a = c;
c = c + 1;

auto b = c;
c = c + 1;

if(a > 0 || b < 10) { /* ... */ }

и, следовательно, преинкремент

c = c + 1;
auto a = c;

c = c + 1;
auto b = c;

if(a > 0 || b < 10) { /* ... */ }
3 голосов
/ 18 апреля 2011

Вызов с c + 1 не изменит значение c в локальном контексте (то, которое использовалось при печати *c), но использование ++c в вызове приведет к *

0 голосов
/ 18 апреля 2011

когда вы вводите c+1, оно не меняет значение c, но ++c меняет значение c .. как пример для разницы между операторами до и после приращения:

int a = 1; 
int b = ++a; 
// Now a is 2 and b is also 2. 

int a = 1; 
int b = a++; 
// Now a is 2 but b is 1.
0 голосов
/ 18 апреля 2011

Нет, он не делает то же самое.

Он увеличивает его, а затем отправляет его в вашу функцию.

0 голосов
/ 18 апреля 2011

ИСПРАВЛЕНО : Вы не должны использовать оператор приращения.Оператор + будет лучше.:

reverse(c + 1);
printf("%c", *c);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...