在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
25 第四章 指针指针代表地址,即使用名字来替换地址,它存储的就是一个地址值。名字与内存位置之间的关联并不是硬件所提供的,它是由编译器为我们实现的。这些指针变量名给了我们一种更方便的方法记住地址——硬件仍然通过地址访问内存的位置。 每个变量都是包含了一序列内容为0或1的位,它们可以被解释为整数,也可以被解释为浮点数,这取决于被使用的方式。如果使用的是整型算术指令,这个值就被解释为整数,如果使用的是浮点型指令,它就是个浮点数。 指针图示: 注意箭头起始于方框内部,因为它代表存储于该变量的值。同样,箭头指向一个位置,而不是存储于该位置的值,这种记法提示跟随箭头执行间接访问操作的结果将是一个左值(即某个变量的地址,如&a,而不是某个变量a的值)。 int *a; *a =12; 上面的程序是极为危险与错误的。这个声明创建了一个名叫a的指针变量,后面那个赋值语句把12存储在a所指向的内存位置。因为从未对a进行初始化,所以我们没有办法预测12这个值将存储于什么地方。虽然如果变量a是静态的它会被初始化为0,变量为自动的,它根本不会被初始化,但无论是哪种情况,声明一个指向整型的指针都不会“创建”用于存储整型值的内存空间(只有声明一个非指针变量时才会分配存储空间)。该程序在不同的编译器中会产生不同的结果,运气好的话,提示内存错误,运行不好的话,程序表面上会正常结束,而且*a值是正确的,但是这里隐藏了一个极为严重的错误并且一旦出现很难发现:a会覆盖内存中原先随机初始化指向的某个位置的值。所以,在对指针进行间接访问之前,必须非常小心,确保它们已被初始化,如: int b, *a;//此时的指针随机指向某个存储空间 printf("%d\n", a);//随机指向的位置:2147348480 a = &b;//初始化指针,让它指向某个确定的内存空间 printf("%d\n", a);//现在指针所指向的位置为:2293576 *a = 12;//将12常量存储到a所指向的某个内存位置 printf("%d\n", *a);//12 printf("%d", b);//12 NULL指针不指向任何东西。要使指针变量为NULL,你可以给它赋一个零。为了测试一个指针变量是否为NULL,你可将它与零值进行比较。之所以选择零这个值是因为一种约定,就不同机器内部而言,NULL指针实际值可能不是零,在这种情况下,只要使用NULL,编译器将负责零值和内部值之间的翻译转换工作。 如果对一个NULL指针进行间接访问会发生什么情况呢?结果会因编译器而异,在有些机器上,它会访问位置为零的地址中的内容,但这是极其错误的;在其他机器上,对NULL指针进行间接访问将引发一个错误,并终止程序,这种情况下程序员就很容易提示发现错误,如XP就是这样的: //将字符数组(字符串就是数组)首地址赋给p1 char *p1="a" ; printf("%c",*p1);//a //将指针指向内存地址为0的位置 char *p2=NULL ; printf("%c",*p2);//!!出错 int a; *&a=12; 上面程序的结果就是将12赋值给变量a。&操作符产生变量a的地址,它是一个指针常量,接着,*操作符访问其操作数所表示的地址,在这个表达式中,操作数是a的地址,所以25就存储到a中。这与 a = 12 有区别吗?从结果上讲没有区别,但它涉及到更多的操作。 假定a存储于位置100,下面这条语句合法吗? *100 = 12; 这是错误的,因为字面值100的类型是整型值,而间接访问操作只能作用于指针类型表达式。如果你确实想把12存储于位置100,你必须使用强制类型转换: *(int *)100 = 12;//将100从整型转换为指向整型的指针类型 虽然强转后合法,但通常我们不会这样作,因为我们无法预测编译器会把某个特定的变量放在内存中的什么位置,所以你无法预先知道变量a的地址。这个技巧除非用来访问内存中某个特定的位置,不是某个变量,而是访问硬件本身。 二级指针(指针的指针): int a = 12; int *b = &a; int**c = &b;
各种指针表达式示例: char ch = 'a'; char *cp = &ch; 现在我们有了两个变量,它们初始化如下:
|
请发表评论