c语言指针学习指向局部变量内存能释放吗?

22:43 提问
c语言的局部变量地址是连续的吗?
int function()
int i,j ,x;
i,j,x的地址是按照顺序以四字节的间隔申请的吗?
按赞数排序
在栈上连续分配,但是根据字节对齐的不同,不一定紧密相连,/b&。
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!
其他相关推荐关于c语言函数中局部变量的返回,在main函数中值是否可用的问题
[问题点数:20分,结帖人tqy_sky]
本版专家分:0
结帖率 60%
CSDN今日推荐
本版专家分:21107
2008年2月 Linux/Unix社区大版内专家分月排行榜第一2007年7月 Linux/Unix社区大版内专家分月排行榜第一
2008年3月 Linux/Unix社区大版内专家分月排行榜第二
2012年9月 Linux/Unix社区大版内专家分月排行榜第三2007年6月 Linux/Unix社区大版内专家分月排行榜第三
本版专家分:0
本版专家分:951
本版专家分:2190
本版专家分:175
本版专家分:53
本版专家分:270
本版专家分:56
本版专家分:17
本版专家分:0
匿名用户不能发表回复!
其他相关推荐下次自动登录
现在的位置:
& 综合 & 正文
C语言 子函数return(局部变量&局部指针&栈)机制
C/C++中,函数内部的一切变量(函数内部局部变量,形参 )都是在其被调用时才被分配内存单元。子函数运行结束时,所有局部变量的内存单元会被系统释放。形参和函数内部的局部变量的生命期和作用域都是在函数内部(
static变量的生命期除外)。
在C中,函数被调用时的传参方式有两种形式:传值和传址。
传址的好处:
(1)能在函数内部通过实参地址间接地改变实参的值。
(2)当所传实参内容比较庞大时,传址只是复制了整个实参的地址过去,指针依据同一个地址访问实参变量。而传值就会将实参内容整个拷贝过去,形参会跟实参占一样大的内存,栈空间是有限的。当然了,在弱小的程序中,传址的这个优点不会被体现出来。
在函数中,可以随意的返回一个局部变量。但如果返回一个局部变量的地址(指针 ),编译器就会给出警告(编译器也不可能那么完美能够彻底的检查出段错误)。在函数内部返局部指针这的确是一个危险的操作。鄙人的笔记先将用return返回值(指针为地址值)的机制搞清楚后再分析一下。
1函数内部返回局部变量过程
Linux等的C语言中return返回值的机制为:将返回值存入eax寄存器中,然后系统再将eax中的值赋给变量(i)。
(1)编写一个简单的C源程序
在linux 下敲一个简单的函数调用的程序:
Figure1:C中函数调用的简单例子
涉及到局部变量存储问题时先查了2个概念:
堆栈:堆栈其实是两种数据结构。
堆:由程序员分配和释放。如在C/C++中程序员使用malloc/new分配堆空间,使用free/delete释放所申请的堆空间。特点:释放内存块顺序随意。
栈:栈是由系统自动分配和回收的内存。如一个子函数被调用时,系统会将函数内的局部变量的内存单元分配到栈上,当函数执行完毕时系统自动释放所分配的栈地址单元。特点:释放栈内存顺序为后进先出。
(2)分析子函数调用的过程
【1】当程序执行到第8行调用子函数child_fun,程序转到到child_fun子函数入口地址处。
【2】程序进入child_fun子函数(即此子函数开始运行 ),执行到”return
1;”时,系统将返回的1存入寄存器eax中,然后经‘}’标志后函数运行完毕。若子函数中有形参和局部变量,则在函数开始运行时,系统自动为局部变量分配栈空间,待函数运行完毕时系统自动释放在栈中为局部变量分配的内存单元中的数据。
【3】child_fun子函数执行完毕,函数返回到调用子函数的地方即第8行处继续执行,将保存在寄存器eax中的值即1赋给变量i。
1.2汇编验证
如何验证所总结的return机制呢?
(1)汇编C源文件
在linux字符界面下,将以上提到的那段C语言程序编译成与之对应的汇编代码:gcc –S
var_return_in_fun.c
得到var_return_in_fun.s文件,打开文件查看汇编代码:vi var_return_in_fun.s:
Figure2:C语言对应的汇编代码
编译C语言源文件时可不为gcc添加加-O2优化参数,不然在汇编代码中会看不到子函数调用的call指令。
(2)分析汇编代码
当初学习RAM汇编指令的时候没有清晰的动过手,对于这段汇编代码也是只认识push、move之系列英语单词,但是不会可以学习一下:
【1】由于不同的CPU的汇编格式不一样,故首先了解一下当前操作系统使用的什么汇编格式。比如windows下采用的Intel的汇编格式,linux采取的是AT&T汇编格式。
【2】收索一下AT&T汇编指令,浏览一下。明白一些基本指令的含义和编写格式后,只抓这个汇编代码的关键部分进行跟踪:
[1]在main函数中,调用子函数child_fun之前的汇编代码就不用看了,是依函数地址,初始化栈、代码段之类的含义。从13行的”call
child_fun”开始,程序就从红线箭头标识的方向跳到子函数child_fun处开始执行。
[2]27行前的代码就不用看了,也根据将子函数地址初始化栈之类的。请我对照C语言源代码,第27行的代码”move1
%eax”的含义是将常数1装入寄存器eax中。常数1对应C语言源代码中return后面的常数1。28行出栈,29行从子函数child_fun处返回到14行处。
[3]14行代码”movel
-8(%ebp)”的含义是将寄存器eax的值载入”-8(%ebp)”所寻址之处,而且这个地址就是变了i的地址(
12行及16行对应语句之间的内容是main函数中的内容,12行之前是初始化代码,16行后是恢复未初始状态的代码,可单独写程序验证)。并且main函数中的返回值也是保存在寄存器eax中的[见图2汇编代码
2函数内部返回局部指针过程
在最开始的未明白return机制前可能还是要纳闷:在子函数中返回一个局部变量,等子函数运行结束时,此局部变量会被释放掉。当在子函数中返回一个指针时,等子函数运行结束时,此地址中的值会被释放掉。有点找不出其中被释放的差别。根据返回局部变量的经验,
可以这么分析:在执行return语句时,首先将return后面的地址值返回存入到比如eax寄存器中,然后系统再将eax中的地址值给接收函数返回地址的指针变量。这看起来都没什么问题,但问题在于两个方面:
[1]接收函数返回地址值的指针变量要访问此地址中的内容。
[2]子函数运行结束后,一切有关于局部变量的内存都已经释放回收。那么在用这个地址来操作就很危险:根本没有这个地址或者是地址中没有内容[没有内容是对的
但真的是像分析的这样么?(是的)。只有写程序来验证了。
2.1返回局部指针也没出错问题的情况
有的程序就能够将局部变量的地址放回回来,甚至在编译时警告都没有。例如以下程序例子:
Figure3:返回局部地址
Figure4:编译运行
这个令人吃惊的结果不禁让人怀疑自己最开始对栈内存释放的理解。这个例子最起码验证了在子函数执行完毕后,原存在栈中的内容是没有被释放掉的。那么栈由系统自动分配和回收到底是怎么个情况呢?再整个不能输出正确结果的例子。
2.2栈内容被释放掉的例子
Figure5:栈内容被释放的例子
Figure6:图5的执行结果
根据程序代码和执行结果可见正如标题那个样子:栈内存还在,只是栈内存中的值被释放掉了。它不在被程序所占用。
因为在子函数执行完毕时毕竟还是将栈内存(即局部变量的地址)返回到了父函数中。但是内存中的值已经被释放掉了。但是为什么第一个值依旧没有被释放掉呢?是正确的呢?可能是首地址所以一直都会给其它程序留个好印象吧。
所以最后的结论是:子函数中的局部地址是能够被return到父函数中去的。只是在父函数中用这个地址去访问内容时,此地址中的内容已经被系统清除掉。这是很危险的操作:在父函数中用此地址访问其内容时,有可能刚被释放掉的这块栈内存又被系统分配另外的局部变量了,而此时你所访问的结果只是会导致程序结果不正确而已;但如果此地址中的内容还是不定状态,访问得到的值跟Figure
释放/回收的含义
栈的分配和释放可以这样子理解:栈内存块在计算机中不可能会移动,它的地址已经被固定。系统分不分配它,它就在那里。当为局部变量分配栈内存时,系统就将局部变量存入到栈的某个内存块中;当子函数运行结束局部变量应当被释放时,系统再将这些存入局部变量的栈内存中的数据清除掉,恢复原来没有被初始化的状态。
不管是返回指针还是返回值,return将return之后的值存到eax寄存器中,回到父函数再将返回的值赋给变量。
(2)局部地址
在函数内返回一个指针会出错的原因:子函数运行完毕时,存局部变量的所有栈地址的内容已经被释放。若在父函数中再访问这些地址中的内容时,因为这些地址的内容已经被释放,所访问到的值可能是乱的、不定的。
(3)分配/释放内存
分配内存,就是将某变量存入到某块内存中的一个地址中;释放内存,就是将此内存中的内容清除掉,恢复内存未被初始化的状态。
此次笔记记录完毕。
【上篇】【下篇】c语言局部变量怎样分配存储空间
[问题点数:40分,结帖人Sforforforfor]
本版专家分:0
结帖率 100%
CSDN今日推荐
本版专家分:2506
本版专家分:1828
2017年5月 Linux/Unix社区大版内专家分月排行榜第一
2015年9月 Linux/Unix社区大版内专家分月排行榜第二
本版专家分:713
本版专家分:31777
2014年4月 C/C++大版内专家分月排行榜第二
2016年2月 C/C++大版内专家分月排行榜第三2016年1月 C/C++大版内专家分月排行榜第三
本版专家分:31777
2014年4月 C/C++大版内专家分月排行榜第二
2016年2月 C/C++大版内专家分月排行榜第三2016年1月 C/C++大版内专家分月排行榜第三
本版专家分:2478
本版专家分:11473
2014年6月 C/C++大版内专家分月排行榜第二
本版专家分:37
本版专家分:369954
2017年 总版技术专家分年内排行榜第一
2014年 总版技术专家分年内排行榜第二
2013年 总版技术专家分年内排行榜第三
2012年 总版技术专家分年内排行榜第七
本版专家分:0
本版专家分:31777
2014年4月 C/C++大版内专家分月排行榜第二
2016年2月 C/C++大版内专家分月排行榜第三2016年1月 C/C++大版内专家分月排行榜第三
本版专家分:31777
2014年4月 C/C++大版内专家分月排行榜第二
2016年2月 C/C++大版内专家分月排行榜第三2016年1月 C/C++大版内专家分月排行榜第三
本版专家分:4268
本版专家分:0
本版专家分:31777
2014年4月 C/C++大版内专家分月排行榜第二
2016年2月 C/C++大版内专家分月排行榜第三2016年1月 C/C++大版内专家分月排行榜第三
匿名用户不能发表回复!
其他相关推荐一.变量A.局部变量与全局变量。体现例子:不同函数之间的变量无法互相访问。#include &stdio.h&
int main()
int i = 520;
printf("before, i = %d\n", i);
for (int i = 0; i & 10; i++)//c99中for语句第一个表达式才能定义变量。
printf("%d\n", i);
printf("after, i = %d\n", i);
getchar();
}&因为i所对应的作用域不同所以for在声明i没有报错。全局变量:指在函数外所定义的变量,受所有函数所共用。局部变量:指在函数内部所定义的变量,只能作用域其函数内部,受其函数所使用。全局变量如果没有初始化,它会自动初始化为0。如果函数内部存在一个与全局变量同名的局部变量,编译器并不会报错,而是在函数中屏蔽全局变量。(也就是这个函数内,全局变量不起作用)例:#include &stdio.h&
void func();
int a, b = 520;
void func()
printf("In func ,a = %d, b = %d\n", a, b);
int main()
printf("In main ,a = %d, b = %d\n", a, b);
printf("In main ,a = %d, b = %d\n", a, b);
getchar();
}结果:In main ,a = 0, b = 520
In func ,a = 880, b = 120
In main ,a = 880, b = 520
建议:不要大量的使用全局变量。因为&&&&1.大量占用内存。 && 2.污染命名空间,使程序可读性降低。&&& 3.提高了程序的耦合性,代码长了就不知道全局变量被那些函数所修改过。B.作用域。含义:当变量被定义在程序的不同位置时,它所作用的范围是不一样的,这个范围被称为作用域。分类:代码块作用域("{}"在其内部的作用域)文件作用域(作用于一个文件或者多个文件时[多个文件先用头文件包含进去然后再用extern关键字告诉编译器此变量已被定义])原型作用域(只适用于那些在函数原型中声明的参数,相当于函数的声明参数与函数的定义参数。)函数作用域(只适用于goto语句的标签,限制goto语句的标签在同一个函数内部,以防出现重名标签。)C.定义与声明的区别。定义:变量被定义时,编译器为其变量申请内存空间并填充其值。声明:变量被声明时,编译器就知道该变量被定义在其他地方。注意:1.局部变量既是定义也是声明。&&& 2.定义只能出现一次,而声明可以很多次。D.链接属性。external(外部):多个文件中声明的同名标识符表示同一个实体internal(内部):单个文件中声明的同名标识符表示同一个实体none(无):声明的同名标识符被当作独立不同的实体注:1.只有具备文件作用域的标识符才能拥有external、internal属性(函数、全局变量等等),其他作用域的标识符是none属性。&&&&&&&&2.默认情况下具备文件作用域的标识符拥有external属性。&&&&&&& 3.使用static关键字可修改拥有external属性的标识符为internal属性。只针对具有文件作用域的标识符生效。&&&&&&& 4.链接属性只能修改一次。修改后不能再改回来。E.生存期。类型:静态存储期、自动存储期静态存储期:静态存储期的变量在程序执行期间一直占据存储空间,直到程序关闭才释放。(全局变量、函数等具有文件作用域的)自动存储期:自动存储期的变量在代码块结束时将自动释放存储空间。(局部变量,函数体等具有代码块作用域的)F.存储类型含义:指存储变量值的内存类型。类型:auto、register 、static、externauto:代码块中变量(局部变量)默认的存储类型、自动变量(代码块作用域、空链接属性none、自动存储期)。register:变量有可能存储在寄存器上,读取速度快,寄存器变量(代码块作用域、空链接属性none、自动存储期)、注意:当变量被声明为寄存器变量后无法通过取址得到其地址。static:使用它来描述局部变量,使其局部变量指定为静态变量(代码块作用域、静态存储期、空链接属性)、使用它来描述全局变量(文件作用域、静态存储期、内部链接属性internal)。extern:告诉编译器此变量已定义。二.动态内存管理库函数:(都在头文件stdlib.h中)malloc——申请动态内存空间free——释放动态内存空间calloc——申请并初始化内存空间realloc——重新分配内存空间A.malloc(申请的空间是在堆上,堆上空间不主动释放会永远存在直到程序关闭)原型:void *malloc(size_t size);//malloc函数向系统申请分配size个字节的内存空间,并返回一个指向这块内存的void指针。注意:申请的空间并未被初始化为0。如果函数调用成功返回void指针,如果函数调用失败返回NULL。另外如果size参数设置为0,返回的值也有可能是NULL,但并不意味着函数调用失败。因为申请的是一块连续的内存空间可以用数组下标索引访问。意:防止丢失内存地址造成内存泄漏。B.free(注意:如果不及时释放没有用的内存,会造成内存泄漏)原型:void free(void *ptr);//free函数将释放ptr参数指向的内存空间。该内存空间必须是由calloc、realloc、malloc函数申请的内存空间。否则该函数将导致未定义行为。如果ptr参数是NULL,则不执行任何操作。注意:该函数不会修改ptr参数的值,所以使用后它仍然指向原来的地方(变为非法空间)。例:#include &stdio.h& //标准输入输出头
#include &stdlib.h& //动态内存分配、exit退出函数
int main(void)
printf("请输入待录入整数的个数:");
scanf("%d", &num);
getchar();
ptr = (int *)malloc(num * sizeof(int));//分配num块int空间大小的内存并返回int指针
if (ptr == NULL) //检测是否分配失败
printf("分配内存失败!\n");
exit(1);//分配失败退出
for (i = 0; i & i++)
printf("请录入第%d个整数:", i + 1);
scanf("%d", &ptr[i]);//以数组索引取访问分配的内存
getchar();
printf("你录入的整数分别是:\n");
for (i = 0; i & i++)
if (i != 0 && i % 5 == 0)//每5个换一行
printf("\n");
printf("%d\t", ptr[i]);
putchar('\n');
free(ptr);//释放内存
getchar();
}如果需要初始化刚申请的内存空间可以用mem开头的函数,包含在string.h头文件中:memset //使用一个常量字节填充内存空间
memcpy //拷贝内存空间memcpy(ptr2,ptr1,10)//第一个参数目的地址,第二个参数原地址,第三个参数拷贝大小
memmove //拷贝内存空间
memcmp //比较内存空间
memchr //在内存空间中搜索一个字符C.calloc原型:void *calloc(size_t nmemb, size_t, size);//calloc函数在内存中动态地申请nmemb个长度为size的连续内存空间(nmemb * size),这些内存空间被默认初始化为0。以下写法等价://calloc()分配内存空间,只调用了一次函数。
int *ptr = (int *)calloc(8, sizeof(int));
//malloc()分配内存空间并用memset()初始化内存空间,调用两次函数。
int *ptr = (int *)malloc(8 * sizeof(int));
memset(ptr, 0, 8 * sizeof(int));D.realloc(慎用)原型:void *realloc(void *ptr, size_t size);//如果新分配的内存空间比原来的大,则旧内存数据不会发生改变。如果新分配的内存空间比原来小,则可能会导致数据丢失。该函数将移动内存空间的数据并返回新的指针地址。如果ptr的参数为NULL,那么调用该函数就相当于调用malloc()。如果size参数为0,并且ptr参数不为NULL,那么该函数相当于调用了free(ptr)。除非ptr参数为NULL,否则ptr的值必须由先前调用malloc、calloc或者realloc函数的返回(不能用指向局部变量的指针,一定要用指向堆的指针)。如果新申请的内存大小不超过原来的内存大小,则依旧使用原来的内存,返回旧地址,否则申请新的更大的内存,将原内存上的数据拷贝过来,释放原内存,返回新地址。例:/*
要求使用realloc申请内存空间,
让用户一直输入一个整数,
根据用户没输入一个我们就新增加一个int空间让其存放
直到用户输入-1表示输入结束。
把用户所有输入打印出来。
#include &stdio.h&
#include &stdlib.h&
int main(void)
int i,//i用于for循环打印,num用户输入的数据
int count = 0;//计算输入了多少个
int *ptr = NULL;//因为用realloc所以ptr必须指向NULL
printf("请输入一个整数[输入-1表示结束]:");
scanf("%d", &num);
getchar();
ptr = (int *)realloc(ptr, count * sizeof(int));
if (ptr == NULL)
ptr[count-1] =
} while(num != -1);
printf("输入的整数分别是:");
for (i = 0; i & i++)
printf("%d\t", ptr[i]);
putchar('\n');
free(ptr);
getchar();
}二.(一)内存的分布例:#include &stdio.h&
#include &stdlib.h&
int global_uninit_
int global_init_var1 = 520;
int global_init_var2 = 880;
void func(void);
void func(void)
int main(void)
int local_var1;
int local_var2;
static int static_uninit_
static int static_init_var = 456;
char *str1 = "I love you";
char *str2 = "You are right!";
int *malloc_var = (int *)malloc(sizeof(int));
printf("addr of func -& %p\n", func);
printf("addr of str1 -& %p\n", str1);
printf("addr of str2 -& %p\n", str2);
printf("addr of global_init_var1 -& %p\n", &global_init_var1);
printf("addr of global_init_var2 -& %p\n", &global_init_var2);
printf("addr of static_init_var -& %p\n", &static_init_var);
printf("addr of static_uninit_var -& %p\n", &static_uninit_var);
printf("addr of global_uninit_var -& %p\n", &global_uninit_var);
printf("addr of malloc_var -& %p\n", malloc_var);
printf("addr of local_var1 -& %p\n", &local_var1);
printf("addr of local_var2 -& %p\n", &local_var2);
getchar();
}效果图:分配规律:C语言内存分配规律:代码段(text):用来存放程序执行代码的一块内存区域。这块大小在程序运行前就已经确定,通常属于只读。也有可能包含一些只读常量。如:字符串常量等。数据段(data):通常用来存放已经初始化的全局变量和局部静态变量。BSS段:通常用来存放程序中未初始化的全局变量的一块内存区域。这个区段中的数据在程序运行前将被自动初始化为数字0。堆:用于存放程序运行中被动态分配的内存段。大小可动态扩展或者缩小。malloc就是存放在堆中。栈:是函数执行的内存区域,通常和堆共享同一片区域。通常存放局部变量。堆栈区别:<span style="color: #.堆是由程序员手动申请,栈由系统自动分配。<span style="color: #.堆是由程序员手动释放,栈由系统自动释放。<span style="color: #.堆的生存周期由程序员动态申请到程序员主动释放为止,不同函数之间均可自由访问。栈的生存周期由函数调用开始到函数返回时结束,函数之间的局部变量不能互相访问。<span style="color: #.堆是从低地址向高地址发展,栈是由高地址向低地址发展。例:#include &stdio.h&
#include &stdlib.h&
int main(void)
int *ptr1 = NULL;
int *ptr2 = NULL; //堆栈共享区域。
ptr1 = (int *)malloc(sizeof(int));
ptr2 = (int *)malloc(sizeof(int));
printf("stack: %p -& %p\n", &ptr1, &ptr2);//栈时存放在指针的指向。
printf("heap: %p -& %p\n", ptr1, ptr2);//堆申请完是存放在镇两个指针里面的
getchar();
}结果中看得出栈更加节省空间。三.宏C语言三大预处理:宏定义(替换)、文件包含、条件编译作用:不用改一处而动千发。A.不太参数的宏定义:(替换)#define PI 3.14注:1.宏定义通常由大写字母组成。2.只是简单进行替换并且由于预处理是在编译之前进行,编译器不会对宏定义进行语法检查。3.宏定义不是说明或语句,末尾不必加分号。4.宏定义的作用域是从定义的位置开始到整个程序结束。5.可以用#undef来终止宏定义的作用域。6.宏定义允许嵌套。 B.带参数的宏定义:参数名和函数参数名一样区分。(形式参数、实际参数)例:#include &stdio.h&
//不带参数的宏定义
#define R 6371
#define PI 3.14
#define V PI * R * R * R * 4 / 3
//带参宏定义
#define MAX(x, y) (((x) &(y)) ? (x) : (y))
int main(void)
printf("地球的体积大概是:%.2f\n", V);
//PI作用域结束。
///////////////////////////////////////
printf("请输入两个整数:");
scanf("%d%d", &x, &y);
getchar();
printf("%d是较大的那个数!\n", MAX(x, y));
getchar();
以下写法会发生错误:#define MAX (x, y) (((x) &(y)) ? (x) : (y))与函数的区别:宏没有数据类型,只是机械的替换。而函数的参数使用了堆栈例:#include &stdio.h&
#define SQUARE(X) X * X
int main(void)
printf("请输入一个整数:");
scanf("%d", &x);
getchar();
printf("%d 的平方是:%d\n", x, SQUARE(x));
printf("%d 的平方是:%d\n", x+1, SQUARE(x+1));
getchar();
}结果:请输入一个整数:4
4 的平方是:16
5 的平方是:9&&& //替换成:x + 1 * x + 1、如果在定义时加括号:#define SQUARE(X) ((X) * (X))就不会
一般不建议用宏定义替换函数应有的功能。C.#和##是两个预处理运算符&&&&&&&&&&&&#在带参数的宏定义中,#运算符后面跟一个参数,预处理器会把这个参数转换为一个字符串。在实参的传入中如果存在多个空白字符,如果存在‘’的字符它会自动加上\。例:#include &stdio.h&
#define STR(s) # s
int main(void)
printf("%s\n", STR(Hello));
printf(STR(Hello
%s num = %d\n), STR(世界), 520);
getchar();
&&&&&&&&&&&&####称为记号连接运算符,如:连接两个参数。例:#include &stdio.h&
#define TOGETHER(x, y) x ## y
int main(void)
printf("%d\n", TOGETHER(2, 50));
getchar();
D.可变参数形式:#define SHOWLIST(...) printf(#__VA_ARGS__)//...代表可变参数,#把参数都变为字符串例:#include &stdio.h&
#define SHOWLIST(...) printf(#__VA_ARGS__)
int main(void)
SHOWLIST(世界, 520, 3.14\n);
getchar();
可变参数是允许空参数的。类型:#define SHOWLIST(format, ...) printf(# fromat, ##__VA_ARGS__)例:#include &stdio.h&
#define SHOWLIST(fromat, ...) printf(# fromat, ##__VA_ARGS__)
int main(void)
SHOWLIST(num = %d\n, 520);//只给了fromat参数,可变参数为空
SHOWLIST(hello world!\n);
getchar();
阅读(...) 评论()

我要回帖

更多关于 指针变量是啥? 的文章

 

随机推荐