C语言指针基础预习

1.指针的类型与指针所指向的类型的区别

从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部


分就是这个指针的类型。这是指针本身所具有的类型。让我们看看例一中各


个指针的类型:


(1)int*ptr;//指针的类型是int*


(2)char*ptr;//指针的类型是char*


(3)int**ptr;//指针的类型是int**


(4)int(*ptr)[3];//指针的类型是int(*)[3]


(5)int*(*ptr)[4];//指针的类型是int*(*)[4]


指针所指向的类型


当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了


编译器将把那片内存区里的内容当做什么来看待。


从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声


明符*去掉,剩下的就是指针所指向的类型。例如:


(1)int*ptr; //指针所指向的类型是int


(2)char*ptr; //指针所指向的的类型是char


(3)int**ptr; //指针所指向的的类型是int*


(4)int(*ptr)[3]; //指针所指向的的类型是int()[3]


(5)int*(*ptr)[4]; //指针所指向的的类型是int*()[4]


在指针的算术运算中,指针所指向的类型有很大的作用。


指针的类型(即指针本身的类型)和指针所指向的类型是两个概念。


2.指针的算数运算与关系运算是如何实现的?

第一种形式是:指针+-整数 标准定义这种形式只能用于指向数组中某个元素的指针,并且这类表达式的结果类型也是指针。这种形式也适用于使用malloc函数动态分配获得的内存。

对一个指针加1使它指向数组中的下一个元素,加5使它向右移动5个元素的位置,依次类推。把一个指针减去3使它向左移动3个元素的位置。


第二种类型的指针运算具有如下的形式:指针—指针

只有当两个指针都指向同一个数组中的元素时,才允许从一个指针减去另一个指针, 两个指针相减的结果的类型是ptrdiff_t,它是一种有符合整数类型。减法运算的值是两个指针在内存中的距离是指针的本身(以数组元素的长度为单位,而不是以字节为单位),因为减法运算的结果将除以数组元素类型的长度。

只有当两个指针指向同一个数组中的元素时,才能进行关系运算。 
当指针p和指针q指向同一数组中的元素时, 
则: (可以用在if判断里面作为条件)

p<q 当p所指的元素在q所指的元素之前时,表达式的值为1;反之为0。 
P>q 当p所指的元素在q所指的元素之后时,表达式的值为1;反之为0。 
p==q 当p和q指向同一元素时,表达式的值为1;反之为0。 
p!=q 当p和q不指向同一元素时,表达式的值为1;反之为0。


3.常量指针与指针常量大的区别

常量指针是指--指向常量的指针,顾名思义,就是指针指向的是常量,即,它不能指向变量,它指向的内容不能被改变,不能通过指针来修改它指向的内容,但是指针自身不是常量,它自身的值可以改变,从而指向另一个常量。
指针常量是指--指针本身是常量。它指向的地址是不可改变的,但地址里的内容可以通过指针改变。它指向的地址将伴其一生,直到生命周期结束。有一点需要注意的是,指针常量在定义时必须同时赋初值。
注:也有人将这两个名称的定义与含义反过来认为:“指针常量:顾名思义它的中心词是“常量”这是重点,指针就是一个修饰的作用。所以这里的指针还是一个变量,它的内容存放的是常量的地址。常量指针:关键字是指针,它是不能被改变的,因为指针总是指向地址的,所以它的意思是它指向的地址是不能被改变的”。但我个人认为后者不合理,所以使用前者。
使用方法:
使用时写法上的区别:常量指针:const在*之前   指针常量:const在*之后。
  当然我们也可以定义常量指针常量,那就需要加上两个const,一前一后!以上只是从定义上给出两者的本质上的不同,在具体使用上,还有很多变化,但万变不离其宗,我们可以根据它的原理分析出各种复杂用法的实质。


4.指针数组与数组指针的区别

数组指针(也称行指针)
定义 int (*p)[n];
()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。


如要将二维数组赋给一指针,应这样赋值:
int a[3][4];
int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。
 p=a;        //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
 p++;       //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]


所以数组指针也称指向一维数组的指针,亦称行指针。


指针数组
定义 int *p[n];
[]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1是错误的,这样赋值也是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 *p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。
如要将二维数组赋给一指针数组:
int *p[3];
int a[3][4];
for(i=0;i<3;i++)
p[i]=a[i];
这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]
所以要分别赋值。


这样两者的区别就豁然开朗了,数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。
还需要说明的一点就是,同时用来指向二维数组时,其引用和用数组名引用都是一样的。
比如要表示数组中i行j列一个元素:
*(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j]

优先级:()>[]>*


5.sizeof与strlen的区别

一、sizeof
    sizeof(...)是运算符,在头文件中typedef为unsigned int,其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等。
    它的功能是:获得保证能容纳实现所建立的最大对象的字节大小。
    由于在编译时计算,因此sizeof不能用来返回动态分配的内存空间的大小。实际上,用sizeof来返回类型以及静态分配的对象、结构或数组所占的空间,返回值跟对象、结构、数组所存储的内容没有关系。
    具体而言,当参数分别如下时,sizeof返回的值表示的含义如下:
    数组——编译时分配的数组空间大小;
    指针——存储该指针所用的空间大小(存储该指针的地址的长度,是长整型,应该为4);
    类型——该类型所占的空间大小;
    对象——对象的实际占用空间大小;
    函数——函数的返回类型所占的空间大小。函数的返回类型不能是void。
**************
二、strlen
    strlen(...)是函数,要在运行时才能计算。参数必须是字符型指针(char*)。当数组名作为参数传入时,实际上数组就退化成指针了。
    它的功能是:返回字符串的长度。该字符串可能是自己定义的,也可能是内存中随机的,该函数实际完成的功能是从代表该字符串的第一个地址开始遍历,直到遇到结束符NULL。返回的长度大小不包括NULL。
*****************
三、举例:
    eg1、char arr[10] = "What?";
              int len_one = strlen(arr);
              int len_two = sizeof(arr); 
              cout << len_one << " and " << len_two << endl; 
    输出结果为:5 and 10
    点评:sizeof返回定义arr数组时,编译器为其分配的数组空间大小,不关心里面存了多少数据。strlen只关心存储的数据内容,不关心空间的大小和类型。
    eg2、char * parr = new char[10];
              int len_one = strlen(parr);
              int len_two = sizeof(parr);
              int len_three = sizeof(*parr);
              cout << len_one << " and " << len_two << " and " << len_three << endl;
    输出结果:23 and 4 and 1
    点评:第一个输出结果23实际上每次运行可能不一样,这取决于parr里面存了什么(从parr[0]开始知道遇到第一个NULL结束);第二个结果实际上本意是想计算parr所指向的动态内存空间的大小,但是事与愿违,sizeof认为parr是个字符指针,因此返回的是该指针所占的空间(指针的存储用的是长整型,所以为4);第三个结果,由于*parr所代表的是parr所指的地址空间存放的字符,所以长度为1。


6.函数指针与指针函数的区别

1、指针函数是指带指针的函数,即本质是一个函数。函数返回类型是某一类型的指针


     类型标识符    *函数名(参数表)


      int *f(x,y);

首先它是一个函数,只不过这个函数的返回值是一个地址值。函数返回值必须用同类型的指针变量来接受,也就是说,指针函数一定有函数返回值,而且,在主调函数中,函数返回值必须赋给同类型的指针变量。


表示:


float *fun();


float *p;


p = fun(a);


注意指针函数与函数指针表示方法的不同,千万不要混淆。最简单的辨别方式就是看函数名前面的指针*号有没有被括号()包含,如果被包含就是函数指针,反之则是指针函数。


来讲详细一些吧!请看下面


 指针函数:
    当一个函数声明其返回值为一个指针时,实际上就是返回一个地址给调用函数,以用于需要指针或地址的表达式中。
    格式:
         类型说明符 * 函数名(参数)
    当然了,由于返回的是一个地址,所以类型说明符一般都是int。
    例如:int *GetDate();
          int * aaa(int,int);
    函数返回的是一个地址值,经常使用在返回数组的某一元素地址上。

函数指针是指向函数的指针变量,即本质是一个指针变量。

 int (*f) (int x); /* 声明一个函数指针 */

 f=func; /* 将func函数的首地址赋给指针f */

指向函数的指针包含了函数的地址,可以通过它来调用函数。声明格式如下:
        类型说明符 (*函数名)(参数)
    其实这里不能称为函数名,应该叫做指针的变量名。这个特殊的指针指向一个返回整型值的函数。指针的声明笔削和它指向函数的声明保持一致。
        指针名和指针运算符外面的括号改变了默认的运算符优先级。如果没有圆括号,就变成了一个返回整型指针的函数的原型声明。


7.comst int *p与int const *p有无区别?如何定义const指针?以及const对指针的作用


无区别,都是定义的int const型的指针。

int * const p可定义int类型的const指针。

对于int const型的指针,*p的值不能改变,即p所指向的内容不能改变;对于const 指针,p的内容不能改变,即p里保存的地址不能改变,但是*p的值是可以改变的。


8.右左法则的应用

1.      第一次开始阅读声明的时候,必须从变量名开始,而不是从最内部的括号开始
2.      最后两个字是本质
3.      先从变量看起,向右看,碰到小括号后再向左看
4.      确定是变量后就要确定变量中保存的是什么值;确定是指针变量后就要确定指针保存的是什么的地址或指针变量指向什么值;确定是数组后就要确定数组中每一个元素的类型;确定是函数后就要说明函数的形参类型和返回值类型。
 
 
实例说明:
简单版:
int a ;     整型变量
int *a;    整型指针变量
int **a    整型指针的指针变量
int a[10]   整型数组
int *a[10]  整型指针数组
int (*a)[10]  数组指针变量
int (*a)(int)  函数指针变量
int (*a[10])(int )  函数指针数组
 
加强版:
int  *(*(*fp1)(int))[10];
声明一个函数指针变量,该指针指向形参是整型,返回值是数组指针的函数,该数组指针指向一个整型指针数组。
int  *(*(*arr[5])())();
声明一个函数指针数组arr,该数组中的每一个元素指向形参为空,返回值是函数指针的函数,该函数指针指向一个形参是空返回值是整型指针的函数
float  (*(*b())[])();
声明一个形参是空,返回值是数组指针的函数,该指针指向一个指针数组,数组中的每一个元素指向一个形参是空,返回值是float 型的函数。
void  *(*c)(char a, int (*b)());
声明一个函数指针变量,该指针指向返回值是 void * 类型,有两个形参的函数,该函数的第一个形参是字符变量,第二个形参是函数指针,指向一个形参是空,返回值是 int 型的函数。
float  (*(*e[10])(int*))[5];
声明一个函数指针数组,该数组中的每一个元素指向一个函数,该函数的形参是 int *类型,返回值是一个数组指针,该指针指向一个float 型数组。

猜你喜欢

转载自blog.csdn.net/cb673335723/article/details/78287736
今日推荐