王学岗c语言指针和指针运算

本文详细介绍了指针的基础概念、使用注意事项及高级应用,包括指针与地址的区别、初始化、二级指针、指针运算等内容。

关于指针有一片文章写的详尽又容易了解:http://blog.chinaunix.net/uid-22889411-id-59688.html

(1)指针和地址的区别
//指针有类型 地址没有类型,需要强制类型转化才能赋值给指针变量

int* p=(int*)0x44fc28

(2)指针使用之前必须要有初始值

void main(){
    int* p;

    //报空指针异常
    printf("%#x",p);



    getchar();
}

上文报错处可以这样写

int* p=NULL;

(3)指针变量多次赋值为不同变量的地址

void main(){
    int* p=NULL;


    printf("%#x",p);
    //200当做一个内存地址赋值给了指针变量(16进制)
    p = 200;
    //打印指针变量对应的值
    printf("%d\n", *p);
    getchar();
}

打印输出发现报错
200转成16进制,由于数字比较小,系统本身已经占用了这块内存区域,内存地址已经被分配掉了,然而系统本身内存数据不允许访问!一般情况下,我们不要直接给指针变量赋值为整数。
(4)NDK指针地址,二级指针

int a=100;
    int b=200;
    int* p1=&a;
     //p1保存的是a变量的地址——0x0022FDE0,通过该地址可以查询到a的值是100
    printf("p1地址:%#x\n",&p1);
    //指针变量也是变量,同样占据了内存空间,同样有地址,因此可以用一个指针指向它
    //这就称之为二级指针,
    //定义一个二级指针p2,&p1指针的地址
    int** p2=&p1;

    **p2=1000;
    printf("二级指针的地址:%#x",&p2);
    //a的值会变成1000,*是取值,&是取地址
    //p2保存的数据是p1的地址,*p2上的数据是p1上面的数据
    //p1保存的数据是a的地址,所以**p2实际上就是a的值
    printf("\na的值:%d",a);

        system("pause");

这里写图片描述

(4)指针运算(赋值运算符和算术运算)
算术运算(+,-,*,/)

void main(){
    int ids[]= {22,33,34,44,34,46,22,90};
    //打印数组
    printf("数组%#x\n",ids);
    //数组第一个元素地址
    printf("数组第一个元素地址 %#x",&ids[0]);
    //两个值相同
    system("pause");
}

控制台输出两个值相同
ids是常量指针,存储的是数组的首地址

继续大家会发现,数组在内存中的存储是连续的
这里写图片描述
我们 看下指针如何运算:

void main(){
    int ids[] = { 22, 33, 34, 44, 34, 46, 22, 90 };
    //打印数组
    printf("数组%#x\n", ids);
    //数组第一个元素地址
    printf("数组第一个元素地址 %#x\n", &ids[0]);
    //两个值相同
    int* p = ids;
    p++;
    printf("地址:%#x值:%d",p,*p);
    system("pause");
}

注意,p++后,*p的值变成了33(既数组的第二个元素),地址也变成了第二个元素的地址,因为int类型占4个字节,+1后就相当于+了一个int字节数,就是字节由de8+4=dec;
这里写图片描述

总结:p++每次向前移动sizeof(数据类型)个字节
下面我使用指针遍历数组

void main(){
    int ids[] = { 22, 33, 34, 44, 34, 46, 22, 90 };
    //打印数组
    printf("数组%#x\n", ids);
    //数组第一个元素地址
    printf("数组第一个元素地址 %#x\n", &ids[0]);
    //两个值相同
    int* p = ids;
    p++;
    printf("地址:%#x值:%d\n",p,*p);


    for (; p < ids + 8;p++){
        printf("值:%d\n",*p);
    }

    system("pause");
}

这里写图片描述

注意:让指针递增或者递减,一般情况下只有在数组遍历的时候才有意义,是基于数组在内存中的象形排列方式;
(5)指针运算(通过使用指针循环给数组赋值)
传统方法赋值

void main(){
    int ids[6] ;
    int*p = ids;
    //传统的写法赋值
    int i = 0;
    for (; i < 6; i++){
        ids[i] = i * 2;
    }
    //输出
    i = 0;
    for (; i < 6; i++){
        printf("值:%d",ids[i]);
    }
    system("pause");
}

这里写图片描述
指针赋值:

void main(){
    int ids[6] ;
    int*p = ids;

    int i = 0;
    for (; p < ids + 6;p++){
        *p = i * 2;
        i++;
    }
    i = 0;
    for (; i < 6; i++){
        printf("值:%d",ids[i]);
    }
    system("pause");
}

运行结果和上次运行结果一样;

(6)指针运算,数组内部的加减

void main(){
    int ids[] = {34,5,65,43,66,77,99};
    int* p = ids;
    p = p + 3;
    //*p的值是43
    printf("值:%d\n地址:%#x\n",*p,p);
    system("pause");
}

(7)指针运算指针大小比较
大小比较,都是在遍历数组的时候运用,其他情况下没用,指针地址相等,并不代表值相等;因为指针有类型
(8)NDK-指针运算-指针与数组的几种写法

int _tmain(int argc, _TCHAR* argv[])
{
    int ids[]={52,84,86,92,48,47,15,32};
    int i=0;
    for(;i<7;i++){
    //输出数据
        printf("%d  %#x\n",ids[i],&ids[i]);
        //ids就是常亮指针,就是一个首地址
        //ids+0等价于 &ids[0]
        //ids+1等价于 &ids[1]
        //以此类推……
        //ids+i 等价于&ids[i]
        //在地址墙面加*就是取值,所以
        //*(ids+i) 等价于 ids[i]
        printf("%d  %#x\n",*(ids+i),ids+i);
    }
    return 0;
}

这里写图片描述

(9)指针引用二维数组

int _tmain(int argc, _TCHAR* argv[])
{
    //两行三列的二维数组
    int ids[2][3]={23,58,4,58,69,79};
    //遍历二维数组,外层循环控制行,内存循环控制列
    int i=0;
    for(;i<2;i++){
    int j=0;
    for(;j<3;j++){
        printf("值:%d,地址:%#x  ",ids[i][j],& ids[i][j]);
    }
    //换行
    printf("\n");
    }
    printf("ids:%#x   &ids:%#x  *ids:%#x ",ids,&ids,*ids);
    getchar();
    return 0;
}

这里写图片描述
大家看下,我们发现ids,&ids,*ids的三个地址是一模一样。注意,地址相同,但并不代表值相同

int _tmain(int argc, _TCHAR* argv[])
{
    //两行三列的二维数组
    int ids[2][3]={23,58,4,58,69,79};
    //遍历二维数组,外层循环控制行,内存循环控制列
    int i=0;
    for(;i<2;i++){
    int j=0;
    for(;j<3;j++){
        printf("值:%d,地址:%#x  ",ids[i][j],& ids[i][j]);
    }
    //换行
    printf("\n");
    }
    printf("ids:%#x   &ids:%#x  *ids:%#x\n ",ids,&ids,*ids);
    printf("长度%d,        长度%d,          长度%d",sizeof(*ids),sizeof(*&ids),sizeof(**ids));
    getchar();
    return 0;
}

大家看下打印结果:
这里写图片描述
大家注意了,长度12说明ids代表行指针(指向一个拥有三个数组的元素),每行3个int类型,每个int类型是4个字节;
长度24说明&ids代表的是一个二维数组指针,24个int类型,每个int类型4个字节;
长度4,说明*ids代表数组的类型,指向该数组的数据类型的指针;如果是double类型的数组,则此处将是8;

再看下下面的代码

int _tmain(int argc, _TCHAR* argv[])
{
    //两行三列的二维数组
    int ids[2][3]={23,58,4,58,69,79};

 //打印结果是第一行的第一个元素23,即ids[0][0]
 printf("值:%d",**ids);
    getchar();
    return 0;
}

我们继续来推导,看下面的代码

int _tmain(int argc, _TCHAR* argv[])
{
    //两行三列的二维数组
    int ids[2][3]={23,58,4,58,69,79};
    //打印第二行,第二列
    printf("值:%d\n",ids[1][1]);
    //用指针来打印第二行,第二列
    printf("值%d",*(*(ids+1)+1));
    getchar();
    return 0;
}

ids代表行指针:ids+0代表第一行,
ids+1代表第二行,
以此类推,第N行为ids+n;

取某一行的第一个元素的指针:*(ids+i)
第一行第一个元素指针:*(ids+0)
第二行第一个元素指针:*(ids+1)
以此类推:*(ids+i)

ids代表首地址所以
取第一行第一个指针:*ids+0;
取第一行第二个指针:*ids+1;
取第一行第三个指针:*ids+2;
以此类推:*ids+j

把以上两个推理结合下,取第二行第二个元素的指针:
*(ids+1)+1
我们可以得出结论:(ids+i)+j,获取该地址的值为(*(ids+i)+j)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值