簡體   English   中英

這個C代碼如何工作?

[英]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|
+--+--+--+--+
  1. str = 0*str'f'因此對str + 1 = 1進行遞歸調用。
  2. str = 1*str'o'因此對str + 1 = 2進行遞歸調用。
  3. str = 2 ,則*str'o'因此對str + 1 = 3進行遞歸調用。
  4. str = 3 ,則*str'\\0'\\0為假值,因此if(*str)求值為false,則不進行遞歸調用,因此返回我們得到的遞歸...
  5. 最近的遞歸之后是`putchar('o'),之后,
  6. 接下來最近的遞歸之后是`putchar('o'),之后,
  7. 最近的遞歸之后是`putchar('f'),我們已經完成了。

C字符串的類型只是指向char的指針。 慣例是指針指向的是一個字符數組, 以零字節結束

因此, *strstr指向的字符串的第一個字符。

如果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條件下,你可以給出任何東西。

條件語句( ifforwhile等)期望一個布爾表達式。 如果提供整數值,則評估結果為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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM