【C】28.指针和数组分析

回顾

  • 数组是一段连续的内存空间
  • 数组的空间大小为 sizeof(array_type) * array_size
  • 数组名可以看作指向数组第一个元素的常量指针

问题:

  1. a+1的意义是什么?结果是什么?
  2. 指针运算的意义是什么?结果是什么?

编程分析 a+1 示例

#include <stdio.h>

int main()
{
    int a[5] = {0};
    int* p = NULL;
    
    printf("a = 0x%X\n", (unsigned int)(a));
    printf("a + 1 = 0x%X\n", (unsigned int)(a + 1));
    // 数组名看着常量指针的话,这里其实也是指针的运算
    printf("p = 0x%X\n", (unsigned int)(p));
    printf("p + 1 = 0x%X\n", (unsigned int)(p + 1));
    
    return 0;
}

运行结果

a = 0xFFFFACA0
a + 1 = 0xFFFFACA4
p = 0x0
p + 1 = 0x4

使用指针运算分析运算结果

p + n   >>> (unsingned int)p + n*sizeof(*p);

int* p = NULL;
p+1 >>> 0 + 1*sizeif(*p) >>> 0 + 1*sizeof(int) >>> 0 + 4 >>> 4;

a = 0xBFA00F38;
a + 1 >>> 0xFFFFACA0+ 1*sizeof(*a) >>> 0xFFFFACA0+ 1*sizeof(a[0])
      >>> 0xFFFFACA0+ 1*4  >>> 0xFFFFACA0+ 4 = 0xFFFFACA4

指针运算

  • 指针是一种特殊的变量 ,与整数的运算规则为
 P+n >>> (unsigned int )p  + n*sizeof(*p)
  1. 当指针p指向一个同类型的数组的元素的时 : p+1 将指向当前元素的下一个元素;p-1将指向当前元素的上一个元素。
  • 指针只支持减法运算,参与减法运算的指针类型必须相同
p1 - p2 <-->( (unsigned int)p1 - (unsigned int)p2) / sizeof(type);

注意:

  1. 只有当两个指针指向同一个数组中的元素时,指针想减才有意义,其意义为指针所指元素的下标差
  2. 当两个指针指向的元素不在同一个数组中时,结果未定义

指针的比较

  • 指针也可以进行关系运算(<, <=, >, >=)
  • 指针关系运算的前提是同时指向同一个数组中的元素
  • 任意两个指针间的比较运算(==,!=)无限制
  • 参与比较运算的指针类型必须相同
  • 从实际意义出发,指针进行比较时必需同一个数组,不然毫无意义

指针运用初探示例

#include <stdio.h>

int main()
{
    char s1[] = {'H', 'e', 'l', 'l', 'o'};
    int i = 0;
    char s2[] = {'W', 'o', 'r', 'l', 'd'};
    char* p0 = s1;
    char* p1 = &s1[3];
    char* p2 = s2;
    int* p = &i;
	
    printf("%d\n", p1 - p0);
    printf("%d\n", p0 + p2); // error
    printf("%d\n", p0 - p2); // 结果未定义
    printf("%d\n", p0 - p);  // error
    printf("%d\n", p0 * p2); // error
    printf("%d\n", p0 / p2); // error
	
    return 0;
}

输出结果:

3
-16

分析:

扫描二维码关注公众号,回复: 8649697 查看本文章

p0 和 p2 指向的是不同的数组,相互相减, 结果未定义。语法是合格的,但是结果是多少没法分析!

指针运算运用

#include <stdio.h>

#define DIM(a) (sizeof(a) / sizeof(*a))

int main()
{
    char s[] = {'H', 'e', 'l', 'l', 'o'};
    char* pBegin = s;
    char* pEnd = s + DIM(s); // Key point
    // pEnd指向数组靠外的虚拟地址(擦边球)
    char* p = NULL;
    
    printf("pBegin = %p\n", pBegin);
    printf("pEnd = %p\n", pEnd);
    
    printf("Size: %d\n", pEnd - pBegin);
	
    for(p=pBegin; p<pEnd; p++)
    {
        printf("%c", *p);
    }
    
    printf("\n");
   
    return 0;
}

运算结果:

pBegin = 0x7ffbffffacb0
pEnd = 0x7ffbffffacb5
Size: 5
Hello

分析:

pEnd 指针指向数组最后一位的数据的后一位的边界位置,我们可以认为这个指针是合法的,可以进行指针的比较运算,减法运算等。这一个特性很重要。

小贴士:

声明不同类型的指针的作用:规定指针在内存中每次移动的字节数。

不同类型的指针的作用是指针在内存中每次移动的字节数不同

小结

  • 数组声明时编译器自动分配一片连续的内存空间。
  • 指针声明是只分配了用于容纳地址值的 4 字节空间
  • 指针和整数可以进行运算,其结果为指针
  • 指针之间只支持减法运算,其结果为数组元素下标差
  • 指针之间支持比较运算,其类型必须相同
发布了84 篇原创文章 · 获赞 0 · 访问量 757

猜你喜欢

转载自blog.csdn.net/zhabin0607/article/details/103335018