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