在 C 函式中,型別引數char *a可以作為指標或陣列傳遞。在下面的函式中,我使用這個事實來執行函式func。此函式替換陣列的第一個字符。
#include <stdio.h>
void func(char* var) {
var[0] = 'X';
}
int main() {
char a[] = "HELLO";
func(a); // OK
char *b = "HELLO";
func(b); // ERROR
}
作為這樣一個函式的作者,我如何防止有人傳遞指標?在我的函式中,我只想傳遞陣列(因此,指向實際陣列的指標)。
uj5u.com熱心網友回復:
使用我之前問過的一個問題,如何在傳遞給函式時強制使用大小錯誤的陣列發出警告?這是一種方法:
void foo(char (*arg)[]) {
char *p = *arg;
p[0]='X';
}
int main(void) {
char s[1];
char *p;
// These three will throw a warning
foo(p);
foo(&p);
foo(s);
// But this will not
foo(&s);
}
所以缺點是您需要使用&運算子才能使這種方法起作用。如果可能的話,在沒有這個要求的情況下解決它將會是棘手和丑陋的。原因是在大多數情況下,陣列會自動衰減為指標。
uj5u.com熱心網友回復:
這里的實際問題是函式是否傳遞了一個指向可能改變的資料的指標,而不是函式是否傳遞了一個字串。
根據 C 2018 7.1.1 1,“字串是由第一個空字符終止并包括第一個空字符的連續字符序列。” 因此,對于char a[] = "HELLO";,該陣列包含一個字串。
用char *b = "HELLO";,b指向字串文字1的第一個字符。字串文字中的資料應該被視為常量——程式不應嘗試修改它,C 實作可能會將它放在只讀記憶體中,以便嘗試修改它會導致程式例外。
如果我們從頭開始設計 C 語言,字串文字將使用const. 但是,const在創建字串文字時不存在。程式員只需要知道資料何時是字串文字的一部分,他們有責任避免嘗試更改它。
在某種程度上,您可以通過const手動添加來改善這個問題,就像const char *b = "HELLO";. 然后嘗試傳遞b到func將導致關于嘗試傳遞const char *引數的char *引數的編譯器診斷訊息。
如果認為防止錯誤非常重要,則所有字串文字都可以寫為復合文字,例如(const char []) { "HELLO" },并且可以定義一個宏來執行此操作:
#define StringLiteral(x) ((const char []) { (x) })
腳注
1從技術上講,字串文字是源代碼中的字符,例如"HELLO",包括引號。編譯程式時,源代碼中的字串文字會導致創建包含字串的陣列。非正式地,我們將此陣列稱為字串文字。
uj5u.com熱心網友回復:
正如我們所知,陣列實際上從未真正傳遞給函式,編譯器在傳遞給函式時將陣列和指標都視為指標,因為指標和陣列彼此接近,但它們并不相同。
char a[] = "你好";
char *p = "世界";
--- --- --- --- --- ---
a: | h | e | l | l | o |\0 |
--- --- --- --- --- ---
----- --- --- --- --- --- ---
p: | *======> | w | o | r | l | d |\0 |
----- --- --- --- --- --- ---
為了解決指標保護點,我們可以使用 GNU C 內置函式
__builtin_types_compatible_p() 用于比較兩種型別成功回傳 1 否則回傳 0
和 GNU 編譯器擴展typeof(),它用于在運行時確定型別,借助 GNU 擴展,我們可以限制將指標傳遞給函式
if (__builtin_types_compatible_p(__typeof__(b), char[]))
{
printf("compatible with char [] so calling to func()");
func(b);
}
else
{
printf("oops sorry only array is allow to passed");
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/392919.html
下一篇:使用指標讀取字符陣列
