C语言指针——指针与数组

种一棵树最好的时间是十年前,其次是现在。

指针与数组

一、指针的运算

指针可以进行三种运算:

1.指针加上整数

如果指针p指向数组a[i],那么指针p + j 指向a[i + j](前提是a[i + j]存在!)

2.指针减去整数:

如果指针p指向数组a[i],那么指针p - j 指向a[i - j](前提 a[i - j] 存在!)

3.两个指针相加减两指针必须指向同一变量!!!否则运算没有意义的!

当两个指针相减时,结果是指针在内存上的距离,可以用数组元素的个数来度量,所以如果指针p指向a[ i ],q指向a[ j ],那么p - q就等于i - j.

指针比较:指针可以使用 >  <  =  >=  <=  ==  != 等符号进行比较,(也是只有在指针指向同一数组时,使用关系运算符进行的指针比较才有意义!)

二、指针用于数组的处理

由于指针的算术运算,所以我们可以通过指针的自增自减来访问数组的元素。

#include<stdio.h>

int main()
{
	int a[10] = {0,1,2,3,4,5,6,7,8,9};
	int *p;
	for(p = &a[0];*p < a[10];p++)
	{
		printf("%d\n",*p);
	}
	
	
	return 0;
}

使用数组下标可以写出不用指针的循环,有一种论调说使用指针可以节省时间,不过对于现在的编译器来说,实际上会自动对使用下标的循环进行优化,即依靠下标的循环会产生更好的代码(大佬说的 [^.^])

*和++组合使用:

#include<stdio.h>

int main()
{
	int a[10] = {0,1,2,3,4,5,6,7,8,9};
	int *p = &a[0];// *p = a;
	while (*p < a[10])
	{
		printf("%d\n",*p++);
	}	
	return 0;
}

当然还有*++p、(*p)++

三、用数组名作为指针

1.可以用数组名作为指向数组第一个元素的指针。例如int a[10] ;    *a = 7 ;这样就是把a[0]元素给他赋值7。通常情况下a + i 就相当于&a[i] ,*(a + i) 就相当于a[i]。

2.数组变量本身表达地址,所以用数组对指针初始化不用&取地址符号,int a[10]; int *p = a;    。但是数组的每一个元素表达的是一个变量,需要取地址符&。 

3.[ ]也可以对指针做,p[0] 相当于a[0] 。*也可以对数组做, *a 相当于a[0]。

注意:当数组变量是一个const类型的指针,就不能被赋值了!

 

4.数组作为函数参数

下面我们看一个有趣的东西( It's amazing!):

#include<stdio.h>
void test1(int a[]);

int main()
{
	int a[5] = {0,1,2,3,3};
	printf("main中sizeof(a[]) = %lu\n",sizeof(a));
	
	test1(a);
	
	return 0;
}

void test1(int a[])
{
	printf("函数中sizeof(a[]) = %lu\n",sizeof(a));
}

运行结果如下:

amazing

在函数test1中sizeof传进去的数组我们发现他的字节大小是8!而不是数组本身的字节大小 20!有趣吧哈哈哈哈QAQ。这是因为数组作为参数传参的时候传进去的是一个指针!就是之前我们说了的数组变量是一个特殊的指针。数组名在传递给函数的时候总是被视为指针

这对我们有很大的意义!:

(1).在给函数传递普通变量时,变量的值会被复制,任何对相应的形式参数的改变都不会影响到变量。而作为实际参数的数组我们可以改变(除非const了一下它)!

(2).给函数传递数组的时间与数组的大小半毛钱关系都没有!(编译器:“我根本就没对你数组进行复制,没想到吧!哈哈哈”)

(3).我们可以在需要的时候吧数组形式参数声明为指针。(编译器对数组和指针的声明完全看做是一样滴)

注意:对于形式参数而言,声明为数组跟声明为指针是一样的;但是对于变量而言声明为数组跟声明为指针是不同的!

5.用指针名当做数组名(如下代码)

#include<stdio.h>

int main()
{
	int a[10],*p = a, i = 0;
	
	for(i = 0;i < 10;i++)
	{
		*p++ = i;
		printf("%d\n",a[i]);
	}
	
	return 0;
}

指针名做函数名

四、指针与多维数组

int a[4][5] = {
   
   {0,1,2,3,4},{10,11,12,13,14},{20,21,22,23,24},{30,31,32,33,34}};

可以把这个理解为包含四个行元素的数组:a[0]、a[1]、a[2]、a[3],可以把a[0]

还需要记住的是数组名为首元素的地址。有这样的说法a不是a[0][0]的地址,但是我试了一下,结果是它们地址相同,所以总结成一句话:数组名为首元素地址。

行指针:一个二维数组每一行视为一个一维数组,指向每一行的一维数组的指针。

处理多维数组的行:

#include<stdio.h>

int main()
{
	int a[4][5] = {
   
   {0,1,2,3,4},{10,11,12,13,14},{20,21,22,23,24},{30,31,32,33,34}};
	int *p,i = 0,j = 4;
	i = 3;
	for (p = a[i];p < a[i] + j;p++)//p = a[i]给p初始化.p < a[i] + j 中a[i]+j表示的是a[i][j] 
	{
		*p = 0;
	}
	
	printf("%d\n",a[i][2]);//输出验证第i行第2列是否为0 
	return 0;
}

p++运行一次之后 就相当于 p +1 就相当于 a[i] +1 就相当于 a[i][1]

处理多维数组的列:

#include<stdio.h>

int main()
{
	int a[4][5] = {
   
   {0,1,2,3,4},{10,11,12,13,14},{20,21,22,23,24},{30,31,32,33,34}};
	int (*p)[5],i = 2;//(*p)的括号不可省略![5]这个表示的是一维数组的长度,不可省略!定义了一个行指针,其宽度为5(即二维数组的列数为5) 
	for ( p = &a[0]; p < &a[4];p++)//p=&a[0]是把第0行那个一行的一维数组的地址交给p这个行指针  &a[4]相当于a+4. p=&a[0]相当于p=a 
	{
		(*p)[i] = 0;//(*p)这里代表着a的一整行 
	} 
	printf("%d\n",a[2][i]);//输出验证第2行第2列是否为0 
	return 0;
}

 

 

猜你喜欢

转载自blog.csdn.net/qq_51182221/article/details/115032443