文档章节

C Primer Plus 第10章 数组和指针 10.4 函数、数组和指针

idreamo
 idreamo
发布于 2016/07/28 07:01
字数 2352
阅读 59
收藏 0

假设您要编写一个对数组进行操作的函数,目的是要此函数返回数组内所有元素的和。假设marbles为这个int数组的名称。应该如何来调用这个函数?

一种合乎情理的猜测如下:

totao = sum(marbles);  // 可能的函数调用

那么原型应该是什么?数组名同时代表数组首元素的地址因此实际参数marbles是一个int的地址,应该把它赋给一个类型为指向int的指针的形式参量

int sum(int *ar);  //相就的原型

函数sum()从该参数可以得到什么信息呢?它得到数组首元素的地址,而且知道可以从此地址找到一个int。请注意它无从知道数组中元素的数量。于是在函数定义中有两种选择,第一种是在函数代码中写上固定的大小。如下所示:

int sum(int *ar)    //相应定义
{
    int i;
    int total = 0;
    
    for (i=0;i<10;i++)    //假设有10个元素
        total+=ar[i];     //ar[i]与*(ar+i)相同
return total;
}

上面的代码利用了这样的事实:正如可以在指针符号中使用数组名称一样,也可以数组符号中使用指针。

这种函数定义是有限制的,它仅在数组大小为10时可以工作。更灵活的方法是把数组大小做为第二个参数传递给函数

int sum(int *ar,int n)    //更通用的方法
{
    int i;
    int total = 0;
    
    for (i=0;i<n;i++)    //使用n表示元素的个数
        total+=ar[i];     //ar[i]与*(ar+i)相同
return total;
}

此外,关于函数参量还有一件需要说明的事情:在函数原型和函数定义的场合中(并且只有在这两种场合中),可以使用int *ar代替int ar[]:

int sum(int ar[],int n);

无论在任何情况下,形式int *ar 都表示ar是指向Int的指针形式int ar[]也可以表示ar是指向int的指针,但只是在声明形式参量时才可以这样使用使用第二种形式可以提醒读者ar不仅指向一个int数值,而且它指向的这个int是一个数组中的元素。

程序清单10.10  sum_arr1.c程序

//sum_arr1.c --对一个数组的所有元素求和
//如果不能使用%zd,请使用%u或%lu
#include <stdio.h>
#define SIZE 10
int sum(int ar[],int n);
int main(void)
{
    int marbles[SIZE] = {20,10,5,39,4,16,19,26,31,20};
    long answer;
    answer = sum(marbles,SIZE);
    printf("The total number of marbles is %ld.\n",answer);
    printf("The size of marbles is %lu bytes.\n",sizeof marbles);
    return 0;
}
int sum(int ar[],int n)
{
    int i;
    int total=0;
    for(i=0;i<n;i++)
        total+=ar[i];
    printf("The size of ar is %lu bytes.\n",sizeof ar);

    return total;
}

输出结果如下:

The size of ar is 4 bytes.
The total number of marbles is 190.
The size of marbles is 40 bytes.

请注意marbles的大小为40字节。的确如此,因为marbles包含10个int 类型的数,每个数占4个字节,因此总共40个字节。但是ar只有4个字节。这是因为ar本身并不是一个数组,它是一个指向marbles的首元素的指针 。对于采用4字节地址的计算机系统,指针的大小为4字节(其他系统中地址的大小可能不是4个字节)。总之,在程序清单10.10中,marbles是一个数组,而ar为一个指向marbles首元素的指针,C中数组和指针之间的关系允许您在数组符号中使用指针ar。

10.4.1  使用指针参数

使用数组的函数需要知道何时开始和何时结束数组。函数sum()使用一个指针参量来确定数组的开始点,使用一个整数参量来指明数组的元素个数(指针参量同时确定了数组中数据的类型)。但是这并不是向函数传递数组信息的惟一方法。但是这并不是向函数传递数组信息的惟一方法。另一种方法是传递两个指针 ,第一个指针指明数组的起始地址(同前面的的方法相同),第二个指针指明数组的结束地址。程序清单10.11中的示例示意了这种方法。这个例子利用了指针参数是变量这一事实,也就是说,程序中没有使用索引来指示数组中的每个元素,而是直接修改指针本身,使指针 依次指向各个数组元素。

程序清单10.11 sum_arr2.c程序

//sum_arr1.c --对一个数组的所有元素求和
//如果不能使用%zd,请使用%u或%lu
#include <stdio.h>
#define SIZE 10
int sump(int * start,int * end);
int main(void)
{
    int marbles[SIZE] = {20,10,5,39,4,16,19,26,31,20};
    long answer;
    answer = sump(marbles,marbles+SIZE);
    printf("The total number of marbles is %ld.\n",answer);
    return 0;
}
/*使用指针算术*/
int sump(int * start,int * end)
{

    int total=0;
    while(start < end)
    {
        total+=*start;  /*把值累加到total上*/
        start++;        /*把指针向前推进到下一个元素*/
    }
    return total;
}

由于指针start最初指向marbles的首元素,因此执行赋值表达式total+=*start时,把首元素的值 加到total上。然后,表达式start++使指针变量start增1,从而指向数组的下一个元素。start是指向int的指针,因此当start增1时它将增加1个int的大小。

请注意函数sump()和sum()结束加法循环的方式不一样。函数sum()使用数组元素的个数做为第二个参数,循环利用这个值来控制循环次数:

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

而函数sump()则使用第二个指针来控制循环次数:

while(start < end)

因为这是一个不相等关系的判断,所以处理的最后一个元素将是end所指向的位置之前的元素。这就意味着end实际指向的位置是在数组最后一个元素之后。C保证在为数组分配存储空间的时候,指向数组之后 的第一个位置的指针也是合法的。这使上面例子中采用的结构是有效的,因为start在循环中最后得到的数值是end。请注意使用这种“越界”指针可使函数调用的形式更加整洁:

sump(marbles,marbles+SIZE);

由于索引是从0开始的,因此marbles+SIZES指向数组结尾处之后的下一个元素。

顺便说一句,尽管C保证指针marbles+SIZES是合法的,但对marbles[SIZE](即该地址存储的内容)不作任何保证。

可以把上面的循环体精简为一行:

total+=*start++ ;

一元运算符*和++具有相等的优先级,但它在结合时是从右向左进行的。这就意味着++应用于start,而不是应用于*start。也就是说是指针自增1,而不是指针所指向的数据自增1。后缀形式start++而不是++start表示先把指针指向的数据加到total上,然后指针再自增1。如果程序使用++start,则顺序就变为指针先自增1,然后再使用其指向的值。

尽管*start++比较常用,但为了清晰起见,应该使用*(start++)。程序清单10.12中的程序示意了这些在关优先级的微秒之处:

程序清单10.12

/*order.c  --指针运算的优先级*/
#include <stdio.h>
int data[2]={100,200};
int moredata[2]={300,400};
int main(void)
{
    int *p1,*p2,*p3;
    p1=p2=data;
    p3=moredata;
    printf(" *p1=%d, *p2=%d, *p3=%d\n",*p1,*p2,*p3);
    printf("*p1++ =%d, *++p2 =%d, (*p3)++ =%d\n",*p1++,*++p2,(*p3)++);
    printf(" *p1 =%d,*p2 =%d,*p3 =%d\n",*p1,*p2,*p3);
    return 0;
}

输出结果如下:

  *p1=100, *p2=100, *p3=300
*p1++=100,*++p2=200,(*p3)++=300
*p1=200,*p2=200,*p3=301

上面的例子中,只有(*p3)++改变了数组元素的值。其他两个操作增加了指针p1和指针p2,使之指向下一个元素。

10.4.2  评论:指针和数组

从前面的介绍中可以看出,处理数组的函数实际上是使用指针做为参数的但是在编写处理数组的函数时,数组符号和指针符号都是可以选用的。如果使用数组符号,则函数处理数组这一事实更加明显。也有一些程序员可能更习惯于使用指针,觉得指针使用起来更加自然。

在C中,两个表达式ar[i]和*(ar+i)的意义是等价的。而且不管ar是一个数组名还是一个指针变量,这两个表达式都可以正常工作。然而,只有当ar是一个指针变量时,才可以使用ar++这样的表达式。

指针符号(尤其在对其使用增量运算符时)更接近于机器语言,而且某些编译器在编译时能够生成效率更高的代码。然而,很多程序员认为程序员的主要任务是保证程序的正确性和易读性,代码的优化应该交给编译器去做。

© 著作权归作者所有

idreamo
粉丝 18
博文 139
码字总数 224743
作品 0
青岛
产品经理
私信 提问
C Primer Plus 第10章 数组和指针 10.7 指针和多维数组

指针和多维数组有什么关系?为什么我们需要知道它们之间的关系?函数是通过指针来处理多维数组的,因此在使用这样的函数之前,您需要更多的了解指针。假设有如下的声明: int zippo[4][2] ; ...

idreamo
2016/08/06
68
0
C Primer Plus 第10章 数组和指针 编程练习答案

1、修改程序清单10.7中的程序rain,使它不使用数组下标,而是使用指针进行计算(程序中仍然需要声明并初始化数组)。 2、编写一个程序,初始化一个double数组,然后把数组内容复制到另外两个...

idreamo
2016/08/14
262
0
C++ primer第二次阅读学习笔记(第4章)

C++语言应尽量使用vector和迭代器类型,应避免使用低级的数组和指针,涉及良好的程序只有在强调速度时才在类实现的内部使用数组和指针。因此要向成为一个真正的C++程序员就要多使用vector和s...

长平狐
2012/10/08
74
0
C Primer Plus 第10章 数组和指针 10.5 指针操作

C提供了6种基本的指针操作,下面的程序将具体演示这些操作。为了显示每一个操作的结果,程序将打印出指针的值(即指针指向的地址)、指针指向地址中存储的内容,以及指针本身的地址(如果您的...

idreamo
2016/07/30
77
0
C Primer Plus 第10章 数组和指针 10.6 保护数组的内容

这种技术也会带来一些新的问题。通常C传递数据的值,其原因是要保护原始数据的完整性。函数使用原始数据的一份拷贝,这样就不会意外的修改原始数据。但是,由于处理数组的函数直接操作原始数...

idreamo
2016/07/31
26
0

没有更多内容

加载失败,请刷新页面

加载更多

Replugin借助“UI进程”来快速释放Dex

public static boolean preload(PluginInfo pi) { if (pi == null) { return false; } // 借助“UI进程”来快速释放Dex(见PluginFastInstallProviderProxy的说明) return PluginFastInsta......

Gemini-Lin
58分钟前
4
0
Hibernate 5 的模块/包(modules/artifacts)

Hibernate 的功能被拆分成一系列的模块/包(modules/artifacts),其目的是为了对依赖进行独立(模块化)。 模块名称 说明 hibernate-core 这个是 Hibernate 的主要(main (core))模块。定义...

honeymoose
今天
4
0
CSS--属性

一、溢出 当内容多,元素区域小的时候,就会产生溢出效果,默认是纵向溢出 横向溢出:在内容和容器之间再套一层容器,并且内部容器要比外部容器宽 属性:overflow/overflow-x/overflow-y 取值...

wytao1995
今天
4
0
精华帖

第一章 jQuery简介 jQuery是一个JavaScript库 jQuery具备简洁的语法和跨平台的兼容性 简化了JavaScript的操作。 在页面中引入jQuery jQuery是一个JavaScript脚本库,不需要特别的安装,只需要...

流川偑
今天
7
0
语音对话英语翻译在线翻译成中文哪个方法好用

想要进行将中文翻译成英文,或者将英文翻译成中文的操作,其实有一个非常简单的工具就能够帮助完成将语音进行翻译转换的软件。 在应用市场或者百度手机助手等各大应用渠道里面就能够找到一款...

401恶户
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部