28-指针和数组分析(上)

注:博客中内容主要来自《狄泰软件学院》,博客仅当私人笔记使用。

测试环境:Ubuntu 10.10

GCC版本:4.4.5

一、数组的本质

1) 数组是一段连续的内存空间

2) 数组的空间大小为sizeof(array_type)*array_size

3) 数组名可看做指向数组第一个元素的指针常量,但不是指针(只能看做!方便理解)

 

                   问题:假设a是数组

                   1、a+1的意义是什么?结果是什么?

                   2、指针运算的意义是什么?结果又是什么?

编程实验
a+1的结果是什么?
28-1.c
#include <stdio.h>
 
int main()
{
    int a[5] = {0};             //初始化为0的5个元素的int类型数组
    int* p = NULL;
   
    printf("a = 0x%X, %d\n", (unsigned int)(a), *a);         // a = 0xBF83FA7C
    printf("a + 1 = 0x%X, %d\n", (unsigned int)(a + 1), *(a+1)); // a + 1 = 0xBF83FA80
   
    printf("p = 0x%X\n", (unsigned int)(p));         // p = 0x0
    printf("p + 1 = 0x%X\n", (unsigned int)(p + 1)); // p + 1 = 0x4
   
    return 0;
}

操作:

1) gcc 28-1.c -o 28-1.out编译正确,打印结果:

a = 0xBF83FA7C, 1    
a+1 = 0xBF83FA80, 2    //a + 1地址增加4位
p = 0x0
p + 1=0x4           //p + 1地址增加4位

分析:

        数组名+1或者指针+1,表示移动

 

二、指针的运算

1) 指针是一种特殊的变量,与整数的运算规则为

         p+n;<-->(unsigned int)p+n*sizeof(*p)    //*p表示原数据类型:int、char……

例子:
int* p = NULL;
p + 1 ==> 0 + 1 * sizeof(*p) ==> 0 + 1 * sizeof(int) ==> 0 + 4 ==> 4
a = 0xBFA00F83
a + 1 ==> 0xBFA00F38 + 1 * sizeof(*a) ==> 0xBFA00F38 + 1 * sizeof(a[0]) ==>
0xBFA00F38 + 1 * 4 ==> 0xBFA00F38 + 4 ==> 0xBFA00F3C

         结论:

         当指针p指向一个同类型的数组元素时:p+1

         将指向当前元素的下一个元素;p-1将指向当前元素的上一个元素

 

2) 指针之间只支持减法运算

3) 参与减法运算的指针类型必须相同

p1-p2;<-->((unsigned int)p1-(unsigned int)p2)/sizeof(type);

 

注意:

1、只有当两个指针指向同一个数组中的元素时,指针相减才有意义,其意义为指针所指元素的下标差

2、当两个指针指向的元素不在同一个数组中时,结果未定义

 

三、指针的比较

1) 指针也可以进行关系运算<,<=,>,>=

2) 指针关系运算的前提是同时指向同一个数组中的元素

3) 任意两个指针之间的比较运算(==!=)无限制

4) 参与比较运算的指针类型必须相同

int* p1;
char* p2;
                  
p1<p2    非法比较
实例分析
指针运算初探
28-2.c
#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;        //获取s1数组首地址
    char* p1 = &s1[3];    //获取s1[3]元素的地址
    char* p2 = s2;        //获取s2数组首地址
    int* p = &i;          
        
    printf("%d\n", p0 - p1);    //ok,0-3=-3
    //printf("%d\n", p0 + p2);    //Error,不存在加法运算
    printf("%d\n", p0 - p2);    //Error,指向不同数组,操作没有意义
    //printf("%d\n", p0 - p);     //Error,类型不一样
    //printf("%d\n", p0 * p2);    //Error,乘法运算不合法
    //printf("%d\n", p0 / p2);    //Error,除法运算不合法
        
    return 0;
}
实例分析
指针运算的应用
28-3.c
#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:关键点
    char* p = NULL;
   
    printf("pBegin = %p\n", pBegin);
    printf("pEnd = %p\n", pEnd);
   
    printf("Size: %d\n", pEnd - pBegin); //5-0=5
        
    for(p=pBegin; p<pEnd; p++)  //指针比较,都是char*类型,指向数组
    {
       printf("%c", *p);                 //打印hello
    }
   
    printf("\n");
  
    return 0;
}

操作:

1) gcc 28-3.c -o 28-3.out编译正确,打印结果:

pBegin = 0xbfa14327
pEnd = 0xbfa1432c     //因为指向的元素为char,地址+5
Size: 5
Hello 

分析:

1. pEnd = s + DIM(s)
==> s + 5 ==> 0xbfa62bff + 5 * sizeof(*s) ==> 0xbfa62bff + 5 * sizeof(char) ==> 0xbfa62bff + 5*1
==> 0xbfa62bff + 5 ==> 0xbfa62c04
2. pEnd指向了数组中s[5],实际中s最大只有s[4],这是一个数组中擦边球技术,虚拟了一个s[5],在C++标准库中也有应用
3. 指针操作可以用在连续内存,比如数组、二维数组       

小结:

1) 数组声明时编译器自动分配一片连续的内存空间

2) 指针声明时只分配了用于容纳地址值的4字节空间

3) 指针和整数可以进行运算,其结果为指针

4) 指针之间只支持减法运算,其结果为数组元素下标差

5) 指针之间支持比较运算,其类型必须相同

发布了40 篇原创文章 · 获赞 1 · 访问量 1754

猜你喜欢

转载自blog.csdn.net/piaoguo60/article/details/104077348
28-