4.疯狂指针-壹

转载请标明出处:http://blog.csdn.net/u012637501

   内存的存储是以一个字节为一个编号,也就是8位合在一起给一个编号,不是0,1就给编号。 内存分为很多个单元,每个单元就会分配一个编号。
指针核心:
    (1)数据类型 * 变量名:* 表示该变量为指针变量,存放的是(数据类型)变量的 存储地址,如int *p=&i;
    (2)* 指针变量:*表示指向"以指针变量的内容为存储地址的 变量",如*p=i;
一、指针概念
1.地址:地址就是内存单元的一个编号,从0开始的非负整数,范围为0~FFFFFFFFF(0~4G-1).CPU对内存是通过控制、数据、地址三条总线来进行控制的。
◆控制:cup会先把内存中的数据读入,进行处理后,在返回给内存,然后内存在把数据写入硬盘。
◆数据:用于数据的传输,不管是把内存中的数据发送给cpu,还是把cpu的数据写如内存条,都是由数据线来完成的,但是数据传输的方向则是由控制线来控制的。
◆地址:地址线则是确定数据要写入内存中的那个单元,所谓的一个单元就是一个字节。
   一条地址总线能控制2的1次方,一般的机器有32个地址线,最终能够控制2的32个单元,而每个单元是八位,而最终我们的内存能够存储2的32次方*8位。 则换算为G的话,最终大小为4G.那么地址总线的范围则是4G大。
2.指针:指针就是地址,地址就是指针。指针的本质是,一个操作受限的非负整数。
        指针的重要性:
            ◇通过指针表示一些复杂的数据结构;
            ◇指针实现快速传递数据,减少了内存的耗用;
            ◇使函数返回一个以上的值;
            ◇指针能够直接访问硬件,且方便处理字符串。
3." "的作用
(1)定义指针变量:如int *p;,即定义了一个名字叫p的变量(称指针变量),int *表示只能存放int类型变量的地址;
(2)指针运算符:该运算符放在已经定义好的指针变量的前面,如果p是一个已经定义好的指针变量,则*p表示以p的内容为地址的变量,如*p=i,*p代表的是p所指向的那个变量i。
4.指针变量:同样是一个变量,但是指针变量存放其他变量的地址。
§举例1:int * p;
            int i=10,j;
            p=&i;
            j=*p;结果:j=10。
    详解:(1)如果去掉"p=&i",那么指针变量p存放的地址是随意的。
                (2)int * p:p是变量的名字,int *表示p变量存放的int类型变量的地址。int * p即p是变量
                      名,p变量的数据类型是int *类型,所谓"int *类型"实际就是存放int变量地址的类型。
                (3)p=&i:指针变量p保存了i的地址,指针变量p指向了普通变量i *p=i*p就是以p的内容
                       为地址的变量修改p的值不影响i的值,修改i的值也不会影响p的值
§举例2:int i=10;
              int * p=&i;    即等价于 int * p;    p=&i;
         详解: int * p=&i,即指针变量p保存的是int类型变量的地址。
注意:指针与指针变量是两个不同的概念,指针的本质就是一个操作受限的非负整数。
§举例3:
#include<stdio.h>
int  main(void)
{
     int *p,*q;
     int i=10;
     p=&i;            //如果*p=i,则编译通过但运行出错,只能int *p=&i;或者 int * p;    p=&i;
    *p=q;            //类型不同,语法错误
   // *p=*q;        //编译通过,运行出错,因为q没有赋值。
    //p=q;            //编译通过,运行出错,因为q是垃圾值赋值给p,p也变成垃圾值
     printf("%d\n",*p);
   // print("%d\n",*q);//编译通过,运行出错
     return 0;
}
详解:(1)*q代表的是整形,因为*q代表的是以q的地址为内容的变量。而p是地址(int *)类型。
            (2)打印*q时出错。因为q的空间是属于本程序的,所以本程序可以读写q的内容(地址)。但是如果q内部是垃圾值(未知地址),则本程序不能读写*q的内容(变量的值),因为此时*q所代表的内存单元的控制权限并没有分配给本程序,所以本程序运行print("%d\n",*q);时就会立即出错。
5.如何通过被调函数修改主调函数中普通变量的值?
    (1)实参为相关变量的地址;
    (2)形参为该变量的类型为类型的指针变量;
    (3)在被调函数中通过" *形参变量名 " 的方式就可以修改主函数中变量的值。
注:

一旦函数执行完毕,其内部的形参所占空间就被收回。

§举例1:通过指针在子函数中修改主函数变量的值
        #include<stdio.h>
        void f(int * p)
        {
                *p=100;
        }
        int main(void)
        {
            intt i=9;
            f(&i);
            printf("i=%d\n",i);
            return 0;
        } 
    运行结果:i=100
    说明:
    (1)f(int *p),不是定义了一个名字叫做*p的形参,而是定义了一个形参,该形参名字叫做i,它的类型是int *,即int * p意味变量p存放的是整型变量地址;
    (2)*p=100,由于函数实参为&i(地址),*p=i;
§举例2:若指针指向的变量值互换
        /*指针互换程序*/
        #include<stdio.h>
        void exchange(int *p,int *q)
        {
            int temp;
            temp=*p;
            *p=*q;
            *q=temp;
        }
        void main()
        {
            int a=5,b=7;
            exchange(&a,&b);
            printf("a=%d,b=%d",a,b);
            while(1);
        }
    运行结果:a=7,b=5
    说明分析:
                (1)由于exchange()函数形参为int *类型的指针变量(存储地址),因此实参传入的是int类型变
                    的地址。
                (2)对于临时变量temp,如果要互换*p和*q的值(为值),则t必须定义成int temp,而不能定义成int 
                    *temp。因为int *为指针变量的类型,其值为地址。
                (3)值交换内存分析
                                
§举例3:若指针变量保存的地址互换
        /*指针互换程序*/
        #include<stdio.h>
        void exchange(int *p,int *q)
        {
            int *temp;
            temp=p;
            p=q;
            q=temp;
        }
        void main()
        {
            int a=5,b=7;
            exchange(&a,&b);
            printf("a=%d,b=%d",a,b);
            while(1);
        }
    运行结果:a=5,b=7
    说明分析:
               (1)对于临时变量temp,如果要交换指针变量q和p的值,则temp必须为int *类型,而不能用int。因
                    为,int *表示的是地址类型,int表示的是变量值类型。
                (2)交换指针变量q和p,则是交换指针变量所保存的值,只影响指针变量p、q指向的内存地址变
                    化,而不影响该内存地址所保存的值。
                (3)内存分析
                                
区别:指针与指针变量
◆指针就是地址,地址就是指针。地址就是内存单元的编号。
◆指针变量:存放地址的变量。而指针只是一个值,这个值是内存单元的一个编号。指针变量才是一个变量,他里面才可以存放数据。
◆指针和指针变量是两个不同的概念,但是需要注意的是,通常我们在叙述时会把指针变量简称为指针,实际他们含义并不一样。
二、指针和数组
1.数组名
    一维数组名是个指针变量,它存放的是一维数组第一个元素的地址。它的值不能被改变,一维数组名指向的是数组的第一个元素。即数组名a=&a[0],是一个常量(地址值),常量是不能被改变的,即一维数组名是不能被 改变的。
2.下标与指针关系
                                a[i] <<==>>*(a+i)
    假设指针变量的名字为p,则p+i的值是p+i*(p所指向的变量所占的字节数)。
3.指针变量的运算原则
(1)指针遍历不能相加,不能相乘,不能相除;
(2)如果两指针变量属于同一数组,则可以相减。或者说两个指针变量指向的是同一块连续空间中的不同存储单元,则这两个指针变量才可以相减;
(3)指针变量可以加减一整数
    如:p+i的值是p+i*(p所指向的变量所占的字节数)
            p-i的值是p-i*(p所指向的变量所占的字节数)
            p++ <===>p+1
            p--   <===>p-1
§举例1:如何通过被调函数修改主调函数中一维数组中的内容?
    #include<stdio.h>
    show_array(int * p,int len)
    {
            int i;
            for(i=0;i<len;i++)
                        printf(" %d",*(p+i));    //等价于p[i]    
    }
    int main(void)
    {
            int a[]={1,2,3,4,5};
            show_array(a,5);    //实参为数组第一个元素地址、数组长度
            return 0;
    }
运行结果:1 2 3 4 5
分析说明:
     (1)数组名a等价于&a[0],&a[0]本身就是int *类型;
     (2)p[i]=*(p+i)=*(a+i)=a(i),即p(i)就是主函数的a[i] 
     (3)内存分析
               
§举例2:计算指针变量所占字节数
    #include<stdio.h>
    int main(void)
    {
        double *q;
        double  arr[3]={1.1,2.2,3.3};
        q=&arr[0];    //将数组的第一个元素地址赋值给类型为double *的指针变量
        printf("%p\n",q);
        q=&arr[1];
        printf("%p\n",q);
        return 0;
    }
运算结果:
    0000 FFAC
    0000 FFB4
分析说明:
(1)%p的作用是输出变量地址(存放至内存的起始地址),
(2)qarr[0]占8个字节,1个字节8位且一个字节在内存中就是一个地址。由B4-AC=8,即证明数据的每一个元素在内存中占8个字节。如果数据类型为char,则结果为C1-C0=1,数组的每一个元素在内存中占1个字节。

总结:
★无论指针变量指向的变量占多少字节,所有的指针变量只占4个字节,且用第一个个字节的地址表示所指向的整个变量的地址。原因:*p具体指向几个字节,要靠前面类型确定,如果为int则为4字节,如果double则占8字节。CPU 与 内存交互时 有32根线,每根线只能是1或0两个状态,所有总共有232个状态。 1 个状态 对应 一个单元。如全为0 全为1 等。 内存中第一个单元,即32根线状态全为0。 
0000 0000 0000 0000 0000 0000 0000 0000 ,其大小为4字节 (1字节=8位),所有每个地址(硬件所能访问)的用4个字节保存(而不是一 位bit) 。一个变量的地址—用该变量首字节的地址表示。这也就是为什么指针变量始终只占4字节的原因。
★一个变量的地址,是用该变量首字节的地址来表示。



           

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值