指针进阶--数组

目录

指针回顾

一、字符指针

二、指针数组

三、数组指针

基本概念

&arr 与 arr

数组指针的使用

二位数组的传参


指针回顾

        指针的本质是一个用来存放地址的变量,大小在三十二位系统下是4字节,六十四位系统下是8字节。

        指针有不同类型,主要作用是用于计算步长,比如在对int*变量加减1是,总会跳过四个字节,对于char*则是一个字节。

一、字符指针

        字符指针,顾名思义,即用来存放字符地址的变量,如下:

#include<stdio.h>
int main()
{
	char c = 'w';
	char* pc = &c;
	*pc = 's';
	printf("%c\n", c);
	return 0;
}

 值得注意的是如果代码写作:char* pstr = "hello world" 则指针变量的本质是存放了首元素的地址,而不是整个字符串,且由于这是一个常量字符串,故而内容不可以通过指针解应用修改内容。请看下面一道面试题目:

#include <stdio.h>
int main()
{
    char str1[] = "hello bit.";
    char str2[] = "hello bit.";
    const char *str3 = "hello bit.";
    const char *str4 = "hello bit.";
    if(str1 ==str2)
        printf("str1 and str2 are same\n");
    else
        printf("str1 and str2 are not same\n");
    if(str3 ==str4)
        printf("str3 and str4 are same\n");
    else
        printf("str3 and str4 are not same\n");
    return 0;
}

其中str3和str4指向的是不可以修改的常量字符串,因此系统会把他们分配到同一块内存中去,也无需另外开辟空间。但是数组的内容是可以修改,对于不同的数组只不过是在初始化的时候赋予了同样的值,但本质上他们指向了不同的内存区域。故该题运行结果如下:

二、指针数组

指针数组本质上是数组,只不过其元素是地址,例如:

int* arr1[10] 这是一个有着十个元素的数组,数组中每一个元素都是一个整型指针;

char* arr2[10] 这是一个存放字符指针的数组,总共是个元素

三、数组指针

基本概念

数组指针不同于指针数组,从字面上来看,数组指针的概念与整型指针、字符指针等概念相统一,他也是一种指针,只不过指针指向的是整个数组,如下:

int (*p)[10] = &arr  int (*)[10] 是数组指针的类型, 括号中的*先和p结合,表明p是一个指针,int表明数组中元素的类型是int。注意:由于[ ]的优先级高于*,所以必须加上(),注意区分int* p1[10](指针数组)。 

&arr 与 arr

了解了数组指针的概念,我们有必要了解&arr 与 arr之间的区别,请看如下代码:

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	printf("arr = %p\n", arr);
	printf("&arr= %p\n", &arr);
	printf("arr+1 = %p\n", arr + 1);
	printf("&arr+1= %p\n", &arr + 1);
	return 0;
}

 根据以上代码及其运行结果,我们可以发现,尽管arr和&arr 在结果上是一样的,但他们本质上的意义却不同,其中arr本质意义是首元素的地址,在加减操作时,跳过的长度与元素大小一致;而&arr是数组指针,代表整个数组的地址,在加减操作时会步长是一整个数组。

数组指针的使用

        数组指针一般不在一维数组中使用

        二维数组的使用如下:

#include<stdio.h>

void print1(int arr[3][5], int row, int col)
{
	int i = 0,j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}

void print2(int(*arr)[5], int row, int col)
{
	int i, j;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			printf("%d ", *(*(arr+i)+j));
		}
		printf("\n");
	}
}


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

	return 0;
}

 上述代码中,print2函数是利用数组指针进行操作的,其中arr就相当于二维数组第一行的地址,因此将其作为实参就相当于一个数组指针,在打印时 arr+i 获得元素所在行的整个数组的地址,对其进行解应用获得所在行首元素的地址,+j获得元素所在列的地址,解应用获得该地址存放的元素。

区分几种表示形式

int arr[5];   有五个元素的整型数组
int *parr1[10];  存放是个整型指针的数组
int (*parr2)[10]; 数组指针
int (*parr3[10])[5] 存放数组指针的数组,parr3是一个有十个元素的数组,每一个元素都是一个数组指针,数组指针指向的数组有5个整型元素。

对于以上形式的区分最重要的是要认识到,int* , int (*)[]等都是类型,不要因为放置的顺序问题而搞混。

二位数组的传参

void test(int arr[3][5])//ok?//可以,数组传参的标准形式
{}
void test(int arr[][])//ok? //不可以,不能省略列数
{}
void test(int arr[][5])//ok? //可以,可以省略行
{}

void test(int *arr)//ok? //不可以,实参是数组指针,而形参是一个整型指针
{}
void test(int* arr[5])//ok? //不可以,实参是指针,形参是数组,类型不匹配
{}
void test(int (*arr)[5])//ok? //可以,实参可以表示二维数组第一行的地址,即一个数组指针
{}
void test(int **arr)//ok? //不可以,第一行的地址并不是一个二级指针
{}
int main()
{
int arr[3][5] = {0};
test(arr);
}

总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。这样才方便运算。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值