2014-09-21 57 views
0

這裏是我的功能:的sprintf本身削減輸出字符串

char *HexCastName(UINT Address) { 
    char Name[100] = ""; 
    UINT Offset; 
    for (int i = 0; i < HardNames.size(); i++) { 
     if (HardNames[i].Array == Hex.CurrentRegion.Array && 
      HardNames[i].Start <= Address && 
      HardNames[i].Start + HardNames[i].Size > Address) { 
      Offset = Address - HardNames[i].Start; 
      sprintf(Name, " : %s[%d]", HardNames[i].Name, Offset); 
     } 
    } 
    return Name; 
} 

我這樣做:

char name[100]; 
sprintf(name, HexCastName(SELECTION_START)); 

結果字符串name只有4位數,雖然HexCastName()回報更多。我試圖追蹤它,並且它似乎將整個字符串傳遞給sprintf(),並且在其中的某個位置,它獲取到_output_l(outfile,format,NULL,arglist)函數。在裏面,format變量最初包含我的整個字符串,然後在讀取一些變量後,執行從output.c中的973跳轉到978,並且我的format已被截斷。我完全被這種行爲困惑......爲什麼4個字母?也許一些指針和字符失敗?

編輯:

這裏,似乎工作的版本:

void HexCastName(char *buff, UINT size, UINT Address) { 
    sprintf(buff, ""); 
    UINT Offset; 
    for (int i = 0; i < HardNames.size(); i++) { 
     if (HardNames[i].Array == Hex.CurrentRegion.Array && 
      HardNames[i].Start <= Address && 
      HardNames[i].Start + HardNames[i].Size > Address) { 
      Offset = Address - HardNames[i].Start; 
      _snprintf(buff, size, " : %s[%d]",HardNames[i].Name, Offset); 
     } 
    } 
} 

char *name = (char *)malloc(100); 
HexCastName(name, 100, SELECTION_START); 
sprintf(str, "%s: $%06X%s", area, 
    Hex.AddressSelectedFirst + Hex.CurrentRegion.Offset, name); 
free(name); 
+0

您正在返回一個自動存儲VAR的地址 - UB。 – 2014-09-21 08:26:08

回答

3

我的C編程語言數組與其他變量具有相同的作用域規則。在您的代碼char name[100]將被推送到堆棧,但將返回時將被刪除。

char *HexCastName(UINT Address) { 
    char Name[100] = ""; // Here `Name` gets pushed to the stack. 
    UINT Offset; 
    for (int i = 0; i < HardNames.size(); i++) { 
     if (HardNames[i].Array == Hex.CurrentRegion.Array && 
      HardNames[i].Start <= Address && 
      HardNames[i].Start + HardNames[i].Size > Address) { 
      Offset = Address - HardNames[i].Start; 
      sprintf(Name, " : %s[%d]", HardNames[i].Name, Offset); 
     } 
    } 
    return Name; 
    // Here will `Name` be "deleted" as it exits scope, the pointer that is returned will point to garbage memory. 
} 

你有3種選擇:

首先是在功能堆中分配的內存Name

char *Name = malloc(100); 

這是不推薦,因爲你可以很容易忘記釋放返回的指針:

void function() 
{ 
    char *Name = HexCastName(0xDEADBEEF); 
    free(Name); // If you forget to write this you will have a memory leak. Uugh. 
} 

第二種方法:

你可以聲明Name靜態的。

static char name[100]; 

如果你不知道什麼static意味着Name總是會在內存中(如全局變量)。這非常好,因爲現在我們不必擔心釋放它的內存。

但是這種方法也有大缺陷。多個函數調用將修改相同的變量Name。例如:

void function() 
{ 
    char *Name1 = HexCastName(0xDEADBEEF); 
    char *Name2 = HexCastName(0xDEAFCAEF); 
    printf("Name1 = %s\n", Name1); 
    printf("Name2 = %s\n", Name2); 
    // Because we declared `Name` static will both pointers point to the same memory and point to the same string. Not very good. 
} 

這變得更糟,因爲函數未聲明返回一個const char *但修改char *

第三種解決方案:

第三個解決方案是一個我建議。這是聲明HexCastName這樣的:

// The user chooses were to write the result. 
void HexCastName(char *NameOut, size_t BufSize, UINT Address) { 
    char NameOut[0] = ""; 
    UINT Offset; 
    for (int i = 0; i < HardNames.size(); i++) { 
     if (HardNames[i].Array == Hex.CurrentRegion.Array && 
      HardNames[i].Start <= Address && 
      HardNames[i].Start + HardNames[i].Size > Address) { 
      Offset = Address - HardNames[i].Start; 
      snprintf(NameOut, " : %s[%d]", BufSize, HardNames[i].Name, Offset); 
     } 
    } 
} 

請注意,我用snprintf而不是常規sprintf。這是因爲sprintf容易受到「緩衝區溢出」的影響。如果您想了解更多關於它,你可以檢查接受這個問題的答案:sprintf function's buffer overflow?

這個版本被使用這樣的:

void function(void) 
{ 
    char Name[100]; 
    HexCastName(Name, sizeof(Name)); 
} 
+0

+1。第三個解決方案是另一個不錯的選擇,但它也有其缺點:在使用之後,不能像第一個解決方案那樣釋放Name。 – 2014-09-21 09:33:00

+0

看起來我只需要malloc在主區域,而不是'HexCastName()',所以malloc和free會非常接近,非常明顯。 – feos 2014-09-21 09:37:48

+0

@YHHao你也可以調用這樣的函數:'char * Name = malloc(100); HexCastName(Name,100);免費(名稱);'。 @feos是的,這是這個版本的優點。 – wefwefa3 2014-09-21 09:41:14

3

您在功能HexCastName,這是一個本地數組變量返回Name。函數退出後,它不再指向有效的地方。

相反,使用動態分配:

char *Name = malloc(100); 

記得釋放內存當它不使用。

+0

我應該在什麼時候釋放它? – feos 2014-09-21 08:32:46

+0

@feos當你不再需要它了。 – 2014-09-21 08:33:50

+0

好吧,我想在返回後不需要它,但它在返回後立即退出。它必須存在一段時間才能到達另一個函數的空間,但是之後不再有'Name'變量,要釋放什麼? – feos 2014-09-21 08:37:32

1

不,這不是sprintf的問題。

原因是,你的Name有其局部範圍和存儲在HexCastName裏面,並且將指針傳遞給函數外部是未定義的行爲。

要解決這個問題,可以通過動態分配存儲空間來使用@YooHao的方法,或者在函數外部使用@OyuHao的方法,或者將其指針傳遞給該函數。

1

HexCastName返回一個指向局部變量的指針。當HexCastName返回時,它指向的內存不再有效,因此您將垃圾傳遞給sprintf

您可以使HexCastName分配與malloc內存並返回,或者你可以讓調用者負責傳入緩衝區HexCastName寫入。

+0

第二個解決方案聽起來很有趣。你能提供一些例子嗎?我試過了,並沒有弄清楚正確的方法。 – feos 2014-09-21 09:02:36