七台河市网站建设_网站建设公司_虚拟主机_seo优化
2025/12/26 8:52:08 网站建设 项目流程

函数和二维数组

为编写将二维数组作为参数的函数,必须牢记,数组名被视为其地址,因此,相应的形参是一个指针,
就像一维数组一样。比较难处理的是如何正确地声明指针。例如,假设有下面的代码:

int data[3][4]={{1,2,3,4},{9,8,7,6},{2,4,6,8}}; int total=sum{data,3};

则sum( )的原型是什么样的呢?函数为何将行数(3)作为参数,而将列数(4)作为参数呢?
Data 是一个数组名,该数组有3 个元素。第一个元素本身是一个数组,有4 个int 值组成。因此data
的类型是指向由4 个int 组成的数组的指针,因此正确的原型如下:

int sum(int (*ar2)[4],int size);

其中的括号是必不可少的,因为下面的声明将声明一个由4 个指向int 的指针组成的数组,而不是由
一个指向由4 个int 组成的数组的指针;另外,函数参数不能是数组:

int *ar2[4];

还有另外一种格式,这种格式与上述原型的含义完全相同,但可读性更强:

int sum(int ar2[][4],int size);

上述两个原型都指出,ar2 是指针而不是数组。还需注意的是,指针类型指出,它指向由4 个int 组成
的数组。因此,指针类型指定了列数,这就是没有将列数作为独立的函数参数进行传递的原因。

由于指针类型指定了列数,因此sum( )函数只能接受由4 列组成的数组。但长度变量指定了行数,因
此sum( )对数组的行数没有限制:

int a[100][4]; int b[6][4]; ... int total1=sum(a,100); int total2=sum(b,6); int total3=sum(a,10); int total4=sum(a+10,20);

由于参数ar2 是指向数组的指针,那么我们如何在函数定义中使用它呢?最简单的方法是将ar2 看作
是一个二维数组的名称。下面是一个可行的函数定义:

int sum(int ar2[][4],int size) { int total=0; for(int r=0;r<size;r++) for(int c=0;c<4;c++) total+=ar2[r][c]; return total; }

同样,行数被传递给size 参数,但无论是参数ar2 的声明或是内部for 循环中,列数都是固定的—4 列。

可以使用数组表示法的原因如下。由于ar2 指向数组(它的元素是由4 个int 组成的数组)的第一个元素
(元素0),因此表达式ar2 + r 指向编号为r 的元素。因此ar2[r]是编号为r 的元素。由于该元素本身就是一个
由4 个int 组成的数组,因此ar2[r]是由4 个int 组成的数组的名称。将下标用于数组名将得到一个数组元素,因
此ar2[r][c]是由4 个int 组成的数组中的一个元素,是一个int 值。必须对指针ar2 执行两次解除引用,才能得到
数据。最简单的方法是使用方括号两次:ar2[r][c]。然而,如果不考虑难看的话,也可以使用运算符*两次:

ar2[r][c]==*(*(ar2+r)+c)

为理解这一点,读者可以从内向外解析各个子表达式的含义:

ar2 ar2+r *(ar2+r) *(ar2+r)+c *(*(ar2+r)+c)

sum( )的代码在声明参数ar2 时,没有使用const,因为这种技术只能用于指向基本类型的指针,而ar2
是指向指针的指针。

函数和C-风格字符串

C-风格字符串由一系列字符组成,以空值字符结尾。前面介绍的大部分有关设计数组函数的知识也适
用于字符串函数。

例如,将字符串作为参数时意味着传递的是地址,但可以使用const 来禁止对字符串参数进行修改。
然而,下面首先介绍一些有关字符串的特殊知识。

将C-风格字符串作为参数的函数

假设要将字符串作为参数传递给函数,则表示字符串的方式有三种:

  • char 数组;
  • 用引号括起的字符串常量(也称字符串字面值);
  • 被设置为字符串的地址的char 指针。
    但上述3 种选择的类型都是char 指针(准确地说是char*),因此可以将其作为字符串处理函数的参数:
char ghost[15]="galloping"; char *str="galumphing"; int n1=strlen(ghost); int n2=strlen(str); int strlen("gamboling");

可以说是将字符串作为参数来传递,但实际传递的是字符串第一个字符的地址。这意味着字符串函数
原型应将其表示字符串的形参声明为char *类型。

C-风格字符串与常规char 数组之间的一个重要区别是,字符串有内置的结束字符(前面讲过,包含
字符,但不以空值字符结尾的char 数组只是数组,而不是字符串)。这意味着不必将字符串长度作为参
数传递给函数,而函数可以使用循环依次检查字符串中的每个字符,直到遇到结尾的空值字符为止。程序
清单7.9 演示了这种方法,使用一个函数来计算特定的字符在字符串中出现的次数。由于该程序不需要处理负数,因此它将计数变量的类型声明为unsigned int。

#include <iostream> unsigned int c_in_str(const char* str, char ch); int main() { using namespace std; char mmm[15]="minimum"; const char *wail="ululate"; unsigned int ms= c_in_str(mmm, 'm'); unsigned int us= c_in_str(wail, 'u'); cout << ms << "m characters in" << mmm << endl; cout << us << "u characters in" << wail << endl; return 0; } unsigned int c_in_str(const char* str, char ch) { unsigned int count=0; while (*str) { if(*str==ch) count++; str++; } return count; }

下面是该程序的输出:

3m characters inminimum 2u characters inululate

程序说明
由于程序清单7.9 中的c_int_str( )函数不应修改原始字符串,因此它在声明形参str 时使用了限定符
const。这样,如果错误地址函数修改了字符串的内容,编译器将捕获这种错误。当然,可以在函数头中使
用数组表示法,而不声明str:

unsignex int c_in_str(const char str[],char ch)

然而,使用指针表示法提醒读者注意,参数不一定必须是数组名,也可以是其他形式的指针。
该函数本身演示了处理字符串中字符的标准方式:

while(*str) { statements str++; }

str 最初指向字符串的第一个字符,因此*str 表示的是第一个字符。例如,第一次调用该函数后,*str
的值将为m—“minimum”的第一个字符。只要字符不为空值字符(\0),str 就为非零值,因此循环将
继续。在每轮循环的结尾处,表达式str++将指针增加一个字节,使之指向字符串中的下一个字符。最终,
str 将指向结尾的空值字符,使得
str 等于0—空值字符的数字编码,从而结束循环。

返回C-风格字符串的函数

现在,假设要编写一个返回字符串的函数。是的,函数无法返回一个字符串,但可以返回字符串的地
址,这样做的效率更高。例如,程序清单7.10 定义了一个名为buildstr( )的函数,该函数返回一个指针。该
函数接受两个参数:一个字符和一个数字。函数使用new 创建一个长度与数字参数相等的字符串,然后将
每个元素都初始化为该字符。然后,返回指向新字符串的指针。

#include <iostream> char* buildstr(char c, int n); int main() { using namespace std; int times; char ch; cout << "Enter a character:"; cin >> ch; cout << "Enter an iteger:"; cin >> times; char* ps = buildstr(ch, times); cout << ps << endl; delete[] ps; ps = buildstr('+', 20); cout << ps << "-DONE-" << ps << endl; delete[] ps; return 0; } char* buildstr(char c, int n) { char* pstr = new char[n + 1]; pstr[n] = '\0'; while(n-->0) pstr[n] = c; return pstr; }

运行结果

Enter a character:V Enter an iteger:46 VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV ++++++++++++++++++++-DONE-++++++++++++++++++++

程序说明
要创建包含n 个字符的字符串,需要能够存储n + 1 个字符的空间,以便能够存储空值字符。因此,程序清单7.10 中的函数请求分配n + 1 个字节的内存来存储该字符串,并将最后一个字节设置为空值字符,然后从
后向前对数组进行填充。在程序清单7.10 中,下面的循环将循环n 次,直到n 减少到0,这将填充n 个元素:

while(n-->0) pstr[n]=c;

在最后一轮循环开始时,n 的值为1。由于n−−意味着先使用这个值,然后将其递减,因此while 循环
测试条件将对1 和0 进行比较,发现测试为true,循环继续。测试后,函数将n 减为0,因此pstr[0]是最后
一个被设置为c 的元素。之所以从后向前(而不是从前向后)填充字符串,是为了避免使用额外的变量。
从前向后填充的代码将与下面类似:

int i=0; while(i<n): pstr[i++]=c;

注意,变量pstr 的作用域为buildstr 函数内,因此该函数结束时,pstr(而不是字符串)使用的内存将
被释放。但由于函数返回了pstr 的值,因此程序仍可以通过main( )中的指针ps 来访问新建的字符串。

当该字符串不再需要时,程序清单7.10 中的程序使用delete 释放该字符串占用的内存。然后,将ps
指向为下一个字符串分配的内存块,然后释放它们。这种设计(让函数返回一个指针,该指针指向new 分
配的内存)的缺点是,程序员必须记住使用delete。在第12 章中,读者将知道C++类如何使用构造函数和
析构函数负责为您处理这些细节。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询