1、全局变量
全局变量在该程序代码中的所有函数中可见,如果你是在程序代码开头就定义了一个变量,则该变量的内容在其代码段中的所有函数中都是可见的。我们可以通过以下的程序代码进行验证。
点击(此处)折叠或打开
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
-
int i;
-
void print_i ()
-
{
-
printf("=== i+1 = %d ===\n",i+1);
-
}
-
-
int main ( void )
-
{
-
i = 1;
-
printf( " ==== %d ====\n",i);
-
print_i();
-
return 0;
- }
我们在 main 函数和 print_i 函数中并没有定义 i 变量,而是在这个程序代码的{BANNED}最佳前面定义了一个整型的变量 i 。
2、消息队列
这个我就不通过代码进行举例了,消息队列不仅仅是可以在不同的函数间传递内存信息,还可以在不同的进程间传递内存信息。
3、管道
管道也是基本功,我也就不再通过程序代码进行举例说明了,同样的,通过管道也不仅仅是可以在不同的函数间传递内存信息,也同样可以在不同的进程间传递内存信息。
4、共享内存
共享内存不仅仅是可以在函数之间传递内存信息,还可以在不同的进程间传递内存信息。
5、通过参数在不同的函数间传递内存信息。
点击(此处)折叠或打开
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
-
void create_mem(char **s)
-
{
-
*s = (char *)malloc(sizeof(char)*65535);
-
if ( s == NULL )
-
printf("=== malloc error ... ===\n");
-
}
-
-
int main ( void )
-
{
-
int i = 0;
-
char *s;
-
-
for ( i = 0 ; i <100000000 ; i++ )
-
{
-
printf("== %d ==\n",i);
-
create_mem(&s);
-
free(s); s=NULL;
-
}
-
return 0;
- }
这里我们要注意两个方面:
a、通过参数来进行内存信息的传递时,如果我们需要在被调用的函数中对传入的参数变量进行内容修改,我们需要传入该参数的地址,而不是传入该参数本身。
比如此例,我们在 main 函数中定义了一个 char *s ,如果我们要在 create_mem 函数中对这个字符指针进行内存分配的话,我们就需要在 create_mem 函数的参数中定义一个指向 char 类型的指针的指针,在调用的时候,我们将 s 的地址传进去,否则程序会 coredump 。
b、通过被调用的子函数 create_mem 内进行的内存分配,由于 create_mem 函数中要将对 s 的改变通过参数返回来,因此在子函数中不能进行 free 操作,则在调用 create_mem 的父函数中,必须执行 free(s); 和 s=NULL; 的操作,否则在多次进行内存分配后,会造成内存分配失败。这种情况经常会发生在重复调用 create_mem 函数的时候。
我们通过如下代码加以验证:
点击(此处)折叠或打开
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
-
void create_mem(char **s)
-
{
-
*s = (char *)malloc(sizeof(char)*65535);
-
if ( s == NULL )
-
printf("=== malloc error ... ===\n");
-
}
-
-
int main ( void )
-
{
-
int i = 0;
-
char *s;
-
-
for ( i = 0 ; i <100000000 ; i++ )
-
{
-
printf("== %d ==\n",i);
-
create_mem(&s);
-
// free(s); s=NULL;
-
}
-
return 0;
- }
6、通过返回值来实现在函数间传递内存信息。
点击(此处)折叠或打开
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
-
-
char *create_mem();
-
-
-
-
int main ( void )
-
{
-
char *s;
-
long i = 0;
-
-
-
for ( i = 0 ; i < 100000000 ;i++ )
-
{
-
s = create_mem();
-
printf("== %d == %s\n",i,s);
-
free(s); s = NULL;
-
}
-
-
}
-
-
char *create_mem()
-
{
-
char *str;
-
-
str = ( char *)malloc(sizeof(char)*65535);
-
-
if ( str == NULL )
-
printf("== malloc faild ==\n");
-
else
-
snprintf(str,40,"This is test for malloc function \n");
-
return str;
- }
通过以上的分析,我们要注意如下的情况:
通过返回值来进行函数间的内存信息传递时,由于内存是在子函数中分配的,那么父函数中定义的 char *s 的指针指向了子函数 create_mem 的返回值,也就是子函数中定义的 char *str 的地址。由于在子函数中不能执行 free(str); 和 str=NULL; 操作(因为执行了这两个操作,str 的内存就被释放和清理了,也就无法返回 str 的值了),因此我们需要在父函数中进行 free(s);和 s=NULL;的操作(实际上就相当于是在 create_men 函数中执行的 free(str); 和 str=NULL;进行了针对 char *str 的内存释放和清理,只是内存释放和清理是在将 str 的值返回给父函数后再执行的。)。
我们再来观察如下代码:
点击(此处)折叠或打开
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
-
-
char *create_mem();
-
-
-
-
int main ( void )
-
{
-
char *s;
-
long i = 0;
-
-
-
for ( i = 0 ; i < 100000000 ;i++ )
-
{
-
s = create_mem();
-
printf("== %d == %s\n",i,s);
-
// free(s); s = NULL;
-
}
-
-
}
-
-
char *create_mem()
-
{
-
char *str;
-
-
str = ( char *)malloc(sizeof(char)*65535);
-
-
if ( str == NULL )
-
printf("== malloc faild ==\n");
-
else
-
snprintf(str,40,"This is test for malloc function \n");
-
return str;
- }
这一段代码也能执行,但是在执行一段时间后会报错,原因就是在不停的嗲用 create_men 进行内存分配,由于内存分配始终没有释放,经过一段时间的运行后,内存会报错。
几个启示:
1、在两个函数中,不管是通过参数传递还是通过返回值传递某个内存信息,其在子函数中分配的内存并不会跟随着子函数的退出而消失,必须在父函数中进行清理,否则随着子函数的多次调用,有可能造成内存泄漏或者是内存分配失败,导致程序运行出现混乱,严重的会造成程序崩溃或者是操作系统崩溃。
2、通过参数在不同的函数中进行内存信息传递时,如果你需要在子函数中改变传入的参数值,那么你需要传递的是这个参数的地址,而不应该是参数变量本身。
这一点我们分别通过如下的两个函数来进行验证。
函数 1 :
点击(此处)折叠或打开
-
#include <stdio.h>
-
#include <stdlib.h>
-
-
void add_one(int *j)
-
{
-
i = j+1;
-
}
-
-
int main ( void )
-
{
-
int i;
-
add_one(&i);
-
printf(" == i + 1 = %d ==\n",i);
-
return 0;
- }
这个地方我们在 main 函数中定义的是 int i; 变量,我们传入到 add_one 函数中时,传入的是指向 i 变量的地址,而我们在 add_one 函数中定义的接收这个变量的是一个指针。假设我们进行如下修改:
点击(此处)折叠或打开
-
#include <stdio.h>
-
#include <stdlib.h>
-
-
void add_one(int j)
-
{
-
i = j+1;
-
}
-
-
int main ( void )
-
{
-
int i;
-
add_one(i);
-
printf(" == i + 1 = %d ==\n",i);
-
return 0;
- }
原因是我们传入的参数 i ,但是在子函数 add_one 中,会将该变量当作是一个静态的变量,对于一个静态的不可修改的内存区域进行更改,会导致程序 coredump 。
函数 2
点击(此处)折叠或打开
-
#include <stdio.h>
-
#include <stdlib.h>
-
-
void update_str(char **str)
-
{
-
snprintf(*str,64,"%s\n","This is a menory test");
-
}
-
-
int main ( void )
-
{
-
char *s;
-
s = ( char *)malloc(sizeof(char)*65);
-
update_str(&s);
-
printf("%s\n",s);
-
free(s);s=NULL;
-
return 0;
- }
这个程序里面,我们在父函数 main 中定义了一个字符指针 char *s; 我们希望这个字符指针指向的地址可以被赋值并保存一个字符串。这个时候我们进行了内存分配,并通过调用 update_men 函数对 char *s 指向的内存地址区间进行了赋值。我们可以看到,我们传入 update_str 函数的,是这个指针的地址,而不是这个指针本身。
同样的,我们在 update_str 函数中,我们定义的参数是一个指向了 str 字符串的指针,即 char **str , 同时,我们在进行赋值操作时,我们是对 *str 进行的赋值操作,也就是指向的这个字符串的内存地址位置进行的赋值操作。
假设我们对该程序进行如下修改:
点击(此处)折叠或打开
-
#include <stdio.h>
-
#include <stdlib.h>
-
-
void update_str(char *str)
-
{
-
snprintf(*str,64,"%s\n","This is a menory test");
-
}
-
-
int main ( void )
-
{
-
char *s;
-
s = ( char *)malloc(sizeof(char)*65);
-
update_str(s);
-
printf("%s\n",s);
-
free(s);s=NULL;
-
return 0;
- }
则程序的执行会报错。