我正在查看下面的代码,我使用递归在C中以相反的顺序打印字符串:
void ReversePrint(char *str) { //line 1
if(*str) { //line 2
ReversePrint(str+1); //line 3
putchar(*str); //line 4
}
}
我对C比较陌生并且被第2行弄糊涂了。*str
从我的理解是取消引用指针并应该返回当前位置的字符串值。但是如何将它用作条件语句的参数(除了布尔权限?)?在第3行,指针将始终递增到下一个块(自int为4个字节)...因此,如果在字符串结束后的下一个内存块中发生数据,则此代码无法失败?
更新:所以c中没有布尔类型正确吗?如果值为0,则条件语句的计算结果为“false”,否则为“true”?
答案 0 :(得分:38)
第2行检查当前字符是否为字符串的空终止符 - 由于C字符串以空值终止,并且空字符被视为false值,因此当它到达结尾时它将开始展开递归字符串(而不是尝试在空终止符之后调用字符上的StrReverse4,这将超出有效数据的范围)。
另请注意,指针指向char
,因此递增指针仅增加1个字节(因为char
是单字节类型)。
示例:
0 1 2 3
+--+--+--+--+
|f |o |o |\0|
+--+--+--+--+
str
= 0
时,*str
为'f'
,因此对str + 1 = 1进行递归调用。str
= 1
时,*str
为'o'
,因此会对str + 1 = 2进行递归调用。str
= 2
时,*str
为'o'
,因此会对str + 1 = 3进行递归调用。str
= 3
时,*str
为'\0'
且\0
为假值,因此if(*str)
的计算结果为false,因此不进行递归调用,从而返回我们得到的递归... 答案 1 :(得分:3)
C字符串的类型只是指向char的指针。惯例是指针指向的是一个字符数组,以零字节终止。
因此, *str
是str
指向的字符串的第一个字符。
如果*str
指向(空)字符串中的终止空字节,则在条件中使用false
求值为str
。
答案 2 :(得分:2)
在字符串的末尾通常是一个0字节 - 行if (*str)
正在检查该字节是否存在,并在它到达时停止。
答案 3 :(得分:1)
在字符串的末尾有一个0
- 所以你有"test" => [0]'t' [1]'e' [2]'s' [3]'t' [4]0
和if(0) -> false
答案 4 :(得分:1)
在第3行中,指针将始终递增到下一个块(自int以来为4个字节)...
这是错的,这是char *,它只会增加1.因为char只有1个字节长。
但是如何将它用作条件语句的参数(除了布尔值右边?)?
你可以使用if($$)at $$的任何值,它只会检查它是否为非零,基本上bool也实现为simple 1 = true和0 = false。
在其他更高级别的强类型语言中,你不能在if中使用这些东西,但在C中,一切都归结为数字。你可以使用任何东西。
if(1) // evaluates to true
if("string") // evaluates to true
if(0) // evaulates to false
你可以在C中的条件中给出任何内容。
答案 5 :(得分:0)
条件语句(if
,for
,while
等)期望一个布尔表达式。如果您提供整数值,则评估结果为0 == false
或non-0 == true
。如上所述,c字符串的终止字符是空字节(整数值0)。因此if
将在字符串的末尾(或字符串中的第一个空字节)失败。
顺便说一句,如果你对NULL指针执行*str
,则调用未定义的行为;在解除引用之前,应始终验证指针是否有效。
答案 6 :(得分:0)
1
str
是指向char的指针。递增str
将使指针指向字符串的第二个字符(因为它是一个char数组)。
注意:递增指针将按指针指向的数据类型递增。
例如:
int *p_int;
p_int++; /* Increments by 4 */
double *p_dbl;
p_dbl++; /* Increments by 8 */
2
if(expression)
{
statements;
}
计算表达式,如果结果值为零(NULL
,\0
,0
),则不执行语句。由于每个字符串以\0
结尾,递归将不得不结束一段时间。
答案 7 :(得分:0)
C没有布尔值的概念:在C中,每个标量类型(即算术和指针类型)都可以在布尔上下文中使用,其中0
表示false
且非零{{1} }。
由于字符串以空值终止,终结符将被解释为true
,而其他每个字符(具有非零值!)将为false
。这意味着有一种简单的方法来迭代字符串的字符:
true
for(;*str; ++str) { /* so something with *str */ }
做同样的事情,但通过递归而不是迭代。
答案 8 :(得分:0)
尝试使用此代码,这与您正在使用的代码一样简单:
int rev(int lower,int upper,char*string)
{
if(lower>upper)
return 0;
else
return rev(lower-1,upper-1,string);
}
答案 9 :(得分:0)
这是一个偏离主题,但当我看到这个问题时,我立刻想知道这是否真的比仅仅做一个strlen并从后面迭代更快。
所以,我做了一点测试。
#include <string.h>
void reverse1(const char* str)
{
int total = 0;
if (*str) {
reverse1(str+1);
total += *str;
}
}
void reverse2(const char* str)
{
int total = 0;
size_t t = strlen(str);
while (t > 0) {
total += str[--t];
}
}
int main()
{
const char* str = "here I put a very long string ...";
int i=99999;
while (--i > 0) reverseX(str);
}
我首先使用X = 1(使用函数reverse1)编译它,然后使用X = 2编译它。两次都是-O0。
递归版本一直返回约6秒,strlen版本返回1.8秒。
我认为这是因为strlen是在汇编程序中实现的,递归会增加很多开销。
我很确定基准是有代表性的,如果我弄错了,请纠正我。
无论如何,我想我应该和你分享。