优秀的编程知识分享平台

网站首页 > 技术文章 正文

C语言学习第22篇---数组和指针的关系剖析

nanyue 2024-09-04 10:05:26 技术文章 4 ℃

原文首发于同名微信公号「Allen5G」,欢迎大家搜索关注,欢迎转发!


数组的本质:

  • 数组是一段连续的内存空间
  • 数组的空间大小为sizeof(array_type)*array_size
  • 数组名可以看做指向数组的第一个元素的常量指针(只是理解,其实是错的,参见《征服C指针》)

实验1: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;
}

理解:

当指针p指向一个同类型的数组的元素时:p+1将指向当前元素的下一个元素:p-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", p0 - p1);
 printf("%d\n", p0 + p2);
 printf("%d\n", p0 - p2);
 printf("%d\n", p0 - p);
 printf("%d\n", p0 * p2);
 printf("%d\n", p0 / p2);
	
 return 0;
}

实验3:指针运算的应用

#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);
	
 for(p=pBegin; p<pEnd; p++)
 {
 printf("%c", *p);
 }
 
 printf("\n");
 
 return 0;
}

数组的访问方式有两种

  • 下标的方式
  • 指针的形式

分析下两种方式的不同:(下标形式对于阅读代码更优)

  • 指针一固定增量在数组中移动时,效率高于下边形式
  • 指针增量为1且硬件具有硬件增量模型时,效率更高
  • 下标形式与指针形式的转换:

实例4:数组的访问方式

#include <stdio.h>
 
int main()
{
 int a[5] = {0};
 int* p = a;
 int i = 0;
 
 for(i=0; i<5; i++)
 {
 p[i] = i + 1;
 }
 
 for(i=0; i<5; i++)
 {
 printf("a[%d] = %d\n", i, *(a + i));
 }
 
 printf("\n");
 
 for(i=0; i<5; i++)
 {
 i[a] = i + 10;
 }
 
 for(i=0; i<5; i++)
 {
 printf("p[%d] = %d\n", i, p[i]);
 }
 
 return 0;
}

实验5:数组与指针的差别

#include <stdio.h>
 
int main()
{
 //extern int* a;
	int a[] = {1, 2, 3, 4, 5};
 
 printf("&a = %p\n", &a);
 printf("a = %p\n", a);
 printf("*a = %d\n", *a);
 
 
 return 0;
}
 
 
、、、、、、、、、、、、、、、、、
int a[] = {1, 2, 3, 4, 5};

a和&a的区别

  • a为数组首元素的地址
  • &a为整个数组的地址
  • a和&a的区别在于指针运算

实例6:指针运算的经典问题

#include <stdio.h>
 
int main()
{
 int a[5] = {1, 2, 3, 4, 5};
 int* p1 = (int*)(&a + 1); 
 int* p2 = (int*)((int)a + 1);
 int* p3 = (int*)(a + 1);
 
 printf("%d, %d, %d\n", p1[-1], p2[0], p3[1]);
 
 return 0;
}
// A. 数组下标不能是负数,程序无法运行
// B. p1[-1]将输出随机数,p2[0]输出2, p3[1]输出3
// C. p1[-1]将输出乱码, p2[0]和p3[1]输出2

数组函数:数组作为函数参数时,编译器将其编译为对应的指针

实例7:数组参数探究

#include <stdio.h>
 
void func1(char a[5])
{
 printf("In func1: sizeof(a) = %d\n", sizeof(a));
 
 *a = 'a';
 
 a = NULL;
}
 
void func2(char b[])
{
 printf("In func2: sizeof(b) = %d\n", sizeof(b));
 
 *b = 'b';
 
 b = NULL;
}
 
int main()
{
 char array[10] = {0};
 
 func1(array);
 
 printf("array[0] = %c\n", array[0]);
 
 func2(array);
 
 printf("array[0] = %c\n", array[0]);
 
 return 0;
}

小结:

最近发表
标签列表