[英]How does this C code work?
我正在查看以下代碼,我使用遞歸在C中以相反的順序打印字符串:
void ReversePrint(char *str) { //line 1
if(*str) { //line 2
ReversePrint(str+1); //line 3
putchar(*str); //line 4
}
}
我對C比較新,我對第2行感到困惑。 *str
我的理解是*str
取消引用指針,應該返回當前位置的字符串值。 但是如何將它用作條件語句的參數(除了布爾權限?)? 在第3行,指針將始終遞增到下一個塊(自int為4個字節)...因此,如果在字符串結束后的下一個內存塊中發生數據,則此代碼無法失敗?
更新 :所以c中沒有布爾類型正確嗎? 如果值為0,則條件語句的計算結果為“false”,否則為“true”?
第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,則不進行遞歸調用,因此返回我們得到的遞歸... C字符串的類型只是指向char的指針。 慣例是指針指向的是一個字符數組, 以零字節結束 。
因此, *str
是str
指向的字符串的第一個字符。
如果str
指向(空)字符串中的終止空字節,則在條件中使用*str
計算為false
。
在字符串的末尾通常是一個0字節 - 行if (*str)
檢查該字節是否存在,並在它到達時停止。
在字符串的末尾有一個0
- 所以你有"test" => [0]'t' [1]'e' [2]'s' [3]'t' [4]0
if(0) -> false
這樣就行了。
在第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條件下,你可以給出任何東西。
條件語句( if
, for
, while
等)期望一個布爾表達式。 如果提供整數值,則評估結果為0 == false
non-0 == true
。 如上所述,c字符串的終止字符是空字節(整數值0)。 因此if
將在字符串的末尾(或字符串中的第一個空字節)失敗。
*str
一句,如果你對NULL指針執行*str
,則調用未定義的行為; 在解除引用之前,應始終驗證指針是否有效。
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
結尾,遞歸將不得不結束一段時間。
C沒有布爾值的概念:在C中,每個標量類型(即算術和指針類型)都可以在布爾上下文中使用,其中0
表示false
,非零表示true
。
由於字符串以空值終止,終結符將被解釋為false
,而其他每個字符(具有非零值!)都將為true
。 這意味着有一種簡單的方法來迭代字符串的字符:
for(;*str; ++str) { /* so something with *str */ }
StrReverse4()
做同樣的事情,但通過遞歸而不是迭代。
試試這個代碼,就像你正在使用的代碼一樣簡單:
int rev(int lower,int upper,char*string)
{
if(lower>upper)
return 0;
else
return rev(lower-1,upper-1,string);
}
這是一個偏離主題,但當我看到這個問題時,我立即想知道這是否真的比僅僅做一個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是在匯編程序中實現的,並且遞歸會增加相當大的開銷。
我很確定基准是有代表性的,如果我弄錯了,請糾正我。
無論如何,我想我應該和你分享這個。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.