第4章 数组和指针的常用方法

来源:互联网 发布:it精英 编辑:程序博客网 时间:2024/05/29 19:11

4.1 基本使用方法

4.1.1 以函数返回值之外的方式来返回值

大型程序中,经常需要通过返回值返回程序处理的状态(比如是否成功,如果失败,还需要返回失败的原因)。

如果将指针作为参数传递给函数,此后在函数内部对指针指向的对象填充内容,就可以从函数返回多个值。

#include<stdio.h>void func(int *a,double *b) {*a=5;*b=3.5;} int main() {int a;double b;func(&a,&b);printf("a..%d b..%f\n",a,b);return 0;}
将指向int和double的指针传递给函数,此后在函数内部对这两个指针指向的变量设定值。

要点:如果需要通过函数返回值以外的方式返回值,将”指向T的指针“作为参数传递给函数。


4.1.2 将数组作为函数的参数传递

C语言中,数组是不能作为参数进行传递的。但可以通过传递指向数组初始元素的指针,使得在函数内部操作数组称为可能。

#include<stdio.h>void func(int *array,int size) {int i;for(i=0;i<size;i++) {printf("array[%d]..%d\n",i,array[i]);}} int main() {int array[]={1,2,3,4,5};func(array,sizeof(array)/sizeof(int));return 0;}

要点:想要将类型T的数组作为参数进行传递,可以考虑传递”指向T的指针“。可是,作为被调用方是不知道数组的元素个数的,所以在必要条件下,需要使用其他方式进行参数传递。


4.1.3 可变长数组

通常C语言在编译时必须知道数组的元素个数,但也可以使用malloc()在运行时再为数组申请必要的内存区域。

这种数组称之为”可变长数组“。

#include<stdio.h>#include<stdlib.h>int main() {char buf[256];int size;int *variable_array;int i;printf("Input array size");fgets(buf,256,stdin);sscanf(buf,"%d",&size);variable_array=malloc(sizeof(int)*size);for(i=0;i<size;i++) {variable_array[i]=i;}for(i=0;i<size;i++) {printf("variable_array[%d]..%d\n",i,variable_array[i]);}return 0;}

必须注意,在使用malloc()实现可变长数组的时候,程序员必须自己来管理数组的元素个数。


要点:在需要获得类型T的可变长数组时,可以使用malloc()来动态地给”指向T的指针“分配内存区域。但此时需要程序员自己对数组的元素个数进行管理。


补充:Java中的数组只能使用内存堆区域。Java的数组和C中使用的malloc()分配的数组,有决定性的不同,Java的数组是知道自身的长度的。此外,尽管Java的数组是保存在堆中,但却不能改变长度,没有类似于realloc()的函数。


4.2 组合使用

4.2.1 可变长数组的数组 P166~P172

4.2.2 可变长数组的可变长数组 P172~P174

4.2.3 命令行参数

对于main()函数,标准中指出必须要写出以下两种方式之一:

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

正常使用第一种形式,如果使用第二种形式,可以取得命令行参数。如在UNIX中的cat命令-用于输出文件的内容。 cat hoge.txt (命令名后是想要输出的文件名)

如果像cat hoge.txt piyo.txt 输出就是将hoge.txt 和piyo.txt两个文件的内容连接后所得的结果。


对于第二种形式,其实可以和下面这种形式是完全一样的。

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

argv[0]保存了命令名自身。在程序输出错误提示信息时,或者需要通过命令名称改变程序的行为时,会经常使用arg[0]。

argc保存了参数的个数(包含了arg[0])。实际上,从ANSI C之后,会保证argv[argc]肯定为NULL,所以完全可以没有argc。


4.2.4 通过参数返回指针

要点:异常处理中使用goto,反而让程序更加简洁。

C++/java中具备异常处理机制的语言,可以不用goto、在C中也有setjmp()/longjmp(),使用它们也能达到相似的效果。


4.2.5 将多维数组作为函数的参数传递

#include<stdio.h>#include<stdlib.h>void func(int (*hoge)[3]) {int i,j;for(i=0;i<4;i++) {for(j=0;j<3;j++) {printf("%d ",hoge[i][j]);}putchar('\n');}}int main(void) {int hoge[][3]={{1,2,3},{4,5,6},{4,5,6},{7,8,9},{10,11,12},};func(hoge);return 0;}


4.2.6 数组的可变长数组
4.2.7 考虑使用结构体


补充:Java和C一样不存在多维数组,也是使用数组的数组来实现多维数组。但是Java和C不同的是,Java的数组都是指针,所以所谓的"数组的数组"其实是”指向数组的指针的数组“。

Java中的类(相当于C中的结构体)也是保存在堆中的,并且只能利用指针进行操作。因此Java中没有类似C中"结构体数组"这样对象。

阻碍Java程序快速执行的最大原因是Java过多使用了堆操作。

C++的对象可以不通过指针,而是通过实体来操作。为实现这个特性,C++使用了带参数的构造方法以及继承的概念,导致C++编程变得非常复杂。


4.3 违反标准的技巧

4.3.1 可变长结构体
4.3.2 从1开始的数组

C语言中,对指向超出数组范围以外的指针,除非它指向”最后元素的下一个元素“,其他情形都属于未定义。

补充:指针可以指到数组的最后元素的下一个元素。

for(p=&array[0];p<&array[SPAN];p++)
这里没有使用循环计数器,而是使用指针遍历数组的各元素。当循环到达终点时,p指向&array[SPAN],也就是array的最后元素的下一个元素。

只是为了照顾以前写的代码,标准才允许指针可以指到数组的”最后元素的下一个元素“。


原创粉丝点击