84669 personnes étudient
152542 personnes étudient
20005 personnes étudient
5487 personnes étudient
7821 personnes étudient
359900 personnes étudient
3350 personnes étudient
180660 personnes étudient
48569 personnes étudient
18603 personnes étudient
40936 personnes étudient
1549 personnes étudient
1183 personnes étudient
32909 personnes étudient
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的指针传过去