玩转指针(Playing with Pointers)

Question: What is a Pointer? What are its limitations? What are its benefits? How do we use it? What all operation we can perform using it?

In this article we are going to discover answers to all these questions.

指针是一个包含其它变量地址的变量,这里的其它变量可以是结构,数组或则其它基本类型的数据。定义指针的基本语法如下:

Datatype * identifier;

Datatype表示定义的指针变量中存储的是何种类型数据的地址。

*是间接取值/解引用符号。

identifier是定义的指针变量名。

指针使得我们能直接对内存操作改变内存中存储的数据,这是C语言的特征。无论何时我们定义一个指向某种类型数据的指针,我们可以称呼这个指针为——例如整型数据——指向整型数据的指针。

在C语言中指针和数组的关系很密切。数组的下标形式可以用指针形式替代,一般指针形式比较快。因此,数组中arr[n]第i各元素可以用*(arr + i)表示。之所以能这样表示是因为数组名本身就是数组第一个元素的地址。但数组名和指针还是有很重要的区别的。指针是一个变量,

ptr=arr;

ptr++;

是合法的,但数组名不是变量,这样的语句:

arr=ptr;

arr++;

都是不合法的,这里arr和ptr的定义也是不同的,分别是int arr[n] 和 int *ptr。

指针操作

现在我们来看看指针相关的操作。可行的操作有:给指针指向的变量赋值,指针变量和指针变量的加减,指针和整数的加减,指针减指针,利用指针对数组元素进行加减和比较。所有其它指针本身的算术都是非法的,包括但不限于指针本身相加,乘除,平移或掩码操作,加减浮点数,不加转换的赋值等。然而,如果两个指针指向同一个数组的元素,可以使用二进制运算== , != , < , >=。

C语言中还定义了一个一般化的指针——void *,也就是空指针。它可以被投射成任何类型的指针,默认情况下返回类型是库函数malloc(),void *类型指针不能de-reference(取指针指向的值)自己,所以需要转化为其它类型的指针。下面的代码包含了所有我们讨论过的方面。

#include<stdio.h>

int main(void)
{
    // Declaring a void pointer
    void *vptr;

    // Creating some pointer variables
    int arr[5]={34,5,17,39,1};
    int *ptr1,*ptr,num,i;

    vptr=arr;

    ptr=(int *)vptr;    //  casting void *

    ptr1=arr+3;        // pointer and integer addition

    if(ptr1 > ptr)            //comparison of pointers
        num=ptr1-ptr;       // subtraction of pointers

    printf("% d,% d,% d\n",*ptr,*ptr1,num);

    ptr = ptr1-2;       //pointer and integer subtraction
    ptr1++;             //pointer increment

    printf("% d,% d\n",*ptr,*ptr1);

    return 0;
}

Output:
34 39 3
5 1

下面是一些非法的操作:

// invalid operations
ptr1  = arr + ptr ;
ptr1 +=ptr;
ptr  *=3;
ptr1 /=ptr;
char *cptr  =ptr;
ptr =*(arr +4.2);
ptr <<2;

这边文章给初学者介绍了指针的基本操作,多维指针和指向函数的指针我们以后会讨论到。

时间: 2024-08-30 14:50:57

玩转指针(Playing with Pointers)的相关文章

NULL指针分析

最近在查看同事写的一段程序时,发现里边有一个函数大概如下: void example(uint8 *pData) { ... if(NULL == *pData) return; while(*pData != NULL) { ... } ... } 第一眼看去感觉红色部分写的没有什么,当看到while时, 感觉第一句有些多余, 没有必要这样判断,当*pData == NULL时while就进不去, 但是想到这里是第一次判断pData,于是估计当时同事是想写if(NULL == pData),笔

C++ 高级数据类型(三)—— 指针

我们已经明白变量其实是可以由标识来存取的内存单元.但这些变量实际上是存储在内存中具体的位置上的.对我们的程序来说,计算机内存只是一串连续的单字节单元(1byte cell),即最小数据单位,每一个单元有一个唯一地址. 计算机内存就好像城市中的街道.在一条街上,所有的房子被顺序编号,每所房子有唯一编号.因此如果我们说芝麻街27号,我们很容易找到它,因为只有一所房子会是这个编号,而且我们知道它会在26号和28号之间. 同房屋按街道地址编号一样,操作系统(operating system)也按照唯一顺

智能指针 shared_ptr 解析

最近正在进行<Effective C++>的第二遍阅读,书里面多个条款涉及到了shared_ptr智能指针,介绍的太分散,学习起来麻烦,写篇blog整理一下. LinJM   @HQU shared_ptr是一个智能指针.在C++ 11颁布之前,它包含在TR1(Technical Report 1)当中,现在囊括在C++11的标准库中. 智能指针 智能指针(Smart pointers)是存储"指向动态分配(在堆上)的对象的指针"的对象.也就是说,智能指针其实是个对象.不过

C++ 常量指针与指针常量

一.常量指针(constant pointers):指针自身是常量,const关键字出现在星号右边.如: 1 char greeting[] = "Hello";2 char* const p = greeting; // const pointer, non-const data 二.指针常量(pointers to constants):指针所指物是常量,const关键字出现在星号左边.如: 1 char greeting[] = "Hello"; 2 cons

OC基础—多态(超级简单)

前言: oc中的指针类型变量有两个:一个是编译时类型,一个是运行时类型,编译时类型由声明该变量是使用的类型决定,运行时类型由实际赋给该变量的对象决定.如果编译时类型和运行时类型不一致,就有可能出现多态. 正文: 新建一个CHPerson类 1 @interface CHPerson : NSObject 2 -(void)eat; 3 -(void)play; 4 @end 5 --------------------------------------------------------- 6

Fibonacii非递归

记得在我们最开始学习C语言的时候,每当讲到递归,无论是课本上,还是老师,都会给出两个经典例子的递归实现,其中一个就是阶乘,另外一个就是Fibonacci(中文多译成斐波那契)数列了. 用递归方法计算阶乘的代码如下: //递归计算阶乘 long Factorial(int n) {     if (n <= 0)     {         return 1;     } return n * Factorial(n - 1); } 这样的递归是一个很明显的尾部递归的例子,所谓的尾部递归(tail

Linux内核学习-进程

先说几个术语: 一.Linux进程的五个段 下面我们来简单归纳一下进程对应的内存空间中所包含的5种不同的数据区都是干什么的.重点:代码段.数据段.堆栈段,这是一个概念堆.栈.全局区.常量区,这是另一个概念1)代码段:代码段是用来存放可执行文件的操作指令,也就是说是它是可执行程序在内存中的镜像.代码段需要防止在运行时被非法修改,所以只准许读取操作,而不允许写入(修改)操作--它是不可写的.代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域.这部分

linux堆栈

进 程(执行的程序)会占用一定数量的内存,它或是用来存放从磁盘载入的程序代码,或是存放取自用户输入的数据等等.不过进程对这些内存的管理方式因内存用途 不一而不尽相同,有些内存是事先静态分配和统一回收的,而有些却是按需要动态分配和回收的.对任何一个普通进程来讲,它都会涉及到5种不同的数据段. 一.Linux进程的五个段 下面我们来简单归纳一下进程对应的内存空间中所包含的5种不同的数据区都是干什么的. 1)代码段:代码段是用来存放可执行文件的操作指令,也就是说是它是可执行程序在内存中的镜像.代码段需

Effective C++ —— 杂项讨论(九)

条款53 : 不要轻忽编译器的警告 请记住: 1. 严肃对待编译器发出的警告信息.努力在你的编译器的最高(最严苛)警告级别下争取“无任何警告”的荣誉. 2. 不要过度倚赖编译器的报警能力,因为不同的编译器对待事情的态度并不相同.一旦移植到另一个编译器上,你原本倚赖的警告信息有可能消失.  条款54 : 让自己熟悉包括TR1在内的标准程序库 TR1代表“Technical Report 1”,TR1宣示了一个新版C++的来临,我们可能称之为Standard C++1.1.不熟悉TR1机能而却奢望成