C-由一个错误关闭

C-由一个错误关闭,c,C,在以下简单的反转函数中,我总是以1为关,这意味着传入的第一个字符永远不会像应该的那样打印到最后: void reverse(char * c) { if(*c != '\0') { reverse(++c); printf("%c", *c); } else { return; } } 然而,当我将调用更改为reverse为c+1时,一切都正常。任何关于为什么的想法,一元预增量运算符应该与c+1完全相同

在以下简单的反转函数中,我总是以1为关,这意味着传入的第一个字符永远不会像应该的那样打印到最后:

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

然而,当我将调用更改为reverse为c+1时,一切都正常。任何关于为什么的想法,一元预增量运算符应该与c+1完全相同。我知道递归函数不是解决这个问题的最佳方法,但我现在只是在试验。谢谢

因为
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;
}

因为
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;
}

使用
c+1
调用不会更改本地上下文中
c
的值(打印
*c
时使用的值),但在调用中使用
++c
会更改
c+1
调用不会更改本地上下文中
c
的值(打印
*c
时使用的值),但是在调用中使用
++c
将是有效的。

修复了该问题:您不应该使用增量运算符。操作员+会更好

reverse(c + 1);
printf("%c", *c);

已修复:不应使用增量运算符。操作员+会更好

reverse(c + 1);
printf("%c", *c);

不,它不会做同样的事情


它将其递增,然后将其发送到您的函数

不,它不会做同样的事情


它将其递增,然后将其发送到您的函数

不,一元预增量与一元相加不同

f(++c)
相当于

c = c + 1
f(c);
auto d = c + 1;
f(d);
f(c+1)
相当于

c = c + 1
f(c);
auto d = c + 1;
f(d);
为了完整起见:
f(c++)

f(c);
c = c+1;
P>但是序列点是重要的,如<代码>(C++ > 0和C+++< 10)< /> >将像

一样评价。
auto a = c;
c = c + 1;

auto b = c;
c = c + 1;

if(a > 0 || b < 10) { /* ... */ }
自动a=c;
c=c+1;
自动b=c;
c=c+1;
如果(a>0 | | b<10){/*…*/}
并因此预增量

c = c + 1;
auto a = c;

c = c + 1;
auto b = c;

if(a > 0 || b < 10) { /* ... */ }
c=c+1;
自动a=c;
c=c+1;
自动b=c;
如果(a>0 | | b<10){/*…*/}

否一元预增量与一元相加不同

f(++c)
相当于

c = c + 1
f(c);
auto d = c + 1;
f(d);
f(c+1)
相当于

c = c + 1
f(c);
auto d = c + 1;
f(d);
为了完整起见:
f(c++)

f(c);
c = c+1;
P>但是序列点是重要的,如<代码>(C++ > 0和C+++< 10)< /> >将像

一样评价。
auto a = c;
c = c + 1;

auto b = c;
c = c + 1;

if(a > 0 || b < 10) { /* ... */ }
自动a=c;
c=c+1;
自动b=c;
c=c+1;
如果(a>0 | | b<10){/*…*/}
并因此预增量

c = c + 1;
auto a = c;

c = c + 1;
auto b = c;

if(a > 0 || b < 10) { /* ... */ }
c=c+1;
自动a=c;
c=c+1;
自动b=c;
如果(a>0 | | b<10){/*…*/}

当您放置
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.

当您放置
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.

我想是这样的,但接下来可以论证的就是按原始顺序打印字符串。这会使它反转的原因是,它到达末尾,然后从每个函数返回,并在运行过程中打印出来。我认为,但可以说,这样做的全部工作就是按原始顺序打印字符串。这将使其反转的原因是,它到达末尾,然后从每个函数打印出来返回。使用
char
而不是
auto
,将其从伪C转换为C。顺便说一下
f(C++,C++)
是未定义的行为,用于在没有序列点的情况下修改
C
两次,
auto a=c
int a=c
相同,而与
c
的类型无关。Yay implicit int.@Zack:我知道这一点,但是我想避免使用特定类型来保持对变量名的关注,但要明确这是在局部范围内。使用
char
而不是
auto
,将其从伪C转换为C。顺便说一下
f(C++,C++)
是未定义的行为,用于在没有序列点的情况下修改
c
两次。在c中,
auto a=c
int a=c
相同,无论
c
的类型如何。Yay implicit int.@Zack:我知道这一点,但我想避免使用特定类型来保持对变量名的关注,但要明确这是在局部范围内。