当声明数时,编译器在连续的内存空间分配基本地址和足够的储存空间,以容纳数组的全部元素。基本地址是数组第一个元素(索引为0)的存储位置。编译器还把数组名定义为指向第一个元素的常量指针。数组
元素的地址是经过索引和数据类型的比例因子来计算的;例如: x[3]的地址 = 基本地址 + (3 x 整型数据的比例因子)函数
如何表示元素a[i][j]的(其中:int *p; p = a;);prototype
0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
1 | |||||
2 | |||||
3 | |||||
4 |
数组 a 的基本地址为 &a[0][0],从这个地址开始,编译器按行为全部的元素分配连续的存储空间。例如:指针
int a[3][4] ={ {15,27,11,35}, {22,19,31,17}, {31,23,14,36} }
数组a的存储以下:code
|15 |27| 11| 35 |22 |19 |31 |17 |31 |23 |14 |36 | |--索引
若是把 p 声明为整型指针,而且初始地址为a[0][0](),那么:内存
a[i][j] = *(p+4*i+j);
C语言支持另外一种建立字符串的方法,即便用char类型的指针变量。例如:字符串
char *str = "good";
上述声明语句建立了一个文本字符串,而后将其地址保存在指针变量str中;这样指针 str 就指向字符串 “good” 的第一个字符,以下所示:编译器
|g(str) | o | o | d | \0 | |--it
由此,能够用指针访问整个字符串:
printf("%s",str); put(str);
固然,也能够用指针来访问字符串中的单个字符。
指针的一项重要的应用就是处理字符串表,特别是处理行的长度可变的“凹凸不平的数组”时;例如:
char *name[3] = { "New Zealand", "Australia", "India" };
上面的声明语句只分配了28个字符,这足以保存全部的字符,具体以下:
|N| e |w | |Z |e |a |l |a| n| d| \0| |-- |A| u| s| t| r| a| l| i| a| \0| |I| n| d| i| a| \0| 下面的语句能够用来显示着三个名称:
for(i = 0; i <= 2; i++) printf("%s\n",name[i]);
要访问第 i 个名称的第 j 个字符,能够这样编写语句:
char c = *(name[i]+j);
使用指针传递变量地址的函数调用过程称为引用调用(咱们已经说过,传递变量实际值的过程称为 “按值调用”)。引用调用提供了一种机制,让被调用的函数能够修改调用函数中存储的值。 请注意如下代码:
//例一 void exchange(int *a, int *b) { int t; t=*a; *a=*b; *b=t; } void main() { int x, y; x = 100; y = 200; printf("%d ,%d\\n",x,y); exchange(&x,&y); printf("%d ,%d\\n",x,y); }
//例二 void exchange(int *a, int *b) { int *t; t=a; a=b; b=t; printf("%d ,%d\n", *a, *b); } void main() { int x, y; x = 100; y = 200; printf("%d ,%d\n", x, y); exchange(&x,&y); printf("%d ,%d\n", x, y); }
代码例二并不会使x,y的值发生互换,由于当函数指针a,b得到x,y的地址后,做为值进行储存,交换a,b的值并无改变其值(x,y的地址)指向的x,y的值。
指针是C语言的一种数据类型,所以也可使用函数返回一个指向调用函数的指针。请看下面的代码:
int *larger(int* , int*);/*prototype*/ main() { int a = 10; int b = 20; int *p; p = larger(&a, &b);/*Function call*/ printf("%d",p); } int *larger(int *x, int *y) { if(*x > *y) return(x);/*address of a*/ else return(y);/*address of b*/ }
注意:返回的地址必须是调用函数中变量的地址。若是返回的是指向被调用函数中局部变量的地址;将产生错误。
与变量同样,函数也属于某种数据类型,在内存中也须要有储存地址。所以能够声明一个指向函数的指针。如同指向字符数组的指针,能够接收任意大小的字符数组同样,指向函数的指针能够指向任意的函数,如此能够减小函数的数量,使函数的功能更增强大。指向函数的指针声明以下:
type (*fptr)();
该语句告诉编译器,fptr为指向函数的的指针,返回type类型的值。用括号把*fptr括起来是必要的。记住,下面的语句:
type *gptr();
表示的是把gptr声明为函数,它返回一个指向type类型的指针。
请仔细关注如下代码:
#include<stdio.h> #include<math.h> #define PI 3.1415926 double table(double (*f)(), double, double, double); double y(double); double cos(double); double table(double (*f)(), double min, double max, double step) { double a, value; for(a = min;a <= max; a+=step){ value = (*f)(a); printf("%5.2f %10.4f\n,a,value"); } } double y(double x) { return (2*x*x-x+1); } void main() { printf("table of y(x) = 2*x*x-x+1\n\n"); table(y, 0.0, 2.0, 0.5); printf("table of cos(x)\n\n"); table(cos, 0.0, PI, 0.5); }
在前面章节中,咱们讨论把结构体做为参数传递给函数。咱们还看到这样的实例,其中函数接收整个结构体的副本,并在运行后把他返回给调用函数。正如咱们前面介绍的那样,该方法不管是在运行速度仍是在内存使用上都不是高效的。经过以指向结构体的指针做为传递参数,而后使用指针来操纵结构体成员,就能够克服该缺点。请看如下函数:
print_invent(struct *item) { printf("Name: %s\n", item->name); printf("price:%f\n", item->price); }
该函数能够用下面的语句来调用:
print_invent(&product);
请关注如下两点: