依睛(IT blog) 我回来了,PHP<-->C/C++ LINUX

笨鸟

统计

积分与排名

友情连接

最新评论

C语言指针详述(1)

第一章 指针的概念

指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。 要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区,还有指针本身所占据的内存区。让我们分别说明。
先声明几个指针放着做例子:

   

指针的类型

 

指针所指向的类型

 

指针的值

 

指针本身所占据的内存区

 

int*ptr;

 int *  int  sizeof( int *)=4  

Sizeof(int*) = 4

 

char*ptr;

 char *  char  sizeof(char*)=1  

Sizeof(char*) = 4

 

int**ptr;

 int **  int*  sizeof(int**)=4  

Sizeof(int**) = 4

 

int*ptr[2];

 int*[2]  int[2]  sizeof(int*[2])=8  

Sizeof(int*[3]) = 4

 int(*ptr)[3];  int(*)[3]  int()[3]  sizeof(int(*)[3])=12  

Sizeof(int(*)[3]) = 4

 

char(*ptr)[3];

 char(*)[3]  char()[3]  sizeof(char(*)[3])=3  

Sizeof(char(*)[3]) = 4

 

int*(*ptr)[4];

 int*(*)[4]  int*()[4]  sizeof(int*(*)[4])=16  

Sizeof(int*(*)[4]) = 4

1 指针的类型
从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。让我们看看例一中各个指针的类型:
2 指针所指向的类型
当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待。
从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。例如:
在指针的算术运算中,指针所指向的类型有很大的作用。
指针的类型(即指针本身的类型)和指针所指向的类型是两个概念。当你对C越来越熟悉时,你会发现,把与指针搅和在一起的"类型"这个概念分成"指针的类型"和"指针所指向的类型"两个概念,是精通指针的关键点之一。
3 指针的值,或者叫指针所指向的内存区或地址
指针的值是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。在32位程序里,所有类型的指针的值都是一个32位整数,因为32位程序里内存地址全都是32位长。 指针所指向的内存区就是从指针的值所代表的那个内存地址开始,长度为sizeof(指针所指向的类型)的一片内存区。以后,我们说一个指针的值是XX,就相当于说该指针指向了以XX为首地址的一片内存区域;我们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址。
指针所指向的内存区和指针所指向的类型是两个完全不同的概念。在例一中,指针所指向的类型已经有了,但由于指针还未初始化,所以它所指向的内存区是不存在的,或者说是无意义的。
以后,每遇到一个指针,都应该问问:这个指针的类型是什么?指针指的类型是什么?该指针指向了哪里?
4 指针本身所占据的内存区
指针本身占了多大的内存?你只要用函数sizeof(指针的类型)测一下就知道了。在32位平台里,指针本身占据了4个字节的长度。
指针本身占据的内存这个概念在判断一个指针表达式是否是左值时很有用。

第二章 运算符和表达式

这里&是取地址运算符,*是...书上叫做"间接运算符"。
&a的运算结果是一个指针,指针的类型是a的类型加个*,指针所指向的类型是a的类型,指针所指向的地址嘛,那就是a的地址。
*p的运算结果就五花八门了。总之*p的结果是p所指向的东西,这个东西有这些特点:它的类型是p指向的类型,它所占用的地址是p所指向的地址。
例五:
int a=12;
int b;
int*p;
int**ptr;
p=&a;//&a的结果是一个指针,类型是int*,指向的类型是int,指向的地址是a的地址。
*p=24;//*p的结果,在这里它的类型是int,它所占用的地址是p所指向的地址,显然,*p就是变量a。
ptr=&p;//&p的结果是个指针,该指针的类型是p的类型加个*,在这里是int **。该指针所指向的类型是p的类型,这里是int*。该指针所指向的地址就是指针p自己的地址。
*ptr=&b;//*ptr是个指针,&b的结果也是个指针,且这两个指针的类型和所指向的类型是一样的,所以用&b来给*ptr赋值就是毫无问题的了。
**ptr=34;//*ptr的结果是ptr所指向的东西,在这里是一个指针,对这个指针再做一次*运算,结果就是一个int类型的变量。

一个表达式的最后结果如果是一个指针,那么这个表达式就叫指针表达式。
下面是一些指针表达式的例子:
例六:
int a,b;
int array[10];
int*pa;
pa=&a;//&a是一个指针表达式。
int**ptr=&pa;//&pa也是一个指针表达式。
*ptr=&b;//*ptr和&b都是指针表达式。
pa=array;
pa++;//这也是指针表达式。
例七:
char*arr[20];
char**parr=arr;//如果把arr看作指针的话,arr也是指针表达式
char*str;
str=*parr;//*parr是指针表达式
str=*(parr+1);//*(parr+1)是指针表达式
str=*(parr+2);//*(parr+2)是指针表达式

由于指针表达式的结果是一个指针,所以指针表达式也具有指针所具有的四个要素:指针的类型,指针所指向的类型,指针指向的内存区,指针自身占据的内存。
好了,当一个指针表达式的结果指针已经明确地具有了指针自身占据的内存的话,这个指针表达式就是一个左值,否则就不是一个左值。
在例七中,&a不是一个左值,因为它还没有占据明确的内存。*ptr是一个左值,因为*ptr这个指针已经占据了内存,其实*ptr就是指针pa,既然pa已经在内存中有了自己的位置,那么*ptr当然也有了自己的位置。

第三章 指针的算术运算

指针可以加上或减去一个整数。指针的这种运算的意义和通常的数值的加减运算的意义是不一样的。例如:
例二:
1。Char a[20];
2。int* ptr=(int*)a;
... 
3。ptr++;
printf("%c\n",*(ptr+1)); //会打印出a[4]的值,编译器是这样处理的:它把指针ptr的值加上了sizeof(int),
printf(“%d\n”*(ptr+1)); //打印a[4],a[5],a[6],a[7]各二进制位组成的int型值
4.ptr += 5;// 编译器是这样处理的:将指针ptr的值加上5乘sizeof(int),
5.printf(“%d\n”*ptr);//指针访问了a[20]之后的内存,结果未知,若是写操作,会有危险
在上例中,指针ptr的类型是int*,它指向的类型是int,它被初始化为指向整形变量a。接下来的第3句中,指针ptr被加了1,编译器是这样处理的:它把指针ptr的值加上了sizeof(int),在32位程序中,是被加上了4。由于地址是用字节做单位的,故ptr所指向的地址由原来的变量a的地址向高地址方向增加了4个字节。
由于char类型的长度是一个字节,所以,原来ptr是指向数组a的第0号单元开始的四个字节,此时指向了数组a中从第4号单元开始的四个字节。
总结一下,一个指针ptrold加上一个整数n后,结果是一个新的指针ptrnew,
ptrnew的类型和ptrold的类型相同,ptrnew所指向的类型和ptrold所指向的类型也相同。ptrnew的值将比ptrold的值增加了n乘sizeof(ptrold所指向的类型)个字节。就是说,ptrnew所指向的内存区将比ptrold所指向的内存区向高地址方向移动了n乘sizeof(ptrold所指向的类型)个字节。
一个指针ptrold减去一个整数n后,结果是一个新的指针ptrnew,ptrnew的类型和ptrold的类型相同,ptrnew所指向的类型和ptrold所指向的类型也相同。ptrnew的值将比ptrold的值减少了n乘sizeof(ptrold所指向的类型)个字节,就是说,ptrnew所指向的内存区将比ptrold所指向的内存区向低地址方向移动了n乘sizeof(ptrold所指向的类型)个字节。

第四章 指针类型转换

赋值运算符=成立的条件是:
1 左边的值必须为可修改的左值(l-value)
2 =两边的表达式结果类型必须一致
如果=两边是指针表达式,它还必须符合第三个条件
3 =两边的指针表达式所指向的类型必须一致。
当我们初始化一个指针或给一个指针赋值时,赋值号的左边是一个指针,赋值号的右边是一个指针表达式。在我们前面所举的例子中,绝大多数情况下,指针的类型和指针表达式的类型是一样的,指针所指向的类型和指针表达式所指向的类型是一样的。
例十四:
1   floatf=12.3;
2   float*fptr=&f;
3   int*p;
在上面的例子中,假如我们想让指针p指向实数f,应该怎么搞?是用下面的语句吗?
p=&f;
不对。因为指针p的类型是int*,它指向的类型是int。表达式&f的结果是一个指针,指针的类型是float*,它指向的类型是float。两者不一致,直接赋值的方法是不行的。至少在我的MSVC++6.0上,对指针的赋值语句要求赋值号两边的类型一致,所指向的类型也一致,其它的编译器上我没试过,大家可以试试。为了实现我们的目的,需要进行"强制类型转换":
p=(int*)&f;
如果有一个指针p,我们需要把它的类型和所指向的类型改为TYEP*TYPE,
那么语法格式是:
(TYPE*)p;
这样强制类型转换的结果是一个新指针,该新指针的类型是TYPE*,它指向的类型是TYPE,它指向的地址就是原指针指向的地址。而原来的指针p的一切属性都没有被修改。
一个函数如果使用了指针作为形参,那么在函数调用语句的实参和形参的结合过程中,也会发生指针类型的转换。
例十五:
voidfun(char*);
inta=125,b;
fun((char*)&a);
...
...
voidfun(char*s)
{
charc;
c=*(s+3);*(s+3)=*(s+0);*(s+0)=c;
c=*(s+2);*(s+2)=*(s+1);*(s+1)=c;
}
}
注意这是一个32位程序,故int类型占了四个字节,char类型占一个字节。函数fun的作用是把一个整数的四个字节的顺序来个颠倒。注意到了吗?在函数调用语句中,实参&a的结果是一个指针,它的类型是int*,它指向的类型是int。形参这个指针的类型是char*,它指向的类型是char。这样,在实参和形参的结合过程中,我们必须进行一次从int*类型到char*类型的转换。结合这个例子,我们可以这样来想象编译器进行转换的过程:编译器先构造一个临时指针char*temp, 然后执行temp=(char*)&a,最后再把temp的值传递给s。所以最后的结果是:s的类型是char*,它指向的类型是char,它指向的地址就是a的首地址。
我们已经知道,指针的值就是指针指向的地址,在32位程序中,指针的值其实是一个32位整数。那可不可以把一个整数当作指针的值直接赋给指针呢?就象下面的语句:
unsigned int a;
TYPE*ptr;//TYPE是int,char或结构类型等等类型。
...
...
a=20345686;
ptr=20345686;//我们的目的是要使指针ptr指向地址20345686(十进制

ptr=a;//我们的目的是要使指针ptr指向地址20345686(十进制)
编译一下吧。结果发现后面两条语句全是错的。那么我们的目的就不能达到了吗?不,还有办法:
unsignedinta;
TYPE*ptr;//TYPE是int,char或结构类型等等类型。
...
...
a=某个数,这个数必须代表一个合法的地址;
ptr=(TYPE*)a;//呵呵,这就可以了。
严格说来这里的(TYPE*)和指针类型转换中的(TYPE*)还不一样。这里的(TYPE*)的意思是把无符号整数a的值当作一个地址来看待。上面强调了a的值必须代表一个合法的地址,否则的话,在你使用ptr的时候,就会出现非法操作错误。

unsigned  char* s_cfque = (unsigned char*)0x800000;
想想能不能反过来,把指针指向的地址即指针的值当作一个整数取出来。完 全可以。下面的例子演示了把一个指针的值当作一个整数取出来,然后再把这个整数当作一个地址赋给一个指针:
例十六:
inta=123,b;
int*ptr=&a;
char*str;
b=(int)ptr;//把指针ptr的值当作一个整数取出来。
str=(char*)b;//把这个整数的值当作一个地址赋给指针str。
好了,现在我们已经知道了,可以把指针的值当作一个整数取出来,也可以把一个整数值当作地址赋给一个指针。

(未完待续)

 

第六章 数组和指针的关系

 1.指针数组:一个数组里存 放的都是同一个类型的指针,通常我们把他叫做指针数


组。


int * a[10];它里边放了10个int * 型变量,由于它是一个数组,已经在栈区分配了1


0个(int * )的空


间,也就是32位机上是40个byte,每个空间都可以存放一个int型变量的地址,这个


时候你可以为这


个数组的每一个元素初始化,或者单独做个循环去初始化它。


一个指针数组中的指针可以为任何同一类型,例如可以为结构指针、函数指针等

struct a

{

    int a;

 
    int b;

}

typedef struct a STRUCTA


STRUCTA* b[4];//一个存放了4个STRUCTA*型指针的数组,其大小为4*sizeof


(STRUCTA*)=16


typedef void(*FUNC)();


FUNC funarr[4];//定义了一个函数指针数组


2.结构数组

struct a

{

   int a;

   int b;

}a[12];//定义了一个结构数组,大小为12*sizeof(struct a) = 48;


3.数组指针 : 一个指向一维或者多维数组的指针;


int (*b2) [20];     //二级指针;b2指向一个大小为20*sizeof(int)的int型数组


int(*b3) [30] [20];  //三级指针――>指向三维数组的指针;


4.数组的数组名具备一些指针的用法,近似于指针,


例如:int array[12][31];//数组的嵌套定义,array是一个含有12个数组类型元素的数


组,其中的每一个


元素是一个int数组,array的类型是int[12][31],其指向的类型是int[31],可以理解为


array是指向数组


的指针。


array[1]是一个含有31个int型元素的数组,它的类型是int[31],它指向的类型是int;


int I;

I = array[4][7] 等同于 I = *(array[4]+7)  等同于 I = *(*(array +4)+7)


 int *p; int **q;  int (*ptr1)[31];  int (*ptr2)[41];


p = array[2];//正确,p指向数组array[2]中下标为0的元素


p = array; // 错误,array是二维数组,其类型为“数组的数组”,类型不匹配


q = array; //错误,array不是指向指针的指针


ptr1 = array; // 正确,同是指向数组int[31]的指针。


ptr2 = array;//错误,array是指向int[31]的指针,ptr2是指向int[41]的指针。


例九:

char*str[3]={


"Hello,thisisasample!",


"Hi,goodmorning.",


"Helloworld"

};


chars[80];


strcpy(s,str[0]);//也可写成strcpy(s,*str);


strcpy(s,str[1]);//也可写成strcpy(s,*(str+1));


strcpy(s,str[2]);//也可写成strcpy(s,*(str+2));


上例中,str是一个三单元的数组,该数组的每个单元都是一个指针,这些指针各指向


一个字符串。把


指针数组名str当作一个指针的话,它指向数组的第0号单元,它的类型是char**,


指向的类型是


char*。


*str也是一个指针,它的类型是char*,它所指向的类型是char,它指向的地址是字符


串"Hello,thisisasample!"的第一个字符的地址,即'H'的地址。 str+1也是一个指针,它


指向数组的第1号


单元,它的类型是char**,它指向的类型是char*。


*(str+1)也是一个指针,它的类型是char*,它所指向的类型是char,它指向


"Hi,goodmorning."的第一


个字符'H',等等。


5.下面总结一下数组的数组名的问题。声明了一个数组TYPE array[n],则数组名称


array就有了两重含


义:第一,它代表整个数组,它的类型是TYPE[n];第二 ,它是一个指针,该指针的


类型是TYPE*,该


指针指向的类型是TYPE,也就是数组单元的类型,该指针指向的内存区就是数组第0


号单元,该指针自


己占有单独的内存区,注意它和数组第0号单元占据的内存区是不同的。该指针的值是


不能修改的,即


类似array++的表达式是错误的。


在不同的表达式中数组名array可以扮演不同的角色。


在表达式sizeof(array)中,数组名array代表数组本身,故这时sizeof函数测出的是整个


数组的大小。


在表达式*array中,array扮演的是指针,因此这个表达式的结果就是数组第0号单元的


值。sizeof


(*array)测出的是数组单元的大小。


表达式array+n(其中n=0,1,2,....。)中,array扮演的是指针,故array+n的结果


是一个指针,它


的类型是TYPE*,它指向的类型是TYPE,它指向数组第n号单元。故sizeof(array+n)测


出的是指针类型


的大小。



例十:


int array[10];


int(*ptr)[10];


ptr=&array;


上例中ptr是一个指针,它的类型是int(*)[10],他指向的类型是int[10] ,我们用整个数


组的首地址来初


始化它。在语句ptr=&array中,array代表数组本身。


本节中提到了函数sizeof(),那么我来问一问,sizeof(指针名称)测出的究竟是指针自身类型的大小呢还


是指针所指向的类型的大小?答案是前者。例如:


int(*ptr)[10];


则在32位程序中,有:


sizeof(int(*)[10])==4


sizeof(int[10])==40


sizeof(ptr)==4


实际上,sizeof(对象)测出的都是对象自身的类型的大小,而不是别的什么类型的大小。

6  数组与指针的不同

引例:
文件 1
int mango[100];
文件 2

extern int  *mango;

.............  // 一些引用 mango[i] 的代码

错误:把数组的定义等同于指针的外部声明。

 

6 1 声明与定义

搞清楚这个问题之前,澄清一些重要概念:

C 语言中的对象必须有且只有一个定义,但它可以有多个 extern 声明。

 

 

概念

区别

定义

只能出现在一个地方,确定对象的类型并分配内存,用于创建新的对象。例如: int a[12]

相当于特殊声明,它为对象分配内存。

声明

可多次出现,描述对对象的类型,用于指代其他地方定义的对象。例如: extern int a[]

相当于普通声明,它所说明的并非自身,而是描述其他地方创建的对象。

 

由于 extern 声明不为对象分配内存,所以不必提供关于数组长度的信息。对于多维数组,需要提供除最左边一维之外其他维的长度——给编译器足够的信息产生相应代码。

 

6 2 输组与指针的访问过程

char a[9] = “abckefg”;                       c = a[i];

编译器符号表具有一个地址 9980

              运行时步骤 1 :取 i 的值,将它与 9980 相加;

              运行时步骤 2 :取地址 [9980+i] 的内容。

Char *p;                                                          c = *p;

编译器符号表有一个符号 p ,它的地址是 4624

              运行时步骤 1 :取地址 4624 的内容,就是 ’5081’

              运行时步骤 2 :取地址 5081 的内容。

 

6 3 定义为指针,但以数组方式引用的过程

char *p = “abchdefs”                                        c = p[i]

编译器符号表有个 p ,地址为 4624

              运行时步骤 1 :取地址 4624 的内容,即 ’5081’

              运行时步骤 2 :取得 I 的值,并将它与 5081 相加;

              运行时步骤 3 :取地址 [5081+i] 的内容。

 

如果将 p 声明为指针,那么不管 p 原来是定义为指针还是数组,都会按照上面的三个步骤操作。

如: char *p[10];

另一个文件中 extern char *p

当用 p[I] 提取这个声明中的内容时,实际上得到的是一个字符,而编译器却把它当作一个指针……

 

 

6 4 指针和数组的其他区别

指针

数组

保存数据地址

保存数据

间接访问数据,首先取得指针的内容,把它作为地址,然后从这个地址提取数据。如果指针有个下标 [I] ,就把指针的内容加上 I 作为地址,从中提取数据

直接访问数据, a[I] 只是简单的以 a+I 为地址取的数据。

通常用于动态数据结构

通常用于存储固定数目且数据类型相同的元素

相关函数为 malloc(),free()

隐式分配和删除

通常指向匿名数据

自身即为数据名

 

7 数组与指针相同时

7 1 输组与指针的可交换性

数组     声明:                extern 如:extern char a[];不能改写成指针形式

                            定义,如 char a[10];不能改写成指针形式

                            函数参数,如func(char a[]);可随意选择数组或指针

        在表达式中使用      如c = a[I];随意选择数组或者指针形式

 

规则 1 :“表达式中的数组名”就是指针。

规则 2 C 语言把数组下表作为指针偏移量

规则 3 :作为函数参数的数组名等同于指针

 

数组与指针可交换性总结:

1.   a[I] 这样的形式对数组进行访问总是被编译器解释为像 *(a+1) 这样的指针访问。

2.   指针始终就是指针。它绝不可以改写成数组。可以用下标形式访问指针,一般都是指针作为函数参数时,而且实际传递给函数的是一个数组。

3.   在特定的上下文环境中,也就是它作为函数的参数(也只有这种情况),一个数组的声明可以看作是一个指针。作为函数参数的数组(就是在一个函数调用中)始终会被编译器修改成为之乡第一个元素的指针。

4.   因此,当把一个数组定义为函数参数时,可以选择把它定义为数组,也可定义为指针。不管用那种方法,在函数内部事实上获得的都是一个指针。

5.   在其他所有情况中,定义和声明必须匹配。如果定义了一个数组,在其他文件对他进行声明时也必须把它声明为数组,指针也是如此。

 

7 2 多维数组

例:

int apricot[2][3][5];

int (*q)[2][3][5] = &apricot;

int (*p)[3][5] =  apricot;

int (*r)[5] = apricot[i];

int *t = apricot[I][j];

int u = apricot[I][j][k];

 

初始化:

只有字符串常量才可以初始化指针数组

char * vegetables[] = { “carrot”,“celery”,“corn”,“cilantro”,“crispy”};

指针数组不可以由非字符串的类型直接初始化:

int *weights[] = {{1,2,3,4,5},       {6,7,8},};    // 无法编译成功

可以这样做:

int row_1[] = {1,2,3,4,5,-1}; //-1 是行结束标志。

Int row_2[] = {6,7,8,-1};

Int *weights[] = {Row_1,Row_2,};

 

7 3 向函数传递一个一维数组

任何一维数组都可以作为函数实参,形参被改写为指向数组第一个元素的指针,所以需要一个约定来提示数组的长度。一般有两个基本方法:

1,   增加一个额外的参数,表示元素数目 (argc 就起这个作用 )

2,   赋予数组最后一个元素一个特殊的值,提示他是数组的尾部(字符串结尾的‘ \0 ’字符就是起这个作用)。这个特殊值必须不会做为正常的元素值在数组中出现。

 

7 4 使用指针向函数传递一个多维数组

C 语言无法表达“这个数组的边界在不同的调用中可以变化”这个概念。 C 语言必须知道数组边界,从而为下标引用产生正确代码。

二维或多维数组无法在 C 语言中作一般的形参。无法向函数传递一个普通的多维数组。

可以向函数传递预先确定长度的特殊数组。

 

方法 1 my_function( int my_array[10][20] );// 只能处理 10 20 列的数组。调用时参数也要匹配

方法 2 my_function( int my_array[][20] );// 只能处理 20 列的数组,调用时参数也要匹配

由于必须提供数组除最左边一维以外的所有维的长度,所以形参只能省略第一个长度。

方法 3 my_function( char **my_array ,…… );

此方法使用前提,必须在调用之前将二维数组改为一个指向向量的指针数组。必须是指针数组,而且必须是指向字符串的指针数组。

 

总结:如果多维数组各维的长度是一个完全相同的固定值,那么把它传给一个函数毫无问题。如果情况更一般些,也更常见一些,就是作为函数的参数的数组的长度是任意的,分析如下:

1,   一维数组——没有问题,但须包括一个计数值或者是一个能够标识越界位置的结束符。被调用的函数无法检测数组参数的边界。

2,   二维数组——不能直接传递给寒暑,但可以把矩阵改写为一个一维的指针数组,并使用相同的下标表示法。对于字符串来说,这样是可以的,对于其他类型,需要增加一个计数值或者能够标识越界位置的结束符。同样,他依赖于调用函数和被调用函数之间的约定。

3,   三维或更多维——都无法使用。必须把它分解为几个维数更少的数组。

1

int main( int argc, char *argv[] )// 由于字符串以 ’\0’ 作为结束标志,所以只需要一个 argc 计数有多少个字符串即可。

2

    int arr[2][3] = {{1,2,3},{4,5,6}};//将要进行传递的二维数组

做法1:

    int *p[2] = {arr[0],arr[1]};将二维数组改造成指针数组,每个指针指向一个一维数组

void fun( int rownum, int colnum ,int *array[]);

fun(2,3,p);//传递一个二维数组必须在传递之前将其转化为一个指针数组,传递时还要传递该二维数组的行数和列数。

做法2:

    int *p[3] = {arr[0],arr[1],NULL};将二维数组改造成指针数组,每个指针指向一个一维数组

void fun( in

作者:leeao   更新日期:2004-11-23
来源:upsdn特约撰稿   浏览次数:

相关文章

    相关评论   发表评论

    • leeao  [2004-11-23]

      做法2:

      int *p[3] = {arr[0],arr[1],NULL};将二维数组改造成指针数组,每个指针指向一个一维数组

      void fun(int colnum,int *array[]);//内部以NULL指针判断第一维的结束

      fun(3,p);//只需要传递数组的列数。

      在例2中,若arr[2][3]是char型,则参数还可以少一个。



      9.5 使用指针从函数返回一个数组

      严格的说,无法直接从函数返回一个数组。

      可以让函数返回一个指向任何数据结构的指针来实现:

      例:

      typedef  int (*PARR_20)[20]; //定义数组指针。

      PARR_20 paf(void) //定义一个函数,该函数返回一个指向20维int数组的指针。

      {

      PARR_20 pear;

      int i;

      pear = (PARR_20)calloc(20,sizeof(int));

      if(!pear)

      printf("error!!");

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

      (*pear)[i] = i;

      return pear;

      }

      调用如下:

      PARR_20 result;

      result = paf();

      printf("result[3] = %d",(*result)[3]);

     
    2007-09-07

    zhiwenshanghai

    posted on 2007-09-07 16:28 向左向右走 阅读(201) 评论(0)  编辑 收藏 引用

    只有注册用户登录后才能发表评论。