一 指针的运算
指针可以作为算数运算,赋值运算和关系运算表达式的有效操作。但是,并非所有在这些表达式中使用运算符都可以处理指针变量。指针只能参与有限的几种算数运算。指针可以进行增 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];
它表示,数组*p有4个int型元素,分别为(*p)[0]、(*p)[1]、(*p)[2]、(*p)[3] ,亦即p指向的是有4个int型元素的一维数组,即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");
}