为什么要精通C指针

指针有几种用途,包括:

  • 写出快速高效的代码;
  • 为解决很多类问题提供方便的途径;
  • 支持动态内存分配;
  • 使表达式变得紧凑和简洁;
  • 提供用指针传递数据结构的能力而不会带来庞大的开销;
  • 保护作为参数传递给函数的数据。

用指针可以写出快速高效的代码是因为指针更接近硬件。也就是说,编译器可以更容易地把操作翻译成机器码。指针附带的开销一般不像别的操作符那样大。

很多数据结构用指针更容易实现,比如链表可以用数组实现,也可以用指针实现。然而,指针更容易使用,也能直接映射到下一个或上一个链接。用数组实现需要用到数组下标,不直观,也没有指针灵活。

下图比较形象地展示了用数组和指针实现员工链表时的情形。图中左边用了数组,head变量表明链表的第一个元素在数组下标10的位置,每一个数组元素都包含表示员工的数据结构。结构的next字段存放下一个员工在数组中的下标。灰底的元素表示未使用。

为什么要精通C指针

右边显示了用指针实现的等价形式。head变量存放指向第一个员工节点的指针。每个节点存放员工数据和指向链表中下一个节点的指针。

指针形式不仅更清晰,也更灵活。通常创建数组时需要知道数组的长度,这样就会限制链表所能容纳的元素数量。使用指针没有这个限制,因为新节点可以根据需要动态分配。

C的动态内存分配实际上就是通过使用指针实现的。mallocfree函数分别用来分配和释放动态内存。动态内存分配可以实现变长数组和数据结构(如链表和队列)。不过,新的C11标准也支持变长数组了。

紧凑的表达式有很强的表达能力,但也比较晦涩,因为很多程序员并不能完全理解指针表示法。紧凑的表达式应该用来满足特定的需要,而不是为了晦涩而晦涩。比如说,下面的代码用了两个不同的printf函数调用来打印names的第二个元素的第三个字符。如果对指针的这种用法感到困惑,不用担心,我们会在1.1.6节中详细介绍解引(dereference)的工作原理。尽管两种方式都会显示字母n,但是数组表示法更简单。

char *names[] = {"Miller","Jones","Anderson"};
printf("%c\n",*(*(names+1)+2));
printf("%c\n",names[1][2]);

指针是创建和加强应用的强大工具,不利之处则是使用指针过程中可能会发生很多问题,比如:

  • 访问数组和其他数据结构时越界;
  • 自动变量消失后被引用;
  • 堆上分配的内存释放后被引用;
  • 内存分配之前解引指针。

我们会在后面的文章中深入研究这几类问题。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程