黑马程序员——c语言学习---指针的探讨

-----------Java培训Android培训IOS培训.Net培训期待与您交流!------------ 
本节探讨c语言中最重要的指针,c语言之所以如此灵活,关键就在于指针的运用,这是一个难点,也是学c语言必须要掌握的内容。

1、什么是指针?

指针如其名字所示的一样,他是一种有方向性的数据,能够指向别的数据类型。首先要明白的一点是,指针也是一种数据。那么在c语言中的指针是怎么运作的呢?在c语言中,我们通过*来创建指针数据,我们通过一个例子来看:

    int a = 12; // 创建整形变量 a
    
    int *p = &a; // 创建指针 p 指向 a
    
    printf("a的地址:%p  a的大小为:%lu Byte  a的内容:%d\n", &a, sizeof(a), a); // 输出 a 的地址、大小及存储内容
    printf("p的地址:%p  p的大小为:%lu Byte  p的内容:%p\n", &p, sizeof(p), p); // 输出 p 的地址、大小及存储内容
    printf("p指向的内容为 %d\n", *p); // 输出p指向的内容
在该例子中,我们创建了一个变量 a=12,然后创建了一个指针 p 指向 变量 a,我们看看程序输出情况:

a的地址:0x7fff5fbff8d8  a的大小为:4 Byte  a的内容:12
p的地址:0x7fff5fbff8d0  p的大小为:8 Byte  p的内容:0x7fff5fbff8d8
p指向的内容为 12

从输出结果可以看出,变量 a 占用内存单元的4个字节,存储的是数值 12,指针 p 占用内存单元的8个字节,存储的是一个地址数据,进一步观察可以发现,p对应内存单元所存储的地址数据和变量a的地址一致,这样我们就可以通过 *p 直接访问 a 的内容,换句话说,*p 就是 a。验证如下:

    *p=13;
    printf("a = %d\n", a); // 输出 a 的内容
前面的代码中我们给变量 a 赋值 12,在该代码中,我们没有直接对 a进行操作,我们看看结果又会怎样:

a = 13
可以发现,我们通过指针 p 就可以间接修改 变量 a 的内容。


2、思考
通过上面的例子发现,我们可以通过指针绕过变量本身,直接修改变量的值,换句话说,我们可以通过指针直接操作变量对应的地址单元!这就是指针的本质。那么,为什么要这样做呢?

a、我们知道,数据在内存中的存储都是以基本的内存单元按顺序进行排列的,对变量的操作其本质就是操作变量对应的地址单元,我们每创建一个变量,实际上就是用一个标识符(变量名)标识了一块内存单元,这样当创建大量的变量时就会产生大量的标识符,这是不利于变量的调用的。当对大量的数据或者具有某种结构和顺序的数据进行操作时,指针的优势就凸现出来,因为指针是直接通过地址单元来操作变量的,而我们对地址单元的简单运算,就能在大量不同的变量之间跳转,非常的灵活。

b、当然这也产生了一些问题。由于指针是对地址单元的直接操作,而如果我们错误的将指针定位到不该指向的内容时,有时会导致整个程序的崩溃,这一点一定要注意。


3、特殊的指针

a、数组

c语言中数组本身就是一种指针,只不过写法略有不同。

    int ar[]={1,2,3};
    int *arp=ar;//int *arp={1,2,3};这样是错误的
    
    //输出数组的值
    printf("%d\n", arp[0]);   // *arp
    printf("%d\n", arp[1]);   // *arp+1
    printf("%d\n", arp[2]);   // *arp+2
    
    printf("ar的地址:  %p\narp的地址: %p \n", &ar, &arp);

输出结果:

1
2
3
ar的地址:  0x7fff5fbff8c8
arp的地址: 0x7fff5fbff8c0 

在上面的例子中,我们将一个指针指向了数组,有没注意到数组名的前面没有加 &地址操作符?这是因为数组名本身就是一个指针!这两个指针占用不同的内存单元,但是他们都能对数组进行操作。

b、字符串

前面有提到,字符串本身就是一种数组,那同样的,他也可以用指针来表示:

    char *str = "This is a string!";
    
    printf("%s\n", str);
输出:

This is a string!
c、指针数组

在数组名的前面加 * 就成为了指针数组:

    //创建指针常量数组
    char *name[]=
    {
        "Jack",
        "Tom",
        "Helen",
        "April",
    };
    
    // 输出
    for (int i=0; i<4; i++){
        printf(" %s\n",name[i]);
    }
输出结果:

 Jack
 Tom
 Helen
 April
d、指针函数

函数本身也是一种指针(函数的细节将在别的章节讨论),我们当然也可以通过指针指向函数:

    //(*p)为固定写法,表示该指针指向函数
    void (*p)(char);
    p=func;
    
    // 测试函数和指针指向的地址
    printf("func地址: %p\n", &func);
    printf("p指向地址: %p\n", p);
    
    // 指针调用函数
    (*p)('A'); // 可以简化为p('A')
输出结果:

func地址: 0x100000e80
p指向地址: 0x100000e80
func()函数被调用,传入字符参数 A 
可以发现这两个地址完全一致。


4、其他

在计算机领域流传一句话:多一层间接,没有解决不了的问题。指针是c语言构建简介结构的关键,在以c语言为基础的面向对象设计语言中,这种对指针的运用将显得格外突出和复杂。


-----------Java培训Android培训IOS培训.Net培训期待与您交流!------------ 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值