C语言之数组和指针分析

数组的本质:

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

指针的运算:

指针与整数运算

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

p + n — (unsigned int)p + n * sizeof( * p)

结论:
当指针p指向一个同类型的数组的元素时:p+1将指向当前元素的下一个元素;p ;p-1将指向当前元素的上一个元素

#include <stdio.h>

int main()
{
	int a[5] = {0};
	
	printf("%0x %0x\n", a, a+1);
}

运行结果:

在这里插入图片描述

#include <stdio.h>

int main()
{
	int a[5] = {1,2,3};		

	int i;
	for(i=0; i<5; i++)
	{
		printf("%d\n",*(a+i));	
	}
}

在这里插入图片描述

指针之间只支持减法运算:

指针之间只支持减法运算,且必须参与运算的指针类型必须相同。

p1 – p2 — ( (unsigned int)p1 - (unsigned int)p2) / sizeof(type); 【其实就是上面公式的逆推…】

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

#include <stdio.h>

int main()
{
	char s1[] = {'H','e','l','l','o'};
	char s2[] = {'W','o','r','l','d'};
	char* p0 = s1;
	char* p1 = &s1[3];
	char* p2 = s2;


	printf("%d\n", p0 - p1);
	printf("%d\n", ((unsigned int)p0 -(unsigned int)p1)/sizeof(char) );//套用公式

	printf("%d\n", 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);
	char* p = NULL;

	for(p = pBegin; p < pEnd; p++)
	{
		printf("%c\n",*p);
	}
	
	return 0;
}

在这里插入图片描述

数组的访问:

int a[5];

a[3] = 5;//以下标的形式访问数组

*(a+3) = 5;//以指针的形式访问数组

两种形式是等价的

下标vs指针:

从理论上而言,当指针以固定增量在数组中移动时 ,其效率高于下标产生的代码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
{
	clock_t start;
	clock_t end;
	
	int a[10000];
	int b[10000];
	
	int* pEnd = &a[10000];
	int* pa = NULL;
	int* pb = NULL;
	
	int k = 0;
	int i = 0;
	
	start = clock();
	
	for(k = 0; k<10000; k++)
	{
		for(i = 0; i<10000; i++)
		{
			b[i] = a[i];
		}
	}
	
	end = clock();
	
	printf("Index Timing: %d\n",end - start);
	
	start = clock();
	
	for(k=0; k<10000; k++)
	{
		for(pa = a, pb = b ; /*这是一条语句*/ pa<pEnd;)
		{
			*pb++ = *pa++;
		}
	}
	
	end = clock();
	
	printf("Point Timing: %d\n", end-start);
}

运行结果:

在这里插入图片描述
这种情况:指针会明显快于下标方式

a和&a的区别:

a为数组是数组首元素的地址

&a为整个数组的地址

a和&a的意义不同其区别在于指针运算

在这里插入图片描述

#include <stdio.h>

int main()
{
	int a[5] = {1,2,3,4,5};

	printf("a : %0x\n",a);

	printf("a+1 : %0x\n",a+1);

	printf("&a+1 : %0x\n",&a+1);
	
	return 0;
}

在这里插入图片描述
可以看到:a和a+1差4,a和&a+1差20

一道摩托罗拉的面试题:

#include <stdio.h>

int main()
{
	int a[5] = {1,2,3,4,5};
	int* p1 = (int*)(&a + 1); //a[4]
	int* p2 = (int*)((int)a +1);//0x02000000
	int* p3 = (int*)(a+1);//a[1]

	printf("%d, %d, %d\n",p1[-1],p2[0],p3[1]);
	
	return 0;
}

在这里插入图片描述

数组参数:

C语言中,数组作为函数参数时 ,编译器将其编译成对应的指针

void f(int a[]); — void f(int* a);
void f(int a[5]); — void f(int* a);

结论:
一般情况下,当定义的函数中有数组参数时 ,需要定义另一个参数来标示数组的大小

#include <stdio.h>

void f(int a[1000]) //等价于int* a
{
	printf("%d\n",sizeof(a));		
}

int main()
{
	int a[5] = {0};
	int i = 0;

	f(a);
	
	return 0;
}

在这里插入图片描述

指针和数组的对比

数组声明时编译器自动分配一片连续内存空间
指针声明时只分配了用于容纳指针的4字节空间
在作为函数参数时,数组参数和指针参数等价
数组名在多数情况可以看做常量指针,其值不能改变
指针的本质是变量,保存的值被看做内存中的地址

猜你喜欢

转载自blog.csdn.net/QQ1402369668/article/details/88773474