C语言——第六章

一.

变量存储空间的分类顺序

先声明的变量后分配存储空间;撤销的顺序与之相反:先建立的后撤销。这种机制就称为栈机制,好像往一个只能允许进出一个盘子的桶里放盘子,先放进的后拿出。在C语言程序中,局部变量就被分配在栈区,而且是以高端为栈底建立的。所以后建变量的地址较小。

每个变量只有一个地址,但占用的空间不同


二.

一个指针所指连变量的类型,称为该指针的基类型。


三.

指向void类型的指针void *p;这表示指针变量不指向某一确定类型的数据。它的作用仅仅是用来存放一个地址,而不能指向非void类型的变量。例如,下面的写法是错误的。

int *p1;

void *p2;

int i;

p2 = &i;

printf("%d", *p2);

如果确实需要将&i的值放在p2中,应先进行强制类型转换,使之成为(void *)类型,再将p2赋值给p1时,同样应进行强制类型转换。

p2 = (void *)&i;

p1 = (int *)p2;

printf("%d", *p1);

注意:执行p1=(int *)p2之后,p2本身的类型并未改变。只是在向p1赋值前先进行强制类型转换,生成一个(int *)类型的临时数据赋值给p1


四.

#include<stdio.h>

int main()

{

int a[5] = {1, 3, 5, 7, 9}, i, *p;

printf("下标法:");

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

printf("%d,", a[i]);

printf("\n数组名法:");

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

printf("%d,", *(a + i));

printf("\n指针变量法:");

for(p = a; p < a + 5; ++p)

printf("%d,", *p);

printf("\n");

return 0;

}

虽然上面三种方法都能输出同样的结果,但它们的执行效率是不同的。用下标法访问数组元素时,是把a[i]转换成*(a+i)进行计算的,即先计算出数组元素的地址(a+i),然后再找到它所指的存储单元,读出或写入它的值。而用指针变量p指向数组元素时则不必每次都计算数组元素地址。特别是使用p++这样的操作是速度比较快的。


五.

char str[M][N];

char *str[N];

char **str;

1.char str[M][N],在这个声明中,有两个相同的数组类型说明符[],按照从左到右的结核性,额可以首先确定str是一个大小为M的向量(一维数组)。对于数组,自然要说明其类型,由char[N]补充说明,这个数组是长度为N的字符数组类型,即它的每个元素都是长度为N的字符数组。用这种方式存储的几个字符串占有连续的存储空间。

2.char *str[N],在这个声明中,有两个不同的数组类型生命符[]*。其中数组类型生命符的优先级别高,可首先确定str是一个大小为N的一维数组。余下的char*补充说明:这个数组的每个元素都是字符类型指针。采用这种方式存储的几个字符串的长度可以不同,不一定占有连续的存储空间。

3.char **str,在这个声明中,有两个相同的类型生命符*。按照自右向左的结合性,可以首先将后面的一个*与名字相结合,得出结论:str是一个指针。对于指针,就要声明它指向什么。由余下的char*补充声明,这个指针是指向字符指针的。

用二维字符数组存储,需要按照最长字符串开辟存储空间,而用字符串数组(即字符指针数组)存储时,可以为不同长度的字符串开辟不同长度的存储空间。采用字符串数组来存储字符串不进可以节省空间,还可以提高执行效率。例如,对存储的字符串进行交换,如果是二维数组存储,必须实际交换所存储的字符串,而采用字符指针数组则只需要交换两指针变量的值,不需要实际移动字符串。


六.P212

全局变量是在编译时在内存静态存储区分配的,非静态的局部变量是程序运行是在栈区自动分配的,而为指针所进行的内存空间动态分配是在程序运行过程中在自由内存区——堆(heap)区分配的。堆可以形成比较大的存储空间,供动态分配使用。

动态分配的特点是,可以由程序员控制,在需要时分配,在不需要时释放,还可以根据具体需要改变所分配存储空间的大小。

以下四个函数包含在stdlib.h中。

1malloc函数,其函数原型为:

void * malloc(unsigned int size)

其作用是在内存的动态存储区中分配一个长度为size的连续空间,函数的返回值是所分配区域的第一个字节的地址。

2calloc函数,其函数原型为:

void * calloc(unsigned n,unsigned size)

其作用是在内存的动态存储区中分配n个长度为size的连续空间,一般用来保存一个数组(n为数组元素的个数,每个数组元素长度为size,这就是动态数组),函数返回指向所分配域的起始位置的指针。如果分配不成功,返回NULL

3free函数,其原型为:

void free(void * pointer)

其作用是释放指针变量p所指向的动态空间,使这部分空间能重新被其他变量使用。pointer应是最近一次调用callocmalloc函数所得到的函数返回值。free函数没有返回值。

4realloc函数,其原型为:

void * realloc(void * pointer,unsigned int size)

对已使用malloc函数或calloc函数获得的动态空间进行重新分配。如果重新分配不成功,返回NULL

说明:

1.因为void *p说明pvoid*类型的指针,声明其类型是未确定的类型,可以通过强制转换的方法将其转换为任何其他类型。例如

double *pd=NULL;

pd = (double *)calloc(10,sizeof(double));

并且通过(double*)calloc()的返回类型进行强制类型转换,以便把double类型数据的地址赋值给指针pd 

2.使用sizeof的母的是用来计算一种类型所占有的字节数,以便适合不同的编译器。

3.由于动态分配不一定成功,为此要附加一段异常处理程序,不致程序运行停止

if(p == NULL)

{

printf("No enough memory!\n");

exit(1);

}


七.

其实main函数也可以有参数。有参数的main函数的原型为

 int main(int argc, char *argv[]);

也就是说,带参数main函数的第一个形参argc是一个整型变量,第二个形参argv是一个指针数组,其每个元素都指向字符型数据(即一个字符串)。

这两个参数的值从哪里传递而来呢?main函数是主函数,它不能被程序中的其他函数调用,因此显然不可能从其他函数向它传递所需要的参数值,只能从程序以外传递而来。也就是在启动一个程序时,从程序的命令行中给出。


八.

main()

{

int a[5];

int i;

for(i = 0; i < 5; ++i, ++a)

printf("%d", *a);

}

这段程序看起来没错,但是仔细一看,或者一运行就会发现有错误。因为a++的使用而导致了这种情况的发生。因为a代表数组的起始地址,是一个常量。而常量是不能进行自加运算的。所以a++是错误的。如果a只是一个函数里面的形参,那么就可以作为一个指针变量就可以进行自加运算了。


九.

利用指针实现各种函数,如:strcpy, strlen, stringcat, stringchr, delchar等。。


十.

一个函数包括一系列指令,在内存中占据一片存储单元,它有一个起始地址,即函数的入口地址,通过这个地址可以找到该函数。也可以定义一个指针变量,使它的值等于函数的入口地址,通过这个指针变量也能调用此函数,这个指针变量称为指向函数的指针变量。例如:

int (*p)();表示p指向一个“返回正兴致的函数”。注意*p两侧的括号不能省略,如果写成“int *p()”就变成“返回指针值的函数”了。

可以用指向函数的指针变量作为被调用函数的实参。由于该指针变量是指向某一函数的,因此先后使指针变量指向不同的函数,就可以在被调函数中调用不同的函数。


十一.

有人可能会认为,实现不同的功能时直接调用不同的函数即可,例如在main函数中直接调用几个函数即可,何必通过一个函数借助传递函数地址的方式实现呢?的确,如果程序功能很简单,可以不通过这种方法。但是在一些较为复杂的问题中,以函数地址作为参数的优越性就比较明显了。。。比如求一个函数的定积分。显然,如果不采用这种方法,而分别编写求解某函数定积分的函数,将是十分麻烦的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值