首先应该明白对象的三种内部的存储方式:自动存储,静态存储,和动态存储。当执行离开当期程序块的时候,堆栈指针返回到它进入程序块
之前的地方,有效的销毁了那个程序块的自动变量。重新进入这个块会再次创建所有的自动变量。静态对象声明或者在文件域中。动态对象是存在系统调用
的在运行期中创建并且保存在堆中,这是一种特殊的留给用户控制的数据区。
下面是C++/C中常见的动态内存的技术
1.参差数组
//在编译期间并不知道多大空间存储一个对象使用堆栈很方便
//在C中处理文本文件习惯是为文本每一行分配堆栈空间,在一个指向char类型的指针数组里面存储地址
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define MAXLINE 1024
static int scomp(const void*,const void*);
int main(int argc,char**argv){
int i,n;
char*strings[MAXLINE],buf[BUFSIZ];
if (argc>1)
freopen(argv[1],"r",stdin);
for (n=0;n<MAXLINE&&fgets(buf,BUFSIZ,stdin);++n)
{
strings[n] = (char*)malloc(strlen(buf)+1);
assert(strings[n]);
strcpy(strings[n],buf);
}
qsort(strings,n,sizeof strings[0],scomp);
for (i=0;i<n;++i)
{
fputs(strings[i],stdout);
free(strings[i]);
}
return 0;
}
static int scomp(const void* p1,const void* p2){
char *a = *(char**)p1;
char *b = *(char**)p2;
return strcmp(a,b);
}
2.在标准C中使用堆
头文件<stdlib.h>使用动态分配声明了4个函数
1.void*malloc(size_t,siz);返回一个指向siz大小的第一个字节的指针通常分配单个对象
2.void*calloc(size_t nelems,size_t elem_size)返回指向nelems*elem_size字节的指针通常分配对象数组
3.void*realloc(void*ptr,size_t siz);用于扩展或者缩小堆栈的分配ptr必须源于上次malloc,calloc或者realloc调用
4.void free(void*ptr)使用以前分配的堆栈内存去可以重用
1.void*malloc(size_t,siz);返回一个指向siz大小的第一个字节的指针通常分配单个对象
2.void*calloc(size_t nelems,size_t elem_size)返回指向nelems*elem_size字节的指针通常分配对象数组
3.void*realloc(void*ptr,size_t siz);用于扩展或者缩小堆栈的分配ptr必须源于上次malloc,calloc或者realloc调用
4.void free(void*ptr)使用以前分配的堆栈内存去可以重用
//getargs.c
#include <stdio.h>
//返回一个指针指向动态分配大小的。字符串的参差数组
extern char**arglist(int ,char**,int*);
extern void free_arglist(int ,char**);
int main(int argc,char**argv){
int i,nargs;
char**args = arglist(--argc,++argv,&nargs);
for (i=0;i<nargs;++i)
printf("%d: %s\n",i,args[i]);
free_arglist(nargs,args);
return 0;
}
//arglist.c从文件递归的读取参数
//从文件递归的读取参数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define CHUNK 10 //重新分配的数量
static char**args;//参数列表
static int nleft;//不同的参数位置
static int nargs;//参数的数量
//私有函数
//用于处理间接文件参数
static void expand(FILE*f);
static void add(char*arg);
char**arglist(int old_nargs,char** old_args,int* new_nargs){
int i;
//最初的分配
args = (char**)calloc(old_nargs,sizeof(char*));//分配字符串数组
assert(args);
nleft = old_nargs;
nargs = 0;
//处理每个命令行参数
for (i=0;i<old_nargs;++i)
{
if (old_args[i][0] == '@')
{
//打开参数文件
FILE*f = fopen(old_args[i]+1,"r");
if (f)
{
expand(f);
fclose(f);
}
}
else
add(old_args[i]);
}
*new_nargs = nargs;
return args;
}
void free_arglist(int n,char**av){
int i;
for (i=0;i<n;++i)
free(av[i]);
free(av);
}
//从文件中继续解析命令行参数
static void expand(FILE*f){
char token[BUFSIZ];
while(fscanf(f,"%s",token)==1)
if (token[0] =='@')
{
FILE* g = fopen(token+1,"r");
if (g)
{
expand(g);
fclose(g);
}
}
else
add(token);
}
//加入新的命令行参数6
static void add(char*arg){
if (nleft==0)
{
//扩大参数列表
args = (char**)realloc(args,(nargs+CHUNK)*sizeof(char*));
assert(args);
nleft = CHUNK;
}
//为存储参数分配空间
args[nargs] = (char*)malloc(strlen(arg)+1);
assert(args[nargs]);
strcpy(args[nargs++],arg);
--nleft;
}