C语言: 指针 -2

一 指针的运算

指针可以作为算数运算,赋值运算和关系运算表达式的有效操作。但是,并非所有在这些表达式中使用运算符都可以处理指针变量。指针只能参与有限的几种算数运算。指针可以进行增 1 (++) 和 减 1(--),给指针加上一个整数(+或+=),从指针中减去一个整数(-或-=),以及用一个指针减去另外一个指针这几种运算。

示例:

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

void main()
{
    int a[10] = { 1,2,3,4,5,6,7,8,9,10 };//数组名是数组的首地址
    
    printf("数组 a 的首地址=%p\n", a);

    for (size_t i = 0; i < 10; i++)
    {
        printf("a[%2d]= %d , *(a+%2d)=%d ", i, a[i],i, *(a + i)); //a[i] == *(a+i) :值相等,*(a + i) 随着 i 增加,指针向前递增,每次前进一个指针变量大小(4个字节)
        printf("   a[%2d]的地址= %p ,(a+%2d)的地址= %p \n",i, &a[i],i, (a + i)); //&a[i] == a+i :地址相同
    }

	printf("\n\n-----------------------\n\n");
	printf("使用指针修改数组元素的值:\n");

    for (int *p = a; p < a+10; p++)
    {
        *p = *p + 1;//元素的值加一
        //printf(" %d\n", *p);
    }

	int n = 0;
	int* vPtr = NULL;
	vPtr = a;
	while (vPtr<a+10)
	{
		printf("a[%2d]= %d\n",n, *vPtr);
		vPtr++;
		n++;
	}


	system("pause");
}

注意:  常见的错误 。1:对每有指向数组中某个元素的指针进行指针算数运算。2:对并不是指向同一个数组中元素的两个指针进行相加减或比较运算。3:在对指针进行算数运算时,指针超越了数组的边界。

如果有:a是一个数组

int a[5]={1,2,3,4,5};
int *p=a;
p++;

p++是先引用,再自增,自增一个sizeof(指针指向的类型)的大小。 ++指针在数组内部向前移动一个元素的大小。p=p+1; 指针在数组内部向前移动一个元素的大小。

*p++  等价于  *(p++) ,   ++是先引用再自增,指针在数组内部向前移动一个元素的大小。++p  先自增,再引用。

*(p++)  和 *(++p)的区别?

*(p++) 先引用*p,再自增p++, 等价于a[i++] 。*(++p) 先自增,再引用。(*p)++   取出指针指向的内容自增一下。

指针与指针的大小比较:

对两个毫无关联的指针比较大小是没有意义的,因为指针只代表了“位置”这么一个信息,但是,如果两个指针所指向的元素位于同一个数组(或同一块动态申请的内存中),指针的大小比较反映了元素在数组中的先后关系。

假设ptr_a和ptr_b分别指向a和b:则

操作意义

ptr_a < ptr_b

如果a存储在b的前面则返回true

ptr_a <= ptr_b

如果a存储在b的前面,或两个指针指向同一位置则返回true

ptr_a == ptr_b

如果两个指针指向同一位置则返回true

ptr_a != ptr_b

如果两个指针指向不同位置则返回true

ptr_a == NULL

如果ptr_a是空值则返回true

 

 

 

 

 

 

 

二 指针与数组:

在C语言中,指针和数组的联系极为紧密,它们可以互换使用。一个数组名可以看作一个常量指针。指针可以用于任何涉及下标的操作。

一维数组:

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

void main()
{
	int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
	printf("数组名:arr=%p ; 取数组名的地址 &arr=%p \n", arr, &arr);

	/*
	数组的地址的不同含义:
	sizeof(*arr) : 取出首地址的内容大小相当于取arr[0](int 类型 4个字节)。
	sizeof(*(&arr)):&arr 是取整个数组的地址,然后再取值 是整个数组的大小(根据数组的个数和存储的数据类型 这里是 10 * 4=40 )
	*/
	printf("(*arr)=%d ; (*(&arr))=%d \n ", sizeof(*arr), sizeof(*(&arr)));

	//指针遍历数组
	int* vPtr = arr;//数组名是数组的首地址
	
	int n = 0;
	while(vPtr < arr + 10)
	{
		printf("*(vPtr+%d) = %d \n", n, *vPtr);
		vPtr++;
		n++;
	}
	


	system("pause");
}

若有定义int(*p)[3];则定义了一个名为p的指针变量,表示p是一个指针变量,它可以指向每行有三个整数(即int型)元素的二维数组.p是指向一维数组的指针变量。这句话的理解是首先(*p)[3]是一个指向一维数组的指针变量,意思就是p这个指针是指向一个含有3个元素的数组的,那么p指针每一次加1就相当于把p中存的地址加6(前提是int类型占2个字节,在VC中是占4个字节)。举个例子:int a[3][3]; int( *p)[3]; p =a; //p=a的意思是把数组a的首地址存放到p中那么p[1]就是a[1][0]的地址,p[1][0]就等于a[1][0],而p[1][2]就等于a[1][2]

二维数组:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

void main()
{
	int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };

	for (size_t i = 0; i < 3; i++)
	{
		for (size_t j = 0; j < 4; j++)
		{
			//输出值及地址
			printf("arr[%d][%d]=%2d  &arr[%d][%d]=%p ;",i,j, arr[i][j],i,j, &arr[i][j]);
		}
		printf("\n\n");
	}
	
	printf("\n-------------------------\n");

	//arr 是一个行指针。指向一个有四个元素的数组(int类型),占16个字节 ,代表某一行的首地址
	printf("arr=%p ,arr+1=%p ,arr+2=%p \n", arr, arr + 1, arr + 2);	//每次加1 前进一行的大小
	//*arr 是一个指向int类型数据的指针
	printf("*arr=%p ,*arr+1=%p ,*arr+2=%p ,*arr+3=%p \n", *arr, *arr + 1, *arr + 2,*arr+3);//每次加1 前进一个元素的大小
	//*(arr+1) 指向第二行元素,*(arr+1)+n 指向第二行第n 个元素
	printf("*(arr+1)=%p ,*(arr+1)+1=%p ,*(arr+1)+2=%p ,*(arr+1)+3=%p \n", *(arr+1), *(arr + 1)+1, *(arr + 1) + 2, *(arr + 1) + 3);

	printf("\n-------------------------\n");

	printf("指针遍历输出元素:\n");

	for (size_t i = 0; i < 3; i++)
	{
		for (size_t j = 0; j < 4; j++)
		{
			printf("arr[%d][%d]=%3d ",i,j, *(*(arr + i) + j)); //*(*(arr + i) + j) == arr[i][j]
		}
		printf("\n\n");
	}


	system("pause");
}

对于二维数组:a[i][j] 等价于 *(*(a+i)+j)    &a[i][j]等价于*(a+i)+j   a[i]等价于*(a+i

C语言可以通过定义行数组指针的方法,使得一个指针变量与二维数组名具有相同的性质。行数组指针的定义方法:

数据类型 (*指针变量名)[二维数组列数]

例如 :int a[3][4]={{10,11,12,13},{20,21,22,23},{30,31,32,33}};  int *p=NULL;    int (*p)[4];

它表示,数组*p4int型元素,分别为(*p)[0](*p)[1](*p)[2](*p)[3] ,亦即p指向的是有4int型元素的一维数组,即p为行指针;此时,可用如下方式对指针p赋值:p=a;

多维数组:

假设三维数组 int arr[2][3][4];  其中的元素 arr[i][j][k] 可表示如下:

(1)*(arr[i][j]+k) :  arr[i][j]是 int 类型指针,其值为 &arr[i][j][0] ,因此,arr[i][j][k] 可表示为 *(arr[i][j]+k)。

(2)*(*(arr[i]+j)+k): arr[i] 是二级指针,其值为 *arr[i][0]。则:arr[i][j] = *(arr[i]+j)

(3)*(*(*(arr+i)+j)+k): 将 *(arr[i]+j) 形式的 arr[i] 替换为 *(arr+i) ,此处 arr 是三级指针,其值为 &arr[0]

arr [i]*(arr+i)
arr [i] [j]*(*(arr+i)+j)   OR *(arr[i]+j)
arr [i] [j] [k]*(*(*(arr+i)+j)+k)  OR  *(*(arr[i]+j)+k)
... ...... ...

 可以由此递推更高维数组

示例:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

void main()
{
	printf(" ----------------三维数组与指针:-------------------\n");
	int arr[2][3][4];
	int n = 0;

	printf("(1)初始化三维数组并输出:\n\n");

	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			for (int k = 0; k < 4; k++)
			{
				arr[i][j][k] = n;
				n++;
				printf("%3d", arr[i][j][k]);
			}
			printf("\n");
		}
		printf("\n");
	}


	printf("(2)指针访问并输出:\n\n");

	printf("sizeof(*arr)=%d 等同于一个面 面指针\n", sizeof(*arr)); // 3行4列 12个(int 类型)元素,占48个字节 
	printf("sizeof(*(arr[0])=%d 等同于一行 行指针\n", sizeof(*(arr[0])));//每行4个(int)元素 占16个字节
	printf("sizeof(*(arr[0][0]+0)=%d 等同于单个元素 行指针\n", sizeof(*(arr[0][0]+0)));//某个元素,第n面,n行 n个

	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			for (int k = 0; k < 4; k++)
			{   
				//*(arr[i][j]+k) 等价于 arr[i][j][k] 等价于 *(*(arr[i]+j)+k) 等价于  *(*(*(arr+i)+j)+k)
				printf("%3d", *(*(*(arr + i) + j) + k));
			}
			printf("\n");
		}
		printf("\n");
	}


	system("pause");
}

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

void main()
{
	printf(" ----------------四维数组与指针:-------------------\n");
	int arr[2][3][4][5];
	printf("数组 arr 的字节数为%d:\n\n", sizeof(arr));
	int count = sizeof(arr) / sizeof(int);//点
	printf("数组 arr 的元素个数为%d:\n\n", count);

	int area = sizeof(*(arr[0][0]+0)); //面
	int row = area / sizeof(int); //行(线)
	int volume= sizeof(*(arr))/ sizeof(int);//体


	if (count > 0)
	{
		printf(" ----------------指针线性初始化数组并输出:-------------------\n");
		int i;
		//int *p=&arr[0][0][0][0] 指针p 指向数组首地址
		for (int* p = &arr[0][0][0][0], i = 0; p < &arr[0][0][0][0] + count; p++)
		{
			*p = i; //元素赋值
			i++;
			printf("%5d", *p);
			if ((*p + 1) % row == 0)
			{
				printf("\n");
			}
			if ((*p + 1) % area == 0)
			{
				printf("\n\n");
			}
			if ((*p + 1) % volume == 0)
			{
				printf("\n\n\n");
			}

		}

		for (size_t i = 0; i < 2; i++)
		{
			for (size_t j = 0; j < 3; j++)
			{
				for (size_t k = 0; k < 4; k++)
				{
					for (size_t l = 0; l < 5; l++)
					{
						printf("%5d", *(*(*(*(arr + i) + j) + k) + l)); //四级指针
					}
					printf("\n");
				}
				printf("\n\n");
			}
			printf("\n\n");
		}

	}
	system("pause");
}

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值