C指针(一)

C指针(一),第1张

概述原文链接:http://www.orlion.ga/916/ 一、指针的基本 *** 作 例: "&"是取地址符,&i表示取变量i的值,int *pi = &i;表

原文链接:http://www.orlion.ga/916/

一、指针的基本 *** 作

    例:

int i;int *pi = &i;char c;char *pc = &c;

    "&"是取地址符,&i表示取变量i的值,int *pi = &i;表示定义一个指向int型的指针变量pi,并用i的地址来初始化pi。全局变量只能用常量表达式初始化,如果定义int p = i;就错了,因为i不是常量表达式,然后用i的地址来初始化一个指针却没有错,是因为i的地址是在编译链接时能确定的,而不需要到运行时才知道,&i是常量表达式。后面两行定义了一个字符型变量c和一个指向c的字符型指针pc,注意pi与pc虽然是不同类型的指针变量,但他们的内存单元都占4个字节,因为要保存32位的虚拟地址,同理在64位平台上指针变量都占8个字节。如果要让pi指向另外一个整型变量可以重新对pi赋值:pi = &j;如果要改变pi所指向的整型变量的值,比如把变量j的值加10,可以:

*pi = *pi + 10;

    指针之间可以相互赋值,也可以用一个指针初始化另一个指针:

int *ptri = pi;

    或者:

int *ptri;ptri = pi;

    表示pi指向哪就让ptri指向哪,本质上是把变量pi所保存的地址值赋给变量ptri。

    用一个指针给另一个指针赋值时要注意,两个指针必须是同一类型的,pi是int *型,pc是char * 型,pi = pc这样赋值就是错误的。但是可以先强制类型转换:

pi = (int *)pc;

    有一种情况需要注意:

int main(voID){    int *p;    ...    *p = 0;    ...}

    在堆栈上分配的变量初始值是不确定的,也就是说指针p所指向的内存地址是不确定的,后面用*p访问不确定的地址就会导致不确定的后果,如果导致段错误还比较容易改正,如果意外改写了数据而导致随后的运行中出错就不好调试了。像这种指向不确定地址的指针称为野指针(Unbound Pointer),为避免野指针,在定义指针变量时就应该给它明确的初值,或者把它初始化为NulL:

int main(voID){    int *p = NulL;    ...    *p = 0;    ...}

    NulL在C标准库的头文件stddef.h中定义:

#define NulL ((voID *)0)

    就是把地址0转换为指针类型,称为空指针,它的特殊之处在于 *** 作系统不会把任何数据保存在地址0及其附近,也不会把地址0-0xfff的页面映射到物理内存,所以任何对地址0的访问都会立刻导致段错误。*p = 0会导致段错误。

    
    在编程时经常需要一种通用指针,可以转换为任意其他类型的指针,任意其他类型的指针也可以转换为通用指针。只能定义voID *类型的指针而不能定义voID型的变量,因为voID *指针和别的指针都一样占4个字节,而如果定义voID变量(也就是类型不确定的变量)编译器不知道应该分配几个字节给变量。voID *指针不能直接Dereference,而必须先转换成别的类型的指针再做Dereference。voID *指针常用于函数接口:

voID func(voID *pv){        /* *pv = 'A' is illegal */        char *pchar = pv;        *pchar = 'A';}int main(voID){        char c;        func(&c);...}

    

二、指针类型的参数和返回值

#include <stdio.h>

int *swap(int *px,int *py)

{

        int temp;

        temp = *px;

        *px = *py;

        *py = temp;

        return px;

}

int main(voID)

        int i = 10,j = 20;

        int *p = swap(&i,&j);

        printf("Now i=%d j=%d *p=%d\n",i,j,*p);

        return 0;

}

    

    尽管在swap函数的作用域中访问不到i和j这两个变量名,却可以通过地址访问它们,最终swap函数将i和j的值做了交换。

三、指针与数组

    

int a[10];int *pa = &a[0];pa++;

    对于上边的这个例子,指针pa指向a[0]的地址,后缀运算符的优先级高于单目运算符,所以是取a[0]的地址,而不是取a的地址。然后pa++让pa指向下一个元素(也就是a[1]),由于pa是int *指针,一个int型元素占4个字节,所以pa++使pa指向的地址加4而不是1。

    *(pa+2)等价于pa[2],pa就像数组名一样。a[2]之所以能取数组下标为2的元素是因为它等价于*(a+2),数组名做右值时自动转为指向首元素的指针,所以a[2]与pa[2]本质上是一样的。由于(*((E1) + (E2)))等价于(*((E2) + (E1))),所以a[2]可以写成2[a]。另外由于a做右值使用时和&a[0]是一个意思,所以int *pa = &a[0]通常会写成int *pa = a;

    C语言规定只有指向同一个数组中元素的指针之间相互比较才有意义,否则没有意义。那么两个指针相减表示什么?pa – a等于几?因为pa – 1 == a,所以pa – a显然应该等于1,指针相减表示两个指针之间相差的元素个数,同样只有指向同一个数组中元素的指针之间相减才有意义。两个指针相加表示什么?想不出来它能有什么意义,因此C语言也规定两个指针不能相加。

总结

以上是内存溢出为你收集整理的C指针(一)全部内容,希望文章能够帮你解决C指针(一)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1209773.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-04
下一篇 2022-06-04

发表评论

登录后才能评论

评论列表(0条)

保存