1.18k likes | 1.34k Views
第 6 章 指针和引用. 本章学习的目标: 1 、掌握指针的基本概念; 2 、掌握指向数组元素指针的用法; 3 、了解指向数组指针的概念; 4 、掌握指针形参的作用和用法; 5 、了解返回指针函数的用法; 6 、了解函数指针的概念; 7 、掌握引用的基本概念、引用形参的作用和用法; 8 、了解返回引用函数的用法。. 6.1 指针基本概念 6.2 指向数组元素的指针 6.3 指针形参 6.4 数组形参 6.5 指向二维数组一整行的指针 6.6 指针数组 6.7 多级指针 6.8 函数指针 6.9 返回指针值的函数 6.10 引用.
E N D
第6章 指针和引用 本章学习的目标: 1、掌握指针的基本概念; 2、掌握指向数组元素指针的用法; 3、了解指向数组指针的概念; 4、掌握指针形参的作用和用法; 5、了解返回指针函数的用法; 6、了解函数指针的概念; 7、掌握引用的基本概念、引用形参的作用和用法; 8、了解返回引用函数的用法。
6.1 指针基本概念 6.2 指向数组元素的指针 6.3 指针形参 6.4 数组形参 6.5 指向二维数组一整行的指针 6.6 指针数组 6.7多级指针 6.8 函数指针 6.9 返回指针值的函数 6.10 引用
6.1 指针基本概念 指针是系统程序设计语言的一个重要概念。指针在C程序中有以下多方面的作用: (1)利用指针能间接引用它所指的对象。 (2)指针能用来描述数据和数据之间的关系,以便构造复杂的数据结构。 (3)利用各种类型指针形参,能使函数增加活力。 (4)指针与数组结合,使引用数组元素的形式更加多样、访问数组元素的手段更加灵活。 (5)熟练正确应用指针能写特别紧凑高效的程序。
变量、变量的地址及变量的值 现实世界中的数据对象在程序中用变量与其对应,程序用变量定义引入变量、指定变量的类型和名。 程序执行时,程序中的变量在内存中占据一定的存储单元,存储单元的开始地址称为变量的地址。 在存储单元中存储的数据信息称为变量的内容。 编译系统根据类型确定变量所需的内存空间的字节数量和它的值的表示形式,检查程序对变量操作的合法性,对合法的操作翻译出正确的计算机指令。变量的名供程序引用它,程序按名引用变量的内容或变量的地址。
如代码: int x = 1; x = x + 2; 其中“x = x+2;”中的第一个x表示引用变量x的地址,第二个x表示引用变量x的内容。 该语句的意义是: 完成取x的内容,加上2的计算,并将计算结果存入变 量x的地址所对应的单元中。 在程序执行时,源程序中按名对变量的引用,已被转换成按地址引用,利用变量的地址或取其内容或存储值。
指针变量和它所指向的变量 运算符 & 取变量的地址 &x的值就是变量x的地址。 变量的地址也可作为一种值被存储和运算。 源程序也可利用变量的地址引用变量。 这为引用变量开辟了一条灵活、可变的途径。按变量名引用变量习惯称为直接引用, 而将变量A的地址存于另一变量B中(B=&A),借助于变量B引用变量A称为对A的间接引用。
变量地址类型是一种指针类型,变量类型不同,变量地址类型(指针类型)也不同。变量地址类型是一种指针类型,变量类型不同,变量地址类型(指针类型)也不同。 存储变量地址的变量称为指针变量,指针变量类型由它能存储的程序对象地址类型来区分。 如果指针变量B存储着程序对象A的地址,则称指针变量B指向程序对象A。 定义指针变量的一般形式为: 类型 * 标识符; 指针变量名 是一种指针类型 指针变量能取这种类型的程序对象的地址
例如: int *ip;//指针变量ip能取int类型变量的地址 float *fp;//指针变量fp能取float类型变量的地址 指针变量ip的类型是int*的, 指针变量fp的类型是float*的。
例如,以下代码将整型变量i的地址赋值给指针变量ip:例如,以下代码将整型变量i的地址赋值给指针变量ip: int i = 2; ip = &i; 这样的赋值使ip与i之间建立如图6.1所示的关系。当指针变量ip的值为变量i的地址时,就说指针变量ip指向变量i。 图6.1 指针变量与它所指变量关系图
指针变量定义时也可指定初值。例如 int j; int *intpt = &j; 在定义int*类型指针变量intpt时,给它初始化为int类型变量j的地址,使它指向j。 当定义局部指针变量时,如果未给它指定初值,则它的值是不确定的。程序在使用它们时,应首先给它们赋值,让指针变量确实指向某个变量。误用值不确定的指针变量会引起意想不到的错误。
为明确表示指针变量暂不指向任何变量,用0(记为NULL)表示这种情况。一个值为NULL的指针变量,习惯称它是空指针。为明确表示指针变量暂不指向任何变量,用0(记为NULL)表示这种情况。一个值为NULL的指针变量,习惯称它是空指针。 例如, ip = NULL; 让ip是一个空指针,暂不指向任何变量。 对于静态的指针变量,如果在定义时未给它指定初值,系统自动给它指定初值为0,让它暂时是一个空指针。
指针变量取程序对象的(开始)地址值,不能将任何其他非地址值赋给指针变量。指针变量对所指对象也有类型限制,不能将一个不能指的对象的地址赋给指针变量。例如:指针变量取程序对象的(开始)地址值,不能将任何其他非地址值赋给指针变量。指针变量对所指对象也有类型限制,不能将一个不能指的对象的地址赋给指针变量。例如: int i = 100, j, *ip, *intpt; float f, *fp; ip = 100; /* 指针变量不能赋整数值 */ intpt = j; /* 指针变量不能赋整型变量的值 */ fp = &i;/*float*类型变量,不能指向int型变量 */ fp = ip; /* 不同类型指针变量不能相互赋值 */
而以下都是正确的赋值: ip = &i ; /* 使 ip 指向 i */ intpt = ip ; /* 使 intpt 指向 ip 所指变量 */ fp = &f ; /* 使 fp 指向 f */ ip = NULL ; /* 使 ip 不再指向任何变量 */ 同类型的指针变量可以相互赋值; 可以赋指针变量能指向的程序对象地址给指针变量。
引用指针变量所指的变量 当指针变量明确指向一个对象(值不是 NULL)时,可以用运算符“*”, 引用指针变量所指向的对象。 如代码: ip = &i; j = *ip; 实现将指针变量ip所指变量的内容(即变量i的内容)赋给变量j。其中,赋值号右边的*ip 表示引用ip所指变量的内容。上述赋值等价于: j = i; 代码 *ip = 200; 实现向指针变量ip所指变量(即变量i)赋值200。其中,赋值号左边的*ip表示引用ip所指变量。上述赋值等价于 i = 200 ;
记号“*指针变量名”与指针变量所指变量的“变量名”等价。记号“*指针变量名”与指针变量所指变量的“变量名”等价。 如代码 intpt = &j; *intpt = *ip+5 ; 与代码 j = i+5 ; 等价。
【例6.1】说明指针变量与它所指变量之间关系的示意程序【例6.1】说明指针变量与它所指变量之间关系的示意程序 #include <stdio.h> int main() { int k; //一个整型变量 int *kPtr; //一个整型指针变量 k = 7; kPtr = &k;//使kPtr指向变量k。 printf("k的地址是 %x\nkPtr的值是 %x",&k, kPtr); printf("\nk的值是 %d\n*kPtr的值是 %d", k ,*kPtr); printf("\n以下表明运算符 * 和 & 是互逆的:\n&*kPtr = %x\n*&kPtr = %x\n",&*kPtr,*&kPtr); return 0; }
【程序说明】 kPtr指向变量k。第一个输出代码输出变量k的地址和指针变量kPtr的值。第二个输出代码输出变量k的值和指针变量kPtr所指变量的值。由于kPtr所指的正是变量k,所以k的地址值与kPtr的内容相同,k的值就是kPtr所指变量的值。第三个的输出代码表示&*kPtr与*&kPtr是一样的。运行以上程序,将输出 k的地址是 12ff7c kPtr的值是 12ff7c k的值是 7 *kPtr的值是 7 以下表明运算符 * 和 & 是互逆的: &*kPtr = 12ff7c *&kPtr = 12ff7c 上述程序的输出发现变量k的地址和变量kPtr的值是相同的,确信变量k的地址赋值给了指针变量kPtr。运算符&和*是互为相反的。当它们以不同的次序作用于指针变量时,得到相同的结果。不同系统上运行以上程序,输出的地址可能不同。
要特别注意指针变量之间的赋值,指针变量所指向的变量之间的赋值,这两种赋值在表示方法上的区别。如代码 intpt = ip; 使两个指针变量intpt与ip指向同一个对象,或都不指向任何对象(如果ip的值为NULL)。
通过指针变量间接引用,实际引用的是哪一个变量,取决于指针变量的值。改变指针变量的值,就是改变指针变量的指向,从而能实现用同样的间接引用代码,引用不同的变量。通过指针变量间接引用,实际引用的是哪一个变量,取决于指针变量的值。改变指针变量的值,就是改变指针变量的指向,从而能实现用同样的间接引用代码,引用不同的变量。 指针变量最主要的应用有两个方面,一是让指针变量指向数组的元素,以便逐一改变指针变量的指向,遍历数组的全部元素。二是让函数设置指针形参,让函数体中的代码通过指针形参间接引用调用环境中的变量,或引用变量的值,或改变变量的值。
为正确理解和使用指针变量,指出以下三点注意事项:为正确理解和使用指针变量,指出以下三点注意事项: (1)定义指针变量与间接引用指针变量所指对象采用相似的标记形式(* 指针变量名),但它们的作用与意义是完全不同的。在指针变量定义中(例如,int *ip;),指针变量名之前的符号“*”说明其随后的标识符是指针变量名。如果指针变量定义时带有初始化表达式,例如 int i,*ip = &i; 初始化表达式的地址是赋值给指针变量本身,而不是指针变量所指对象。实际上,在初始化之前,指针变量还未指向一个确定的对象。 (2)通过某个指向变量i的指针变量ip间接引用变量i与直接按变量名i引用变量i,效果是相同的,凡能直接按变量名可引用的地方,也可以用指向它的某个指针变量间接引用它。例如,有 int i, *ip = &i; 则凡变量i能使用的地方,*ip一样能用。
(3)因单目运算符*、&、++和--是从右向左结合的。注意分清运算对象是指针变量、还是指针变量所指对象。(3)因单目运算符*、&、++和--是从右向左结合的。注意分清运算对象是指针变量、还是指针变量所指对象。 例如,有变量定义 int i, j, *ip = &i ; 代码 j = ++*ip; 先是*ip,间接引用ip所指向的变量(变量i),然后对变量i的自增运算,并将运算结果赋值给变量j。 ++*ip相当于++(*ip)。
代码 j = *ip++; 是先求子表达式ip++。ip++的值为原来ip的值,然后是ip自增。 表达式*ip++的值与*ip相同,并在求出表达式值的同时,ip增加了1个单位。相当于代码 j = *ip; ip++; 经上述表达式计算后,ip不再指向变量i。 这种情况常用在指针指向数组元素的情况,在引用数组某元素之后,自动指向数组的下一个元素。 代码 j = (*ip)++ ; 则是先间接引用ip所指向的变量,取这个变量的值赋值给j,并让该变量自增。
6.2指向数组元素的指针 将数组元素的地址赋值给指针变量,就能使指针指向数组元素。 例如:int a[100], *p; p = &a[0] /* 或写成 p = a; */ 表示:把a[0]元素的地址赋给指针变量 p,即 p 指向数组a的下标为0的元素。 好处: 1.为引用数组元素提供了一种新的途径; 2.比用下标引用数组元素更灵活和简洁,因为指针有一定的运算能力。
对指向数组元素的指针允许作有限的运算: 例如: int *p, *q, a[100]; p = &a[10]; q = &a[50]; (1)当两个指针指向同一个数组的元素时,这两个指针可以作关系比较(< ,<=, ==,>, >=, !=)。 若 p==q表示p,q指向数组的同一个元素; p<q表示p所指向的数组元素的下标小于q所指向的数组元素的下标。 p>q表示p所指向的数组元素的下标大于q所指向的数组元素的下标。
(2) 指向数组元素的指针可与整数进行加减运算。 由于数组元素在内存中顺序连续存放,因此表达式a+1为a[1]的地址,a+2为a[2]的地址。 若指针 p = &a[0]; 则表达式 p+i 的值为 a[i]的地址。或者说,p+i的值为指向a[i]的指针值。 (3) 引用数组元素的方法 1.用数组元素的下标法,如a[5]、a[i]。 2.利用数组名,如 *(a+i)表示a[i]。 3.利用指针变量,如 p = &a[0]; 则 *(p+i)表示 a[i]。 *(p+i)也可写成p[i]。
用数组名与指针的区别: 指针变量的值可改变,例如p++;数组名只代表数组首元素的指针,是不可改变的(是常量)。
int a[100], b[100], *p, *q; for(p = a; p < a + 100;) /*利用指针遍历数组,输入数组的全部元素*/ scanf(“%d”, p++); for(p = a; p <= &a[99]; p++)/*利用指针遍历数组,输出数组的全部元素*/ printf(“*p = %d\t”, *p); printf(“\n”); for(p = a, q = b; p < a + 100;)/* 利用指针将已知数组复制到另一个数组*/ *q++ = *p++;
当指针变量指向字符串某字符时,习惯称这样的指针为字符串的字符指针。当指针变量指向字符串某字符时,习惯称这样的指针为字符串的字符指针。 字符串存储于字符数组中,所以指向字符串字符的指针也是指向数组元素的指针。但因字符串有字符串结束符,具体编写字符串处理程序时不再需要指定字符串的字符个数,而处理普通数组通常需要指定数组的元素个数。 首先指出程序存储字符串常量的方法。为字符串常量提供存储空间有两种方法:
(1)把字符串常量存放在一个字符数组中。 例如: char s[] = "I am a string."; 数组s共有15个元素,其中s[14]为’\0’。对于这种情况,编译程序根据字符串常量所需的字节数为字符数组分配存储单元,并把字符串常量填写到数组中,即对数组初始化。 (2)字符串常量放在程序运行环境的常量存储区中。 表达式中出现的字符串常量由编译系统将它与程序中出现的其他常量一起存放在常量存储区中。程序要访问存于常量存储区中的字符串常量,需用一个字符串的字符指针指向它的第一个字符。
当字符串常量作为表达式出现时,字符串常量放入常量存储区,而把表达式转换成该字符串常量存储区的第一个字符的指针。当字符串常量作为表达式出现时,字符串常量放入常量存储区,而把表达式转换成该字符串常量存储区的第一个字符的指针。 字符串常量赋值给字符指针变量,向字符指针变量赋值的是字符串常量的第一个字符的指针,而不是向指针变量赋字符串常量的全部字符。
例如: char *cp1, *cp2 = “I am a string”;/*用字符串常量初始化字符指针变量*/ cp1 = ”Another string”; /*用字符串常量赋值给字符指针变量*/ 使字符指针变量cp2指向字符串常量“I am a string”的第一个字符I,使cp1指向字符串常量”Another string ”的第一个字符A。以后就可通过cp2或cp1分别访问这两个字符串常量中的其它字符。 例如,*cp2或cp2[0]就是’I’,*(cp1+3)或cp1[3]就是字符’t’。要特别强调指出,企图通过指针变量修改存于常量区中的字符串常量是不允许的。
例如,调用库函数strlen()求字符串常量的长度:例如,调用库函数strlen()求字符串常量的长度: strlen("I am a string.") 该函数调用的结果是14,表示这个字符串常量由14个有效字符组成。 如果s是一个字符数组,其中已存有字符串,cp是一个字符指针变量,它指向某个字符串的首字符: char s[] = “I am a string.”, *cp = "Another string."; 则代码: printf(“%s\n”,s); 输出存于字符数组s中的字符串。 而代码: printf(‘%s\n”,cp); 输出字符指针变量cp所指向的字符串。
【例6.2】将一个已知字符串复制到一个字符数组,设from为已知字符串的首字符指针,to为存储复制字符串的字符数组首元素的指针。若用下标引用数组元素标记法,完成复制的代码可写成:【例6.2】将一个已知字符串复制到一个字符数组,设from为已知字符串的首字符指针,to为存储复制字符串的字符数组首元素的指针。若用下标引用数组元素标记法,完成复制的代码可写成: k = 0; while ((to[k] = from[k]) != ‘\0’) k++; 如采用字符指针描述有: while ((*to++ = *from++) != ‘\0’); 由于字符串结束符’\0’的值为0,上述测试当前复制字符是不是字符串结束符的代码中,“!=’\0’”是多余的,字符串复制更简洁的写法是: while (*to++ = *from++);
【例6.3】将字符串s中的某种字符去掉,假设要去掉的字符与字符变量c中的字符相同。【例6.3】将字符串s中的某种字符去掉,假设要去掉的字符与字符变量c中的字符相同。 一边考察字符,一边复制不去掉的字符来实现。引入字符指针p和q,其中p指向当前正要考察的字符,若它所指的字符与c中的字符不相同,则应将它复制到新字符串中。否则,该字符不被复制,也就从新的字符串中去掉了;q指向下一个用于存储复制字符的存储位置。每次复制一个字符后,q增加1。每次考察了一个字符后,p就增1。 for(p = q = s; *p; p++) if (*p != c) *q++ = *p; /* 复制 */ *p = ’\0’; /* 重新构成字符串 */
6.3 指针形参 在函数计算过程中,函数不能修改实参变量。但许多应用要求被调用函数能修改由实参指定的变量。C语言的指针形参能实现这种特殊的要求。指针形参能够指向的对象的类型在形参说明时指明。例如,以下函数说明中 void divNum(int *intPt, int d); intPt是一个指针形参,它能指向int类型的变量。 调用有指针形参的函数时,对应指针形参的实参必须是某个变量的指针。指针形参从实参处得到某变量的指针,使指针形参指向一个变量。这样,函数就可用这个指针形参间接访问被调用函数之外的变量,或引用其值,或修改其值。因此,指针类型形参为函数改变调用环境中的变量提供了手段。
【例6.4】本例中的两个函数用于说明一般形参与指针形参的区别。函数squreByValue()有一个整型形参n,求得n的二次方幂返回。函数squreByPoint()设有一个整型指针形参,该函数根据指针形参所指变量,将变量的值改成是它调用之前的二次幂。【例6.4】本例中的两个函数用于说明一般形参与指针形参的区别。函数squreByValue()有一个整型形参n,求得n的二次方幂返回。函数squreByPoint()设有一个整型指针形参,该函数根据指针形参所指变量,将变量的值改成是它调用之前的二次幂。
#include <stdio.h> int squreByValue(int n) { return n*n;//以n的平方为结果返回 } void squreByPoint(int *nPtr) { *nPtr = *nPtr * *nPtr;/*将形参所指向的变量值平方,并存于该变量中*/ }
int main() { int m = 5; printf(”数m原来的值是 %d\n”, m); printf(”函数调用squreByValue(m)的返回值是 %d\n”, squreByValue(m)); printf(”函数调用后m的值是 %d\n”, m); printf(”*******************************************************\n”); printf(”数m原来的值是 %d\n”, m); squreByPoint(&m); //m值将因调用函数而改变 printf(”函数调用squreByPoint (&m)后m的值是 %d\n”, m); return 0; }
图6.2示意一般形参的函数调用过程 void main() m { int m = 5; printf(”%d\n”, squreByValue(m)); } int squreByValue(int n) { return n * n; } n 5 无定义 主函数调用函数squreByValue()之前 不占存储空间 void main() m { int m = 5; printf(”%d\n”, squreByValue(m)); } int squreByValue(int n) { return n * n; } n 5 5 存储空间被释放 squreByValue()接受调用后 void main() m { int m = 5; printf(”%d\n”, squreByValue(m)); } int squreByValue(int n) { return n * n; 结果25 } n 5 无定义 函数squreByValue()计算出形参的二次幂之后 不占存储空间 void main() m { int m = 5; printf(”%d\n”,squreByValue(m)); //输出25 } int squreByValue(int n) { return n * n; } n 5 无定义 函数调用squreByValue()结束,返回主函数之后
图6.3示意指针形参的函数调用过程 void main() m { int m = 5; squreByPoint(&m); } void squreeByPoint(int *nPtr) { *nPtr = *nPtr * *nPtr; } nPtr 5 无定义 主函数调用函数squreByPoint()之前 不占存储空间 void main() m { int m = 5; squreByPoint(&m); } void squreeByPoint(int *nPtr) { *nPtr = *nPtr * *nPtr; } nPtr 5 获得存储空间,指向m 计算结果赋值给m squreByPoint()接受调用后 void main() m { int m = 5; squreByPoint(&m); } void squreeByPoint(int *nPtr) { *nPtr = *nPtr * *nPtr; } nPtr 25 函数squreByPoint()执行,返回之前 void main() m { int m = 5; squreByPoint(&m); } void squreeByPoint(int *nPtr) { *nPtr = *nPtr * *nPtr; } nPtr 25 无定义 函数squreByPoint()返回之后 不占存储空间
【例6.5】说明指针形参用法的示意程序。 程序中的函数swap()的功能是交换两个整型变量的值,函数swap()设置了两个整型指针形参。 在函数swap()的体中,用指针形参间接引用它们所指向的变量。 调用函数swap()时,提供的两个实参必须是要交换值的两个变量的指针,而不是变量的值。
调用 swap 函数之前: a = 1 b = 2 #include <stdio.h> int main() { int a = 1, b = 2;void swap(int *, int *); printf(”调用swap函数之前:a = %d\tb = %d\n“, a, b); swap(&a,&b);/*以变量的指针为实参,而不是变量的值 */ printf(”调用swap函数之后:a = %d\tb = %d\n“, a, b); return 0; } void swap(int *pu, int *pv)/* 函数设置两个指针形参 */ { int t; t = *pu; /* 函数体通过指针形参,间接引用和改变调用环境中的变量 */ *pu = *pv; *pv = t; } 调用 swap 函数之后: a = 2 b = 1 &b &a
【例6.6】对于非指针类型形参,实参向形参传值,函数不能改变实参变量值的示意程序。【例6.6】对于非指针类型形参,实参向形参传值,函数不能改变实参变量值的示意程序。 #include <stdio.h> void paws(int u, int v) { int t = u; u = v; v = t; printf(”在函数 paws 中:u = %d\tv = %d\n“, u, v); } int main() { int x = 1, y = 2; paws(x, y); printf(”在主函数 main 中:x = %d\ty = %d\n“, x, y); return 0; } 在函数 paws 中:u = 2 v = 1 1 2 在主函数 main 中:x = 1 y = 2
例子说明,只有实参向形参单向传递值,函数执行时,形参值的改变不会影响实参变量。例子说明,只有实参向形参单向传递值,函数执行时,形参值的改变不会影响实参变量。 希望函数能按需要改变由实参指定的变量,需要在三个方面协调一致。 (1)函数应设置指针形参; (2)函数体必须通过指针形参间接引用变量; (3)调用函数时,必须以希望改变值的变量的指针为实参。
读程序,回答程序的输出结果。 #include <stdio.h> void f1(int x, int y) { int t = x; x = y; y = t; } void f2(int *x, int *y) { int t = *x; *x = *y; *y = t;} void f3(int **x, int **y) { int *t = *x; *x = *y; *y = t;} int main() { int x = 1, y = 2; int *xpt = &x, *ypt = &y; printf(”First:x = %d\ty = %d\n“, x, y); f1(x, y); printf(”After call f1():x = %d\ty = %d\n“, x, y); x = 1; y = 2; f2(&x, &y); printf(”After call f2():x = %d\ty = %d\n“, x, y);
读程序,回答程序的输出结果。 x = 1; y = 2; printf(”Befor call f3():x = %d\ty = %d\n“, x, y); printf(”Befor call f3():*xpt = %d\t*ypt = %d\n“, *xpt, *ypt); f3(&xpt, &ypt); printf(”After call f3():x = %d\ty = %d\n“, x, y); printf(”After call f3():*xpt = %d\t*ypt = %d\n“, *xpt, *ypt); return 0; }
6.4数组形参 为了能使函数处理不同的数组,函数应设置数组形参。对应数组形参的实参是数组某元素的地址,最通常的情况是数组首元素的地址。由于数组名能代表数组首元素的地址,所以常用数组名实参对应数组形参。例如,下面定义的函数sum()用于求n个数之和,这个函数正确地设置有两个形参,一个形参是数组,用于对应实在数组;另一个形参是整型的,用于指定求和数组的元素个数。 int sum(int a[], int n) { int i, s; for(s = i = 0; i < n; i++) s += a[i]; return s; }
利用以上定义的函数sum(),如果有以下变量定义:利用以上定义的函数sum(),如果有以下变量定义: int x[] = {1, 2, 3, 4, 5}; int i, j; 则语句 i = sum(x, 5); j = sum(&x[2], 3); printf("i = %d\nj = %d\n", i, j); 将输出 i = 15 j = 12 将数组x的地址(&x[0])传送给数组形参a, 将数组x中的x[2]的地址(&x[2])传送给形参a
对于数组类型的形参来说,函数被调用时,与它对应的实在数组由多少个元素是不确定的,可能会对应一个大数组,也可能会对应一个小数组,甚至会对应数组中的某一段。对于数组类型的形参来说,函数被调用时,与它对应的实在数组由多少个元素是不确定的,可能会对应一个大数组,也可能会对应一个小数组,甚至会对应数组中的某一段。 在数组形参说明中,形参数组不必指定数组元素的个数。 为了正确指明某次函数调用实际参与计算的元素个数,应另引入一个整型形参来指定,就如函数sum()那样。
因传递给数组形参的实参是数组段的开始地址,函数内对数组形参的访问就是对实参所指数组的访问。函数也可以改变实参所指数组元素的值。例如,以下initArry()函数的定义:因传递给数组形参的实参是数组段的开始地址,函数内对数组形参的访问就是对实参所指数组的访问。函数也可以改变实参所指数组元素的值。例如,以下initArry()函数的定义: void initArray(int x[], int n, int val) { int i; for(i = 0; i < n; i++) x[i] = val; } 函数initArray()是给数组元素赋指定值的。如有数组定义 int a[10], b[100]; 语句 initArray(a, 10, 1); initArray(b, 50, 2); initArray(&b[50], 50, 4); 分别给数组a的所有元素赋值1,为数组b的前50个元素赋值2,后50个元素赋值4。