此文为指针系列第二篇:
C 语言精要总结 - 指针系列(一)
C 语言精要总结 - 指针系列(二)
前面提到过指针的解引用运算,除此之外,指针还能进行部分算数运算、关系运算
指针能进行的有意义的算术运算包括加减法运算,但不包括乘除运算。并且运算存在诸多限制。
加法运算
指针加法运算只适合指针与整数,不能用在指针与指针。
指针加上或者减去一个整数 n,是存储的地址值加上或者减去 n * 指针指向类型的空间大小。也就是
结果指针 = 指针 ± n * 指针指向类型空间大小。
例如 int 类型的整数指针 + 1,运算结果依然是一个整型指针,其存储的地址值为原指针值 + 1*4,这是因为整型变量占用 4 个字节的空间。这个计算结果,恰好在当前指针指向基础上,向下偏移指向下一个相同类型的空间。如下图
指针与整数的加减法一般用在迭代连续的内存空间 - 数组,如果运算得到的指针指向第一个元素之前或者最后一个元素之后,可能会产生非法读写内存中断,就像引用一个未初始化的指针一样不可预知。
指针除了可以与整数做加减运算,连个指针之间还可以做减法运算(不能做加法运算)且必须是同类型的指针。运算结果为两个指针指向地址之间,可以存放多少此类型的变量数(或其相反数),类型为 ptrdiif_t 类型(一种有符号整数类型)。
- 1 int * p1 = (int * ) 0x100;
- 2 int * p2 = (int * ) 0x10c;
- 3 printf("p2-p1 : %d\n", p1 - p2); // -3
如上程序将输出 - 3,也如上图所示,这 3 个空间存放着 10、80、6 三个整型变量。
指针与指针相减,一般也用在连续地址空间 - 数组中。此时两个指针相减跟下标索引相减是等价的。
- 1 int arr[5];
- 2 printf("%d\n", &arr[4] - &arr[0] == 4 - 0); // 1
常量指针表示通过此指针,不能修改其指向的内存区域的内容,指针本身的值是可以修改为指向另一个变量,虽然可以修改指向另一个变量,但是依然不允许修改指向变量里的内容。常量指针一般用在函数一些函数参数中,以只读的方式传递函数参数。这里说明一点 C 语言除了宏定义常量和枚举之外,是不能定义普通常量的,只可用 const 定义只读变量,而常量指针指向的是就是一个只读变量。只读变量是不能修改的变量。
- 1 const intreadOnlyVar =10;
- 2 int* pROVar = (int*) & readOnlyVar;
- 3* pROVar =11;
- 4printf("%d\n",readOnlyVar);
而指针常量表示指针本身的内容不可变(指向不可变),因此,定义指针常量时必须同时初始化一个地址值。
定义指针常量和定义常量指针的方式区别在于 const 关键字的位置
- int const* p1 ;
- const int* p2 ;
- int*constp3 = NULL;
- const int*constp4 = NULL;
以 * 号为界限,看 cosnt 修饰的是谁,如果修饰的是类型关键字,表示指向常量类型——常量指针,如果修饰的是指针标识符,表示指针常量。显然 p1、p2 是常量指针,p3 是指针常量,p4 既是常量指针,又是指针常量。
指针数组指元素由指针组成的数组,一般用在存储字符串组,例如下面的程序
- 1 char * options[5] = {
- 2 "--list",
- 3 "--prefix",
- 4 "--with"5
- };
- 6
- for (i = 0; i < 5; i++) 7 {
- 8
- if (NULL != options[i]) {
- 9 printf("%s\n", options[i]);
- 10
- }
- 11
- }
此时指针数组前三个成员指向静态区的三个字符串常量,而后两个指针被默认初始化为 0(NULL)
C 语言中出现的字符串字面量,实际是存储在静态数据区的字符串常量。当一个字符串出现在 C 语言表达式中,其实际值是一个指针常量。如下面声明一个指针常量的代码
- char* str ="hello";
可以用另一段代码来描述,即先在某处为字符串分配空间,记录指向第一个字符的一个指针常量,并将字符拷贝进去。代码如下
- char*conststrBuff = (char* )malloc(6);
- strcpy(strBuff,"hello");
- char* str = strBuff;
- free(strBuff);
既然明确字符串常量在代码中实际是一个指针常量,因此其也可以参与运算。代码如下
- printf("%c\n", *"hello"); // h
- printf("%s\n", "hello" + 1); // ello
常量指针 "hello"+1 后得到一个新的指针,按指针运算的规则将指向下一个 e,所以以字符串形式输出 ello
除此之外指针输在还用在处理许多多维数组的地方,这在后续的章节中会提到。
常量指针数组表示元素都指向常量的数组。定义方式如下
- 1 const char* options[5] = {
- 2 "--list",
- 3 "--prefix",
- 4 "--with"
- 5};
当然,这里的例子,const 加与不加没太大区别,因为即便不加 const 关键字,options 中的每一个元素依然是指向一个字符串常量,是不能修改的。例如要将 "--list" 中的第 2 个'-'换成'+'号,下面的代码是行不通的,方法只有让指针指向一个全新的字符串常量(因为是常量指针,所以指针本身的内容可以修改)
- * (options[0] +1) ='+';
加上 const 的好处是,让编译器或者 IDE 工具在运行之前便告知你此类代码存在的问题。关于字符串常量,下面的异常代码可能更易懂一些
- char* str ="hello";
- *(str +3) ='w';
指针常量数组表示每个指针元素都是不可修改的(指向固定了),但是其指向内容,视情况是可以修改的。
- 1 char*constoptions[5] = {
- 2 "--list",
- 3 "--prefix",
- 4 "--with"
- 5};
当然,因为字符串常量的缘故,上面的代码定义了一个指针元素、指针元素指向区域内都不可变的指针数组。例如,像下面的代码都是非法的
- 1 options[0] = tmpStr; // 修改指针指向新的字符串常量
- 2 * (options[0]) = '+'; // 修改第一个元素指向区域的内容
下一系列将用一两个复杂的案例详细讲解指针与数组的关系。
来源: http://www.cnblogs.com/lvyahui/p/6965284.html