void GetMemory(char *p) { p = (char *)malloc(100); } void Test(void) { char *str = NULL; GetMemory(str); strcpy(str, "hello world"); printf(str); }
光阴似箭催人老,日月如移越少年。
提問者似乎不太了解 C 語言,建議閱讀《K & R》等基礎教程。
你試圖通過 GetMemory() 把 *str 指向一段 malloc() 分配的內存。
GetMemory()
*str
malloc()
但是,C 語言的函數傳參是按值傳參,*str 的值 NULL 被拷貝到 *p,隨後 *p 被指向 malloc() 返回的值,此時 GetMomory() 函數結束。*str 的值仍然為 NULL,沒有任何變化。之後,你使用 strcpy 企圖把 "hello world" 複製到 NULL,當然出錯。
NULL
*p
GetMomory()
strcpy
"hello world"
正確的做法是,傳遞指針變量 *str 的地址給 GetMemory(char **p)。*str 本身就是一個指針,指向一個地址。*str 雖然是指針,但指針也有自己的地址,把 *str 的地址傳給 **p,**p 便是一個指向指針的指針。
GetMemory(char **p)
**p
到此為止,你的主要問題已經解決。可以跳過剩餘部分直接看代碼。
free()
程序退出後,操作係統會自動釋放所有內存。但是,使用完內存後立刻釋放永遠沒錯。
printf()
另外,你的 printf() 用法錯誤。printf() 的參數不能直接是要打印的數據。而需要一個帶轉換說明符的字麵字符串,後麵的參數是要格式化的實參。
有人說按照 printf() 的原型,直接跟一個字符串 printf(str) 也是沒有問題的。然而,str 如果是從外部獲得的內容,如用戶輸入的,會導致嚴重的安全問題。GCC 和 Clang 會對這樣的用法都會產生警告。
printf(str)
str
比如說,在老舊的 32 位 Linux 上:
#include <stdio.h> int main(int argc, char **argv) { char *secret = "This is a secret!\n"; printf(argv[1]); return 0; }
如果使用 -mpreferred-stack-boundary=2 編譯
-mpreferred-stack-boundary=2
$ gcc -mpreferred-stack-boundary=2 FormatString.c -o FormatString $ ./FormatString %s This is a secret!
哦?這是為什麼?我對底層了解不多,隻能說這和 varargs 的內存越界有關,而 *secret 正好在這個內存地址上。有沒有聯想到 OpenSSL 前些時間曝光了“心髒出血”漏洞?
varargs
*secret
-mpreferred-stack-boundary=2 並非攻擊的必要手段。隻要條件適宜,經過周密計算,危害可能比這大得多。
因此這樣的用法必須禁止,應使用
printf("%s\n", str);
或
puts(str);
#include
使用庫函數前需要 #include 提供相應函數的頭文件。
stdio.h
stdlib.h
strcpy()
string.h
main()
main() 函數是程序的入口,沒有入口,程序從何處執行?
更正後的程序如下。
#include <stdio.h> #include <stdlib.h> #include <string.h> void GetMemory(char **p) { *p = (char *)malloc(100); } void Test(void) { char *str = NULL; GetMemory(&str); strcpy(str, "hello world"); printf("%s\n", str); free(str); *str = NULL; // 避免误用已悬空的指针 } int main(void) { Test(); return 0; }
娘的……答案評論裏不支持貼代碼,那我就另外加一個答案吧。對於最佳答案的一些評論
int printf ( const char * format, ... );
因此,printf(str) 是可行的。
但是,如果 str 是用戶輸入的內容或外部獲得的內容,str 中就可能含有惡意代碼,可以用來進行內存溢出進而執行任意代碼的攻擊。因此,這樣做應該是嚴格禁止的。—— Biergaizi
char* GetMemory() { char* p = (char *)malloc(100); memset(p, 0, SIZE); // or *p = 0; return p; }
以下下代碼在win7上編譯,運行通過
#include <stdio.h> #include <stdlib.h> #include <string.h> #define SIZE 100 void GetMemory(char **p) { *p = (char *)malloc( memset(*p, 0, SIZE); // or **p = 0; } void Test(void) { char *str = NULL; GetMemory(&str); strcpy(str, "hello world"); printf(str); free( str); str = NULL; } int main(void) { Test(); return 0; }
最簡單的回答就是樓主沒有搞清楚: 引用傳遞和值傳遞
想要修改str指向的內容,你得把指向str的指針傳過去
提問者似乎不太了解 C 語言,建議閱讀《K & R》等基礎教程。
變量賦值錯誤(崩潰原因)
你試圖通過
GetMemory()
把*str
指向一段malloc()
分配的內存。但是,C 語言的函數傳參是按值傳參,
*str
的值NULL
被拷貝到*p
,隨後*p
被指向malloc()
返回的值,此時GetMomory()
函數結束。*str
的值仍然為NULL
,沒有任何變化。之後,你使用strcpy
企圖把"hello world"
複製到NULL
,當然出錯。正確的做法是,傳遞指針變量
*str
的地址給GetMemory(char **p)
。*str
本身就是一個指針,指向一個地址。*str
雖然是指針,但指針也有自己的地址,把*str
的地址傳給**p
,**p
便是一個指向指針的指針。到此為止,你的主要問題已經解決。可以跳過剩餘部分直接看代碼。
遺漏
free()
程序退出後,操作係統會自動釋放所有內存。但是,使用完內存後立刻釋放永遠沒錯。
printf()
用法錯誤另外,你的
printf()
用法錯誤。printf()
的參數不能直接是要打印的數據。而需要一個帶轉換說明符的字麵字符串,後麵的參數是要格式化的實參。有人說按照
printf()
的原型,直接跟一個字符串printf(str)
也是沒有問題的。然而,str
如果是從外部獲得的內容,如用戶輸入的,會導致嚴重的安全問題。GCC 和 Clang 會對這樣的用法都會產生警告。比如說,在老舊的 32 位 Linux 上:
如果使用
-mpreferred-stack-boundary=2
編譯哦?這是為什麼?我對底層了解不多,隻能說這和
varargs
的內存越界有關,而*secret
正好在這個內存地址上。有沒有聯想到 OpenSSL 前些時間曝光了“心髒出血”漏洞?-mpreferred-stack-boundary=2
並非攻擊的必要手段。隻要條件適宜,經過周密計算,危害可能比這大得多。因此這樣的用法必須禁止,應使用
或
沒有
#include
任何頭文件使用庫函數前需要
#include
提供相應函數的頭文件。printf()
由stdio.h
提供malloc()
由stdlib.h
提供strcpy()
由string.h
提供沒有
main()
函數main()
函數是程序的入口,沒有入口,程序從何處執行?更正後的程序如下。
娘的……答案評論裏不支持貼代碼,那我就另外加一個答案吧。對於最佳答案的一些評論
因此,
printf(str)
是可行的。但是,如果
str
是用戶輸入的內容或外部獲得的內容,str
中就可能含有惡意代碼,可以用來進行內存溢出進而執行任意代碼的攻擊。因此,這樣做應該是嚴格禁止的。—— Biergaizi以下下代碼在win7上編譯,運行通過
最簡單的回答就是樓主沒有搞清楚: 引用傳遞和值傳遞
想要修改str指向的內容,你得把指向str的指針傳過去