C语言指针

发布时间:2014-10-23 23:23:34
来源:分享查询网

指针变量是包含内存地址的变量,它指向内存中的一块区域,通过指针的值,可以间接访问到相应的内存单元的数据,并做相应的修改。 1、指针的定义和简单使用 定义一个指针变量和定义一般的变量类似,只需在变量名前面加一个“*”。对一个指针变量赋值可以用取地址符&来获取到一个变量的地址,如果要获得指针指向的内存区域的数据,用解参考运算符*(也称为间接运算符,它返回其操作数指向的对象的值)。指针的值为NULL(NULL是stdio.h中定义的符号变量,实际上是0)说明其不指向任何的内存单元,0是唯一直接可以赋值给指针变量的整数值。实际上,*和&是互补的,当两个运算符连续应用于一个指针变量时,无论顺序如何,运算结果相同。同时可以用printf中的格式化字符串%p来输出指针变量的值,下面是一个简单的程序。 #include <stdio.h> int main() { int a; a=9; //定义并初始化一个指针,命名就可以看出 int *aPtr=NULL; //将指针指向变量a aPtr=&a; printf("The address of a is %p" "\nThe value of aPtr is %p",&a,aPtr); printf("\n\nThe value of a is %d" "\nThe value of *aPtr is %d",a,*aPtr); printf("\n\nShowing that * and & are complements of " "each other\n&*aPtr = %p" "\n*&aPtr = %p\n",&*aPtr,*&aPtr); return 0; } 运行结果如下: 2、用指针做函数的参数 2.1 通过指针实现的引用传递 程序设计语言的参数传递方式,大致分两种:值传递和引用传递。C语言中没有引用传递,但是C语言通过指针间接实现了引用传递。通过用指针变量作为函数的参数,可以传递变量的地址(只需要在变量前面加上&运算符就可以),这样,用该地址就可以访问到主调函数中的该变量的内存地址,并可以进行相应的修改。这样,在函数执行完毕之后,修改仍然可以得到保留。 2.2 const const限定符可以告诉编译器特定的变量的值是不能被修改的。如果想确保函数不会修改传递进来的参数值,应该将参数声明为const。这样对于C语言中用指针实现的引用传递,有四种情况:指向非常量数据的非常量指针(int *aPtr),指向非常量数据的常量指针(int *const aPtr),指向常量数据的非常量指针(const int *aPtr)和指向常量数据的常量指针(const int * const aPtr)。简单的说,就是指针变量自身和指针指向的变量都有可能是const,这样就产生了四种情况,这四种情况提供了四种不同的访问权限,下面分别解释。 指向非常量数据的非常量指针(int *aPtr):指针的值本身和指针指向变量的值都可以在函数中被修改。 指向非常量数据的常量指针(int *const aPtr):指针的值不能被修改,但是指针指向的变量的值可以被修改。 指向常量数据的非常量指针(const int *aPtr):指针指向的值不能被修改,但是指针本身的值可以被修改。 指向常量数据的常量指针(const int * const aPtr):指针本身和指针指向变量的值都不能被修改。 从别的书上看到的一个记忆的方法,沿着*划一条线:如果const位于*的左侧(如const int *aPtr),那么可以理解为const是修饰指针指向的变量,这样就不能通过该指针间接地修改该变量的值;如果const位于*的右侧(int *const aPtr),那么说明这个const是修饰的指针本身,这样的话就不可以修改该指针使它指向其它变量;如果两边都有const(const int * const aPtr),那说明指针本身和指针指向变量的值都不可以修改。至于左侧右侧容易记混的问题,其实很容易解决,因为这样想就好了,*左侧是指针指向的变量类型啊,const放在这儿,很明显是在修饰指针指向的对象啊,记住左侧,右侧就反着好了。 3、sizeof和指针运算 3.1 sizeof sizeof是C语言中特殊的一元运算符,可以应用在变量名称、数据类型和常量之前,它在程序编译期间以字节为单位来确定数组或其他数据类型的大小。当应用于数组时,sizeof返回数组中的字节总数。如float a[20],sizeof(a)的值应该是4*20,80。当然,如果想获得数组的大小可以采用sizeof(a)/sizeof(float)。 3.2 指针运算 实际上,指针变量可以进行的算术操作是有限的:递增,递减,将指针和整数相加,从指针中减去一个整数或者一个指针减去另一个指针。需要注意的是,对于指针的算术运算,其单位长度并不是一般意义上的1,而是sizeof(TYPE)。这样,如果float a[14]; float *aPtr=a;(或者int *aPtr=&a[0]); aPtr++;这样aPtr应该指向的是数组a的第二个元素,也就是a[1],这里的单位长度就是sizeof(float)。同样地,如果aPtr=aPtr+5;,这样aPtr又指向了数组a的第6个元素。如果aPtr-a,这样可以得到两个指针之间的元素间隔个数。应该是6。 进行指针运算要注意: (1)如果将一个指针的值赋给另外一个指针,那么这两个指针的类型必须相同,否则应该用类型转换运算符进行类型转换。但是,有一个例外就是指向void类型的指针,它是通用指针,可以代表任何指针类型。因此,所有指针类型都可以赋值给void指针,而void指针也可以赋值给任何类型的指针,而不需要任何类型转换运算符。但是,void指针不能解参考,编译器知道指向int类型的指针引用的是32位计算机上的4个字节内存,但指向void的指针仅包含未知数据类型的内存位置,也就是说,编译器不知道指针所引用的字节数。编译器必须知道数据类型,才能确定所引用的字节数。 (2)除非两个指针变量都指向的是一个数组中的元素,否则对它们相减的结果没有任何意义,因为我们不能假设两个变量在内存中是连续的。 4、指针和数组 4.1 数组和指针的共性 实际上,数组名称的本质是一个常量指针。因此,int a[6]; int *aPtr;定义一个数组和指针之后,通过a[3],*(a+3)和*(aPtr+3)都可以访问到数组的第四个元素的值。但是区别在于,aPtr=aPtr+3;这样aPtr就指向了a数组的第四个元素,但是,不能a=a+3;,因为a是一个数组名,它是一个常量指针它的值不能被修改,更加具体地说,它应该是一个指向非常量数据的常量指针。 4.2 指针数组 数组元素也可以是指针类型,指针数组常见的用途就是构成由字符串组成的数组,简单地说就是字符串数组,数组中的每一个元素都是字符串。下面是一个例子,const限定符说明不能修改每个元素指针所指向的字符串。 #include<stdio.h> int main() { const char *suit[4]={"Hearts","Diamonds","Clubs","Spades"}; int i; for(i=0;i<4;i++) printf("sizeof pointer to \"%s\" :%d\n",suit[i],sizeof(suit[i])); printf("\nsizeof suit:%d\n",sizeof(suit)); return 0; }运行结果如下: 从这个例子中,可以看出const char *suit[4]={"Hearts","Diamonds","Clubs","Spades"};定义了一个指针数组,但是,其中的每个元素只是一个指针,而不是数组名(如果是数组名的话,sizeof的结果不应该都是4)。这样定义字符串数组可以节省空间。 5、函数指针 和数组名实际上就是数组第一个元素在内存中的地址类似,函数迷你实际上就是执行函数任务的代码在内存中的起始地址。函数指针包含函数在内存中的地址,可以传递给函数、从函数返回、存储在数组中或者是赋值给其它的函数指针,下面是两个函数指针的例子。 (1) 用函数指针实现升序/降序排序 #include <stdio.h> #define SIZE 10 int ascending(int a,int b) { return a>b; } int descending(int a,int b) { return a<b; } void swap(int *aPtr,int *bPtr) { int temp=*aPtr; *aPtr=*bPtr; *bPtr=temp; } void bubble(int work[],const int size,int(*compare)(int a,int b)) { int pass; int count; for(pass=1;pass<size;pass++) for(count=0;count<size-pass;count++) { if((*compare)(work[count],work[count+1])) swap(&work[count],&work[count+1]); } } int main() { int order; int counter; int a[SIZE]={2,6,4,8,10,12,89,68,45,37}; printf("\nData items in original order:\n"); for(counter=0;counter<SIZE;counter++) printf("%5d",a[counter]); printf("\nEnter 1 to sort in accending order,\n" "Enter 2 to sort in descending order: "); scanf("%d",&order); if(order==1) { bubble(a,SIZE,ascending); printf("\nData items in ascending order:\n"); } else { bubble(a,SIZE,descending); printf("\nData items in descending order:\n"); } for(counter=0;counter<SIZE;counter++) printf("%5d",a[counter]); printf("\n"); return 0; }运行结果如下: (2) 函数指针数组 #include<stdio.h> void function1(int a); void function2(int a); void function3(int a); int main() { void (*f[3])(int)={function1,function2,function3}; int choice; printf("Enter a number between 0 and 2, 3 to end: "); scanf("%d",&choice); while(choice >=0 && choice<3) { (*f[choice])(choice); printf("Enter a number between 0 and 2, 3 to end: "); scanf("%d",&choice); } printf("Program execution completed.\n"); return 0; } void function1(int a) { printf("You entered %d so funtion1 was called\n\n",a); } void function2(int a) { printf("You entered %d so funtion2 was called\n\n",a); } void function3(int a) { printf("You entered %d so funtion3 was called\n\n",a); }运行结果: 参考<C语言程序设计经典教程>,呵呵,基本算是摘取了。Whatever,说明白最重要。

返回顶部
查看电脑版