乐趣区

关于c:C进阶28指针和数组分析

Summary

1)数组是一段 间断的内存空间,数组的元素个数为 #define DIM(a) (sizeof(a) / sizeof(*a))

2)指针是一种 非凡的变量 与整数的运算规定为
p + n; <--> (unsigned int)p + n * sizeof(*p)
当指针 p 指向一个数组里的元素时,p + 1 将指向以后元素的下一元素p - 1 将指向以后元素的上一元素

3)指针之间 只反对减法运算 ;参加减法运算的指针 必须类型雷同
留神:只有当 2 个指针 指向同一个数组中的元素时,指针相减才有意义 ,意义为指针所指元素的 下标差 ;当 2 个指针指向的元素 不在同一个数组时 未定义
p1 - p2; <--> ((unsigned int)p1 - (unsigned int)p2) / sizeof(type);

4)char* pEnd = s + DIM(s); pEnd 指向了 数组 s 中最初一个元素的后一地位 ,尽管这个地位不属于数组,但 在 C 语言中,依然认为这个边界地位是属于数组的,这个知识点在 STL 中也有利用。

5)指针也能够进行 关系运算 (<, <=, >, >=),但前提是同时 指向同一个数组中的元素
两个指针间能够进行 比拟运算 (==,!=),但两个 指针的类型必须雷同

6)for (p = pBegin; p < pEnd; p++),p 指向了数组的首元素,pEnd 在 C 语言中被认为是数组的元素,所以 p 和 pEnd 都指向了同一个数组里的元素,类型雷同,可能进行比拟

指针和数组剖析

数组是一段 间断的内存空间
数组的空间大小为 sizeof(arr_type) * arr_size
数组名可看做 指向数组第一个元素的指针常量

1、指针的运算

问题:对于数组 int a[5],a + 1 的意义是什么?后果是什么?指针运算的意义是什么,后果又是什么?

论断:
指针是一种 非凡的变量 与整数的运算规定为
p + n; <--> (unsigned int)p + n * sizeof(*p)
当指针 p 指向一个数组里的元素时,p + 1 将指向以后元素的下一元素p - 1 将指向以后元素的上一元素

#include <stdio.h>

int main()
{int a[5] = {0};
    int* p = NULL;
    
    printf("a = 0x%X\n", (unsigned int)(a));
    printf("a = 0x%X\n", (unsigned int)(a + 1));
    
    printf("p = 0x%X\n", (unsigned int)(p));
    printf("p = 0x%X\n", (unsigned int)(p + 1));
    
    return 0;
}

输入:a = 0xBFCEEF78
a = 0xBFCEEF7C
p = 0x0
p = 0x4

指针之间 只反对减法运算 ;参加减法运算的指针 必须类型雷同
p1 - p2; <--> ((unsigned int)p1 - (unsigned int)p2) / sizeof(type);
留神:只有当 2 个指针 指向同一个数组中的元素时,指针相减才有意义 ,意义为指针所指元素的 下标差 ;当 2 个指针指向的元素 不在同一个数组时 未定义

#include <stdio.h>

int main()
{char s1[] = {'H', 'e', 'l', 'l', 'o'};
    char s2[] = {'H', 'e', 'l', 'l', 'o'};    
    char* p0 = s1;
    char* p1 = &s1[3];
    char* p2 = s2;
    int i = 0;
    int* p = &i;
    
    
    printf("%d\n", p0 - p1);    // 下标差:-3
    printf("%d\n", p0 + p2);    // error
    printf("%d\n", p0 - p2);    // undefined behavior
    printf("%d\n", p0 - p);     // error
    printf("%d\n", p0 * p2);    // error
    printf("%d\n", p0 / p1);    // error
    
    return 0;
}
输入:(指针之间的 + * / 都不容许,不同类型指针的减法运算也不容许)test.c:17: error: invalid operands to binary + (have‘char *’and‘char *’)
test.c:19: error: invalid operands to binary - (have‘char *’and‘int *’)
test.c:20: error: invalid operands to binary * (have‘char *’and‘char *’)
test.c:21: error: invalid operands to binary / (have‘char *’and‘char *’)

p0 - p2 的输入为 5,但并不知道这是什么意思
#include <stdio.h>

// 计算数组的大小
#define DIM(a) (sizeof(a) / sizeof(*a))      

int main()
{int s1[] = {'H', 'e', 'l', 'l', 'o'};
    int s2[] = {'H', 'e', 'l', 'l', 'o'};    
    int* p0 = s1;
    int* p1 = &s1[3];
    printf("p1 - p0 = %d\n\n", p1 - p0);        // 3


    char s[] = {'H', 'e', 'l', 'l', 'o'};
    char* pBegin = s;
    char* pEnd = s + DIM(s);
    char* p = NULL;
    
    
    printf("pBegin = %p\n", pBegin);
    printf("pEnd = %p\n", pEnd);
    
    printf("Size: %d\n", pEnd - pBegin);    // 5
    
    for (p = pBegin; p < pEnd; p++)         // 指针比拟,指针运算
    {printf("%C", *p);
    }
    printf("\n");
    
    return 0;
}

输入:p1 - p0 = 3

pBegin = 0xbf9ff2a7
pEnd = 0xbf9ff2ac
Size: 5
Hello

剖析:

  • char* pEnd = s + DIM(s); pEnd 指向了 数组 s 中最初一个元素的后一地位 ,尽管这个地位不属于数组,但 在 C 语言中,依然认为这个边界地位是属于数组的,这个知识点在 STL 中也有利用。
  • for (p = pBegin; p < pEnd; p++),p 指向了数组的首元素,pEnd 在 C 语言中被认为是数组的元素,所以 p 和 pEnd 都指向了同一个数组里的元素,类型雷同,可能进行比拟

2、指针的比拟

指针也能够进行 关系运算 (<, <=, >, >=),但前提是同时 指向同一个数组中的元素
两个指针间能够进行 比拟运算 (==,!=),但两个 指针的类型必须雷同

#include <stdio.h>   

int main()
{int a[5] = {0};
    int* p0 = a;
    int* p1 = &a[1];
    char* p2;
    
    
    printf("%d\n", p1 < p0);    // ok, 0
    printf("%d\n", p1 < p2);    // undefined    

    printf("%d\n", p1 != p0);   // ok, 1 
    printf("%d\n", p1 == p2);   // undefined
    
    return 0;
}

以上代码在编译时曾经 warning:
test.c:14: warning: comparison of distinct pointer types lacks a cast
test.c:17: warning: comparison of distinct pointer types lacks a cast

本文总结自“狄泰软件学院”唐佐林老师《C 语言进阶课程》。
如有错漏之处,恳请斧正。

退出移动版