Chinaunix首页 | 论坛 | 博客
  • 博客访问: 445589
  • 博文数量: 88
  • 博客积分: 2677
  • 博客等级: 少校
  • 技术积分: 893
  • 用 户 组: 普通用户
  • 注册时间: 2009-06-13 08:01
文章分类

全部博文(88)

文章存档

2017年(3)

2016年(1)

2012年(4)

2011年(4)

2010年(57)

2009年(19)

我的朋友

分类: C/C++

2010-02-04 23:20:53

学习(其实算是复习)参考《谭浩强C语言》。
http://blogimg.chinaunix.net/blog/upfile2/100205005915.pdf
http://blogimg.chinaunix.net/blog/upfile2/100205010430.zip

指针
int i = 5,*p = &i;

++*p 相当于 ++(*p)   :6/7/8/9/................p指向的整型变量的值,在+1

*p++ 相当于 *(p++)   :6/?/?/?/?/?.............p变量存放的地址的值,在+1(加一个int型的大小size,不是数学上的+1)
                     *p++,由于++和*同优先级,所以结合方向自右而左。
                     如果p指向的是一个数组,由于数组是连续存储的,那么+1(+一个int型)则是指向下一个元素。
                     如果char *p的话,+1则是+一个char型的大小size;


(*p)++              :5/6/7/8/9/..............p指向的整型变量的值,在+1


2. 指针变量的运算
1) 赋值运算:指针变量的赋值运算有以下几种形式。
    ① 指针变量初始化赋值,前面已作介绍。
    ② 把一个变量的地址赋予指向相同数据类型的指针变量。
    例如:
    int a,*pa;
    pa=&a; /*把整型变量a 的地址赋予整型指针变量pa*/
③ 把一个指针变量的值赋予指向相同类型变量的另一个指针变量。
    如:
        int a,*pa=&a,*pb;
        pb=pa; /*把a 的地址赋予指针变量pb*/
    由于pa,pb 均为指向整型变量的指针变量,因此可以相互赋值
④ 把数组的首地址赋予指向数组的指针变量。
    例如:
        int a[5],*pa;
        pa=a;
    (数组名表示数组的首地址,故可赋予指向数组的指针变量pa)
    也可写为:
        pa=&a[0]; /* 数组第一个元素的地址也是整个数组的首地址,也可赋予pa*/
    当然也可采取初始化赋值的方法
        int a[5],*pa=a;
⑤ 把字符串的首地址赋予指向字符类型的指针变量。
    例如:
        char *pc;
        pc="C Language";  /* pc中仅是字符串的首地址,不是整个字符串,%s格式不能打印,可用%c打印首地址中的字符'C' */
    或用初始化赋值的方法写为:
        char *pc="C Language";
    这里应说明的是并不是把整个字符串装入指针变量,而是把存放该字符串的字符数组的首地址装入指针变 量。在后面还将详细介绍。
    这个是指向字符串的指针变量,还不是指向字符串的指针数组。

⑥ 把函数的入口地址赋予指向函数的指针变量。
    例如:
        int (*pf)();
        pf=f; /*f 为函数名*/

2) 加减算术运算
int buf[10];
int *p ;

p=&buf[0]; /* 相当于 p = buf :p指向数组buf,也是指向buf[0]*/

p=p+2; /*p指向buf[2],即p的值为&buf[2]*/

指针变量的加减运算只能对数组指针变量进行,对指向其它类型变量的指针变量作加减
运算是毫无意义的。

main()
{
    int buf[10],i;
    int *p ;
    /* buf数组赋值{0,1,2,3,4,....,9} */
    for(i=0;i<10;i++)
        buf[i]=i;
    

    /* p指向数组buf,即指向元素buf[0] */
    /* p=buf; */ /* 数组名表示数组的首地址,故可赋予指向数组的指针变量p */
    /* p = &buf[0]; */ /* 数组第一个元素的地址也是整个数组的首地址,也可赋予p */
    p = &buf;
    
    for(i=0;i<10;i++)
    {
        printf("buf[%d]=%d\n", i, *p);
        p++;
/* p指向的是数组,故做加减运算还算有意义 */
    }
}



3) 两个指针变量之间的运算:只有[指向同一数组的两个指针变量之间]才能进行运算,否则运算毫无意义.
   ① 两指针变量相减:两指针变量相减所得之差是两个指针所指数组元素之间相差的元素个数。
      由于指向的是同一数组(一个数组是按元素的长度连续的存放在内存中的),所以[相减]的话,得到的
      是被指向的两个元素之间的元素个数。
      例如:
         

main()
{
    float buf[10];
/* float型数组,每个元素4个字节,未作赋值故值全被自动赋为0 */
    float *pa=&buf[3],*pb=&buf[8];
/* pa指向第4个元素,pb指向第9个元素 */
    
    printf("%d\n", (pb-pa));
/* 打印结果是 5 */

    /* pb-pa: (元素9的地址值 - 元素4的地址值)/4(单个float型数组元素的Byte长度) */
   
/* 例为:(0xFFC6 - 0xFFB2)/4 = 5 */

    /* 这个减运算会去除以"单个元素的Byte长度",请注意 */
}


    pa+pb 相加,毫无意义。

② 两指针变量进行关系运算:指向同一数组的两指针变量进行关系运算可表示它们所指数组元素之间的关系
   例如:
      pf1==pf2 表示pf1和pf2指向的是否为同一数组中的同一元素(也就是存放的地址的数值是否相等);
      pf1>pf2 表示pf1 处于高地址位置(存放的地址的数值是否大);
      pf1
      p==0 表明p是否为空指针,即未指向任何变量;
      p!=0 表示p不是空指针。

#define NULL 0
int *p1=NULL;

printf("%p\n",p1); /* 打印输出结果为:0000或0x0等 */

对指针变量[赋为0值]和[不赋值]是不同的。

指针变量[未赋值]时,可以是任意值,是不能使用的;否则将造成意外错误。
   → gcc会有警告 warning: ‘p1’ is used uninitialized in this function

而指针变量[赋0值]后,则可以使用,只是它不指向具体的变量而已。

指向数组元素的指针
C 语言规定,数组名代表数组的首地址,也就是第0号元素的地址。
在定义指针变量时可以赋给初值:
    int *p=&a[0];
↓它等效于:
    int *p;
    p=&a[0];
↓当然定义时也可以写成:
   int *p=a;

如果p 的初值为&a[0],则:
1) p+i 和a+i 就是a[i]的地址,或者说它们指向a 数组的第i 个元素。
2) *(p+i)或*(a+i)就是p+i 或a+i 所指向的数组元素,即a[i]。例如,*(p+5)或*(a+5)就是a[5]。
3) 指向数组的指针变量也可以带下标,如 p[i]与*(p+i)等价

根据以上叙述,引用一个数组元素可以用:
1) 下标法,即用 a[i]形式访问数组元素。在前面介绍数组时都是采用这种方法。
2) 指针法,即采用*(a+i)或*(p+i)形式,用间接访问的方法来访问数组元素,其中a是数组名,p 是指向数组的指针变量,其处值p=a

几个注意的问题:
1) 指针变量可以实现本身的值的改变。如 p++是合法的;而a++是错误的。因为a 是数组
名,它是数组的首地址,是常量。
→ *p++,由于++和*同优先级,结合方向自右而左,等价于*(p++)
→ *(p++)与*(++p)作用不同。若p 的初值为a,则*(p++)等价a[0],*(++p)等价a[1]
→ (*p)++表示 p 所指向的元素值加1。
→ 如果 p 当前指向a 数组中的第i 个元素,则
    *(p--)相当于a[i--];
    *(++p)相当于a[++i];
    *(--p)相当于a[--i]。



指向多维数组的指针和指针变量
1. 多维数组的地址
设有整型二维数组a[3][4]如下:
    0 1 2 3
    4 5 6 7
    8 9 10 11
它的定义为:
int a[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}}

实际也就是3个一维数组:
a[0]和a[1]和a[2],每个一维数组中有4个元素。

所以:
a 是二维数组名,a 代表整个二维数组的首地址,也是二维数组0 行的首地址
a[0]是第一个一维数组的数组名和首地址
a+1 是二维数组1 行的首地址,等于1008。
a[1]是第二个一维数组的数组名和首地址

由此可得出:a+i,a[i],*(a+i)均和&a[i][0]是等同的。

二维数组中不能把&a[i]理解为元素a[i]的地址,根本不存在元素a[i],只有元素a[i][j]。
a[i],&a[i],*(a+i)和a+i

最后也就是 a+i,a[i],&a[i],*(a+i) 均和&a[i][0]是等同的。


2. 指向多维数组的指针变量

把二维数组a 分解为一维数组a[0],a[1],a[2]之后,设p 为指向二维数组的指针变量。
可定义为:
    int (*p)[4]
它表示p 是一个指针变量,它指向包含4 个元素的一维数组

*(p+i)+j 是二维数组i 行j 列的元素的地址
而*(*(p+i)+j)则是i 行j 列元素的值



字符串的指针指向字符串的针指变量
1) 用[字符数组]存放一个字符串,然后输出该字符串。

main(){
     char string[]=”I love China!”;
     printf("%s\n",string);
}
/* string 是数组名,它代表字符数组的首地址 */


2) 用[字符串指针]指向一个字符串。

main(){
    char *string=”I love China!”;
    printf("%s\n",string);
}

定义string 是一个字符指针变量,然后把字符串的首地址赋予string(应写出整个字符串,以便编译系统把该串装入连续的一块内存单元),并把首地址送入string


使用[字符串指针变量]与[字符数组]的区别
用字符数组和字符指针变量都可实现字符串的存储和运算。但是两者是有区别的
1.
[字符串指针变量]本身是一个变量,用于存放字符串的首地址。而字符串本身是存放在以该首地址为首的一块连续的内存空间中并以‘\0’作为串的结束
[字符数组]是由于若干个数组元素组成的,它可用来存放整个字符串
2.
对[字符串指针方式]:
    char *ps="C Language";
可以写为:
    char *ps;
    ps="C Language";

而对[数组方式]:
    static char st[]={"C Language"};
不能写为:
    char st[20];
    st={"C Language"};
只能对字符数组的各元素逐个赋值

函数指针变量
在C语言中,一个函数总是占用一段连续的内存区,而函数名就是该函数所占内存区的首地址

我们可以把函数的这个首地址(或称入口地址)赋予一个指针变量,使该指针变量指向该函数。然后通过指针变量就可以找到并调用这个函数

函数指针变量定义
    类型说明符 (*指针变量名)();
其中“类型说明符”表示被指函数的返回值的类型
“(* 指针变量名)”表示“*”后面的变量是定义的指针变量
最后的空括号()表示指针变量所指的是一个函数

例如:
int (*pf)();


int max(int a,int b){
     if(a>b)return a;
     else return b;
}
main(){
     int max(int a,int b);
     int(*pmax)();
/* 定义 pmax 为 函数指针变量 */
     int x,y,z;


     pmax=max;
/* 把被调函数的入口地址(函数名) 赋予 该函数指针变量 */
     printf("input two numbers:\n");
     scanf("%d%d",&x,&y);
     z=(*pmax)(x,y);
/* 函数指针变量形式 调用函数 :(*指针变量名) (实参表) */

                   /* 函数指针变量不能进行算术运算,与数组指针变量不同,函数指针的移动是毫无意义 */
                   /* 函数调用中"(*指针变量名)"的两边的括号()不可少 */

     printf("maxmum=%d",z);
}



指针型函数

所谓函数类型就是指函数返回值的类型
例如:
    int foo(){...}  :int 指的是函数返回值的数据类型。

在C语言中允许一个函数的返回值是一个指针(即地址),这种返回指针值的函数称为指针型函数
例如:

int *ap(int x,int y)
{
     ......  /* 函数体 */
}
/* ap 是一个返回指针值的指针型函数,它返回的指针指向一个整型变量。 */


实际上如果我们在写程序的时候:
将 int *ap(){...}   写成   int* ap(){...} 的话,貌视便于理解。

main(){
     int i;
     char *day_name(int n);
/* 定义 指针函数 */
     printf("input Day No:\n");
     scanf("%d",&i);
     if(i<0) exit(1);
/* exit(1)表示发生错误后退出  exit(0)表示正常退出 */
     printf("Day No:%2d-->%s\n",i,day_name(i));

     /* day_name(i) 的返回值指向一个字符串 ,该函数中定义了一个静态指针数组name */
}
char *day_name(int n){
     static char *name[]={ "Illegal day",
                           "Monday",
                           "Tuesday",
                           "Wednesday",
                           "Thursday",
                           "Friday",
                           "Saturday",
                           "Sunday"};
     return((n<1||n>7) ? name[0] : name[n]);

}


应该特别注意的是[函数指针变量]和[指针型函数]这两者在写法和意义上的区别

    int(*p)() 和 int *p() 是两个完全不同的量。

int (*p)() 是一个变量说明,说明p 是一个指向函数入口的指针变量,该函数的返回值是整型量,(*p)的两边的括号()不能少

int *p() 则不是变量说明而是函数说明,说明p 是一个指针型函数,其返回值是一个指向整型量的指针,*p 两边没有括号。作为函数说明,在括号内最好写入形式参数,这样便于与变量说明区别。
int *p()只是函数头部分,一般还应该有函数体部分。

[指针数组]和[指向指针的指针]

一个数组的元素值为指针则是[指针数组]。
指针数组是一组有序的指针的集合
指针数组的所有元素都必须是具有相同存储类型指向相同数据类型的指针变量。

    类型说明符 *数组名[数组长度]
类型说明符为指针值所指向的变量的类型
例如:
    int *pa[3]
表示pa 是一个指针数组,它有三个数组元素,每个元素值都是一个指针指向整型变量

应该注意[指针数组]和[二维数组指针变量]的区别:

[二维数组指针变量]是单个的变量,其一般形式中"(*指针变量名)"两边的括号不可少。
而指针数组类型表示的是多个指针(一组有序指针)在一般形式中"*指针数组名"两边不能有括号。
例如:
    int (*p)[3];
表示一个指向二维数组的指针变量。该二维数组的列数为3 或分解为一维数组的长度为3

    int *p[3]
表示p 是一个指针数组,有三个下标变量p[0],p[1],p[2]为指针变量

char *name[]={"Illagal day",
              "Monday",
              "Tuesday",
              "Wednesday",
              "Thursday",
              "Friday",
              "Saturday",
              "Sunday"};

/* name[0] 即指向字符串"Illegal day",name[1]指向"Monday"......。 */


[指针数组]也可以用作函数参数。


main(){
     static char *name[]={ "Illegal day",
/* 定义 指针数组 */
                           "Monday",
                           "Tuesday",
                           "Wednesday",
                           "Thursday",
                           "Friday",
                           "Saturday",
                           "Sunday"};
     char *ps;
     int i;
     char *day_name(char *name[],int n); /* 定义 指针函数 */
     printf("input Day No:\n");
     scanf("%d",&i);
     if(i<0) exit(1);
     ps=day_name(name,i);
     printf("Day No:%2d-->%s\n",i,ps);
}


char *day_name(char *name[],int n)
/* 指针数组 作为 形式参数 */
{
     char *pp1,*pp2;
     pp1=*name;
     pp2=*(name+n);
     return((n<1||n>7)? pp1:pp2);
}




指向指针的指针

如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。

通过指针访问变量称为间接访问。由于指针变量直接指向变量,所以称为“单级间址”。

如果通过指向指针的指针变量访问变量则构成“二级间址”。

指针变量                  变量
┌-----┐                 ┌---┐
| 地址   ------------->   值
└-----┘                 └---┘

指针变量1                 指针变量2                 变量
┌------┐                 ┌-----┐                 ┌---┐
| 地址1   ------------->   地址2   ------------->   值
└------┘                 └-----┘                 └---┘

定义一个指向指针型数据的指针变量
    char **p;
p 前面有两个*号,相当于*(*p)

使用指向指针的指针

main()
{

    /* 定义 指针数组 */
    char *name[]={"Follow me","BASIC","Great Wall","FORTRAN","Computer desighn"};
    char **p;
/* 定义 指向指针的指针 */
    int i;
    for(i=0;i<5;i++)
    {

        p=name+i; /* 指针变量p 指向 指针数组的第i元素 ,该元素 指向 "string"的首地址 */
        printf("%s\n",*p);
    }
}


main()
{

    static int a[5]={1,3,5,7,9};
    int *num[5]={&a[0],&a[1],&a[2],&a[3],&a[4]};/* 指针数组的元素只能存放地址 */
    int **p,i;

    p=num;

    for(i=0;i<5;i++)
    {

        printf("%d\t",**p);p++;

    }
}



main 函数的参数

main函数可以带参数,这个参数可以认为是 main 函数的形式参数

习惯上这两个参数写为argc 和argv。
C语言还规定:
argc(第一个形参)必须是整型变量,
argv( 第二个形参)必须是指向字符串的指针数组。
加上形参说明后,main 函数的函数头应写为:
    main (int argc,char *argv[])

由于main 函数不能被其它函数调用,因此不可能在程序内部取得实际值。那么,在何
处把实参值赋予main 函数的形参呢?
实际上,main 函数的参数值是从操作系统命令行上获得的。
shell命令:
    执行文件名  参1 参2 目标文件

argc 参数表示了命令行中参数的个数(注意:文件名本身也算一个参数),argc 的值是在输入命令行时由系统按实际参数的个数自动赋予的。
例如有命令行为:
    C:\>E24 BASIC foxpro FORTRAN
所以共有4 个参数,因此argc 取得的值为4
argv 参数是字符串指针数组,其各元素值为命令行中各字符串(参数均按字符串处理)的首地址。




int main (int argc,char *argv[]){...}  和 int main (int argc,char **argv){...}  的区别:

char *argv[] 的含义,是一个未指定长度的指针数组,其元素值都是被指向的字符串的首地址,长度由系统给出(就是 argc 的值)。
单级间址

而char **argv的含义,是一个指向指针的指针变量,其存放的值是另一个指针变量的地址
其实其相当于
char*argv[];
char **p; /* char*(*p); */
p = argv; /* 变量p中存放的是 数组argv的首地址 */

所以也就写成了 char **argv /* char*(*argv) */
二级间址


void 指针类型
ANSI 新标准增加了一种“void”指针类型,即可以定义一个指针变量,但不指定它是指向哪一种类型数据




结构指针变量的说明和使用

指向结构变量的指针
一个指针变量当用来指向一个结构变量时,称之为结构指针变量。
结构指针变量中的值是所指向的结构变量首地址
结构指针变量说明的一般形式为:
    struct 结构名 *结构指针变量名
例如:
    struct stu *pstu;
当然也可在定义stu 结构时同时说明pstu。
与前面讨论的各类指针变量相同,结构指针变量也必须要先赋值后才能使用。
(就像指向数组的指针变量,指向字符串的指针变量,指向函数的指针变量)

赋值是把结构变量的首地址赋予该指针变量,不能把结构名赋予该指针变量

boy是被说明为stu类型的结构变量:
pstu=&boy    是正确的。
pstu=&stu    是错误的。
stu是结构体类型名,而boy才是该结果体类型的结构体变量

其访问的一般形式为:
    (*结构指针变量).成员名
或为:
    结构指针变量->成员名

例如:
    (*pstu).num
或者:
    pstu->num

struct stu /* 定义了一个 结构体类型 */
{
     int num;
     char *name;
     char sex;
     float score;
} boy1={102,"Zhang ping",'M',78.5},*pstu;
/* 同时定义了一个该类型的结构体变量并赋初值 */

/* 也定义了一个指向该结构体变量boy1的 结构体指针变量pstu */

main()
{
     pstu=&boy1;
     printf("Number=%d\nName=%s\n",boy1.num,boy1.name);
     printf("Sex=%c\nScore=%f\n\n",boy1.sex,boy1.score);
     printf("Number=%d\nName=%s\n",(*pstu).num,(*pstu).name);
     printf("Sex=%c\nScore=%f\n\n",(*pstu).sex,(*pstu).score);
     printf("Number=%d\nName=%s\n",pstu->num,pstu->name);
     printf("Sex=%c\nScore=%f\n\n",pstu->sex,pstu->score);
}


输出结果都是相同的,可以看出:
    结构变量.成员名
    (*结构指针变量).成员名
    结构指针变量->成员名
这三种用于表示结构成员的形式是完全等效的。


指向结构数组的指针
指针变量可以指向一个结构数组。 (结构数组是什么?)
这时结构指针变量的值是整个结构数组的首地址

设ps 为指向结构数组的指针变量,则ps 也指向该结构数组的0 号元素,ps+1 指向1 号元素ps+i 则指向i 号元素
这与普通数组的情况是一致的。

struct stu /* 定义了一个 结构体类型 */
{
     int num;
     char *name;
     char sex;
     float score;
}boy[5]={
                /* 同时定义了一个结构体数组,就是每个元素都是该结构体类型 */
            {101,"Zhou ping",'M',45},
            {102,"Zhang ping",'M',62.5},
            {103,"Liou fang",'F',92.5},
            {104,"Cheng ling",'F',87},
            {105,"Wang ming",'M',58},
        };


main()
{
     struct stu *ps;
/* 定义了一个 该结构体类型的指针变量 */
     printf("No\tName\t\t\tSex\tScore\t\n");
     for(ps=boy;ps<boy+5;ps++)/* 指针变量中 存放 整个结构体数组boy的首地址 */
     printf("%d\t%s\t\t%c\t%f\t\n",ps->num,ps->name,ps->sex,ps->score);
}


应该注意的是,一个结构指针变量虽然可以用来访问 结构变量结构数组元素的成员
但是,不能使它指向一个成员。也就是说不允许取一个成员的地址来赋予它。
因此,下面的赋值是错误的。
    ps=&boy[1].sex;
而只能是:
    ps=boy;(赋予数组首地址)
或者是:
    ps=&boy[0];(赋予0 号元素首地址)


结构指针变量作函数参数

在 ANSI C 标准中允许用结构变量作函数参数进行整体传送
但是这种传送要将全部成员逐个传送,特别是成员为数组时将会使传送的时间和空间开销很大,严重地降低了程序的效率。

因此最好的办法就是使用指针,即用指针变量作函数参数进行传送。这时由实参传向形参的只是地址,从而减少了时间和空间的开销。

struct stu   /* 定义了一个 结构体类型 */
{
     int num;
     char *name;
     char sex;
     float score;}boy[5]=/* 同时定义了一个结构体数组,就是每个元素都是该结构体类型 */
                              {101,"Li ping",'M',45},
                              {102,"Zhang ping",'M',62.5},
                              {103,"He fang",'F',92.5},
                              {104,"Cheng ling",'F',87},
                              {105,"Wang ming",'M',58},
                         };


main()
{
     struct stu *ps; /* 定义了一个 该结构体类型的指针变量 */
     void ave(struct stu *ps);
     ps=boy; /* 指针变量中 存放 整个结构体数组boy的首地址 */
     ave(ps); /* 该结构体类型的指针变量 作为形式参数 开始传递 */
}
void ave(struct stu *ps)
{
     int c=0,i;
     float ave,s=0;
     for(i=0;i<5;i++,ps++)
     {
          s+=ps->score;
          if(ps->score<60) c+=1;
     }
     printf("s=%f\n",s);
     ave=s/5;
     printf("average=%f\ncount=%d\n",ave,c);
}



动态存储分配

在数组一章中,曾介绍过数组的长度是预先定义好的,在整个程序中固定不变。C语言中不允许动态数组类型

例如:
    int n; /* 定义整型变量 n */
    scanf("%d",&n); /* 外部输入 n 的值 */
    int a[n]; /* 利用 n 的值,来定义相应长度的数组 */
变量表示长度,想对数组的大小作动态说明,这是错误的

但是在实际的编程中,往往会发生这种情况,即所需的内存空间取决于实际输入的数据,而无法预先确定
对于这种问题,用数组的办法很难解决。为了解决上述问题,C语言提供了一些内存管理函数,这些
内存管理函数可以按需要动态地分配内存空间,也可把不再使用的空间回收待用,为有效地利用内存资源提供了手段。

常用的内存管理函数有以下三个:
1. 分配内存空间函数 malloc
调用形式:
     (类型说明符*)malloc(size)
功能:在内存的动态存储区中分配一块长度为"size"字节的连续区域。函数的返回值为该区域的"首地址"
“类型说明符”表示把 该区域用于何种数据类型
(类型说明符*)表示把返回值强制转换为该类型指针
“size”是一个无符号数。
例如:
    char *pc;
    pc=(char *)malloc(100);
表示分配100 个字节的内存空间,并强制转换为"字符数组类型"
函数的返回值为指向该字符数组的指针,把该指针赋予指针变量pc

2. 分配内存空间函数 calloc
calloc 也用于分配内存空间。
调用形式:
    (类型说明符*)calloc(n,size)
功能:在内存动态存储区中分配 n 块长度为“size”字节的连续区域。函数的返回值为该区域的"首地址"
(类型说明符*)用于强制类型转换。
calloc 函数与malloc 函数的区别 仅在于"一次"可以分配 "n 块"区域。
例如:
    struet stu *ps;
    ps=(struet stu*)calloc(2,sizeof(struct stu));

其中的sizeof(struct stu)是求stu 的结构长度。

语句的意思就是:按"stu 的长度"分配"2 块连续区域",强制转换为stu 类型,并把其首地址赋予指针变量ps。

3. 释放内存空间函数 free
调用形式:
free(void*ptr);
功能:释放ptr 所指向的一块内存空间,ptr 是一个任意类型的指针变量,它指向被释放区域的首地址
被释放区应是由malloc 或calloc 函数所分配的区域。



main()
{
     struct stu 
/* 定义了一个 结构体类型 */
     {
          int num;
          char *name;
          char sex;
          float score;
     } *ps;/* 也定义了一个指针变量pstu,其指向地址中的数据的类型是stu结构体类型  */


     /* 按结构体类型分配了 1个 结构体大小的连续存储空间  */

    /* 该连续存储空间的首地址,存放在指针变量ps中  */
     ps=(struct stu*)malloc(sizeof(struct stu));

   
     ps->num=102;
     ps->name="Zhang ping";
     ps->sex='M';
     ps->score=62.5;
     printf("Number=%d\nName=%s\n",ps->num,ps->name);
     printf("Sex=%c\nScore=%f\n",ps->sex,ps->score);


     free(ps);/* 不在使用该连续空间中的数据,故释放,节省内存空间资源  */
}


整个程序包含了:
申请内存空间、
使用内存空间、
释放内存空间、
三个步骤,实现存储空间的动态分配。



阅读(1525) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~