指针

来源:互联网 发布:linux入门那本书好 编辑:程序博客网 时间:2024/05/13 08:24

c语言不存在字符串类型,但提供字符串常量。c语言里面字符串常量的定义是:一串以NUL字节结尾的零个或多个字符。字符串通常存储在字符数组中,这也是c语言没有现实地提供字符串类型的原因。由于NUL字节是用于终结字符串的,所以在字符串中不能有NUL字节。不过,这个限制一般不会造成什么问题。之所以选择NUL,是因为它是一个不可打印的字符。字符串的书写如下:

"Hello" "\aWarning\a""Line 1\nLine2"""

最后一个表明即使是空字符串,依然存在作为终结符的NUL字节。

注意:不能把字符串常量赋值给一个字符数组,因为字符串常量作为一个赋值语句的右边时它是一个指向自己的指针而不是字符本身。

如:char *p="message";则指针p指向字符串的第一个地址


1.int a=102;

int b=-1;

int *p=&a;

int *q=&b;

那么a的值是102,b的是-1,p的值是a这个数的内存地址不是102,q的值是b的内存地址。

间接访问(解引用指针):通过一个指针访问它所指向的地址的过程。如*p的值就是102,*q的值就是-1.

2.未初始化和非法的指针

int *a;//创建了一个名叫a的指针

*a=12;//把12赋值给存储在a所指向的位置。

从上面的两条语句可以发现我们并不知道a到底指向什么位置,即未对它进行初始化,我们无法知道12这个值到底存储在什么地方。如果变量是静态的,它会被初始化为0,但如果是自动的,它根本不会被初始化。无论哪种情况,声明一个指针都不会创建存储其类型的内存空间。所以在使用指针之前,必须对其进行初始化的工作。

3.NULL指针

NULL指针并不指向任何东西,要使一个指针为NULL指针,可以给它赋一个0值。为了测试一个指针是否为NULL指针,可以将它与0进行比较。

NULL指针是非常有用的,它表示了某个特定的指针目前并未指向任何东西。比如在查找时,找不到就返回NULL,则可根据这个NULL值来进行相关的操作。

所以使用指针的时候,如果你已经知道了它将被初始化在什么位置,你可以将它初始化为该地址,否则就初始化为NULL指针。

4.指针、间接访问和变量

int *&a=25;

这就话中&a先产生a的地址,接着*操作表示解除引用表示访问地址指向的单元,所以这句话将25存于a中。

一般用int a=25即可而不用上面的语句。

5.指针常量

如果a存放的地址是100,那么*100=25并不表示将25赋值给a,因为指针解除引用的间接访问操作的对象是指针不是整型数100,应该使用这个语句*(int *)100=25强制转换之后才可以。

6.指针的指针

int a=12;

int *b=&a;

int *c=&b;

则它们之间的关系就为:a<--b<--c;一个指向一个。c是一个指向指针的指针,这里&b的操作是正确的,因为指针变量和其他变量一样,是对地址的一种表示,对其进行&运算就是取它的地址,这里不可以用int *c=b;这样的话c就与b指向同一个a的地址,不是指针的指针了。

int **c;表示表达式**c的类型是int。

int a=12;

int *b=&a;

int **c=&b;

现在对最后一个表达式进行分析,*的操作符是从右向左结合的,所以这个表达式相当于*(*c),我们必须从里往外进行分析,*c是指c指向的位置,我们知道这是变量b(因为如int *c=&b;则c指向b,它相当于int *c;c=&b;这两句,注意赋值时要把定义时int *c中c前面的*去掉即为c=&b;而int **c=&b就相当于int **c;*c=&b;去掉一个*号,所以c为指针的指针,所以表达式**c即为a的值即为int型。),外面的*就表示解除引用,表示访问这个位置指向的地址,也就是变量a。

所以我们可以知道下面的对应情况:

表达式 相当于的表达式

a 12

b &a

*b a即12

c &b

*c b即&a

**c *b即a即12

所以可以知道对指针的操作就是要不断地代入去观察。


指针表达式:

char ch='a';

char *cp=&ch;

ch作为右值时表示的是'a',作左值时表示的是'a'的地址(如ch='b';)

&ch作为右值表示指向ch的指针,作为左值时非法,因为&ch为ch地址,不可以为地址赋值。

&cp作为右值时表示的是指针的指针,不可以作为左值,不可以为地址赋值。

cp作为右值表示它指向的地址,作为左值表示它指向的地址,所以都是合法的。注意与&ch区分,cp为指针,&cp为地址。

*cp+1作为右值表示cp所在的值加1,作为左值时表示cp所在值加1,为一个常量,这里为'b'('a'+1='b'),不可以给b赋值,所以作为左值时它是非法的。

*(cp+1)可以最为左值,因为此时它表示的是cp+1这个位置的值,可以给该位置赋值,所以可以作为左值,作为右值即表示此处的值。

++cp不可以作为左值,因为++进行的是拷贝的运算,所以++cp是拷贝的是一个存储位置,而不可以赋值给存储位置,所以非法,cp++作为左值也是非法的。*++cp作为右值表示的是内存地址的值,作为左值是那个位置本身的值。*cp++右值是ch的值,左值是ch的内存位置的值,而++优先级大于*的,但这里涉及三个操作(1)++操作符产生cp的一份拷贝(2)++增加cp的值(3)在cp的拷贝上执行间接访问操作。++*cp作为左值是非法的,此时++与*都是右结合,所以先执行*运算,之后表达式的值为'b',而不能给b赋值,所以出错;可以作为右值。(*cp)++不可以作为左值,可以作为右值,原理和上一个一样。++*++cp不可以作为左值,因为相当于++(*(++cp));++cp指向cp下一个位置,加上*号表示该位置的值,在++表示对该位置的值加1的拷贝,所以不可以作为左值,只可以作为右值。++*cp++;++优先级高于*,所以相当于++(*(cp++))与上面一样不可以作为左值,只可以作为右值。


char *p="1234";

则执行*p='2';是错误的,因为"1234"是一个常量,不可以对其进行修改


char s[]="1234";

char *p=s;

*p='2';是对的,因为s是一个字符数组,不是常量,可以对其进行修改。


*p++--;是错误的,P++后返回的是一个拷贝,不可以再对其进行修改。


int a;

a++--;都不行,因为返回拷贝,不可以对其进行修改。


指针运算:

float占4的字节,在计算float型指针加3的时候,这个3将根据float类型的大小(比如为4)进行调整,这样,实际加到指针上的整型值为3*4=12。

第一种运算:指针+-整数

第二种运算:指针+-指针。这种情况只有当两个指针都指向同一个数组中的元素时才可以进行此操作(如果指向不同数组中的元素,那么结果是未知的)。两指针相减的结果是两个指针的距离(以数组元素的长度为单位,不是以字节为单位,因为减法运算的结果将除以数组元素类型的长度),如p1指向a[i]],p2指向a[j],则p2-p1的值就是j-i的值。现在来看一下具体过程:假设数组元素的类型是float,每个元素占据4个字节的内存空间,数组起始位置为1000,p1的值为1004,p2的值为1024,则p2-p1=5,因为两个指针的差值为20再除以长度4即为5,实际上p1对应a[i]而p2对应a[i+5],所以为5。

当对指针进行>,<,>=,<=的关心运算时,运算对象也是指针指向的地址,用地址的大小去比较,但只有当两个指针都指向同一个数组中的元素时才可以进行此操作(如果指向不同数组中的元素,那么结果是未知的),一般而言,数组后面元素的地址都大于前面的。

0 0
原创粉丝点击