C--数组名与指针

1.数组名

1.1 分类

  • 数组定义:char a[5];
  • 形参数组名:void fun(char b[]);
  1. 数组名a代表一个固定的地址,内涵在于其指代实体是数组这种数据结构,可以理解为指针常量,但不是指针常量!(比如sizeof(a)等于5,而sizeof(指针)等于4),另外数组名a不能用作左值;形参数组名b是指针变量,在函数fun中可以用作左值。
  2. 数组名a作右值时,a代表数组首元素的地址,而&a代表整个数组的首地址。这两个值是相等的,但是意义不相同,在参与运算的时候有不同的表现。
  3. 数组名传入函数形参后,会失去本身常量的特性,变为一个普通的指针。

1.2 示例

如下代码用于查看数组名的特性以及区别:

#include 

void fun(char b[])	//形参数组名
{
	b++;
	printf("%c\n", *b);
}

int main()
{
	char a[5] = { 'a', 'b', 'c' };
	printf("%p %p\n", a, a + 1);
	printf("%p %p\n", &a, &a + 1);
	printf("%d %d\n", sizeof(a), sizeof(&a));
	//a++;	//报错:表达式必须是可修改的左值
	fun(a);

	return 0;
}

1.3 运行

C--数组名与指针_第1张图片

1.4 说明

第一行printf:a表示数组首元素地址,a+1地址会偏移一个元素,由于数组类型为char,所以结果a+1的地址较a加了1。
第二行printf:&a+1地址同样会偏移,不同的是由于&a表示整个数组的首地址,所以&a+1会偏移整个数组大小的地址;
第三行printf:数组名的sizeof值等于数组所占用的内存字节数;32位编译器中,指针类型的变量或常量返回值通常是4(字节)。
第四行printf:形参数组名失去了数组名的常量特性,可以自增自减。


2.指针数组

指针数组的一般定义方式类似char *p[10];p优先和[ ]结合,表示核心是数组,这个数组中存储的内容全部是指针变量。指针数组适合用来指向若干个字符串,使字符串处理更加方便,如果使用二维数组来存,可能会因为字符串长度不固定带来内存单元浪费。常见的比如int main(int argc, char* argv[]);

2.1 初始化

指针数组初始化赋值有以下三种方式:

  • 定义时初始化:char *p[] = {“aaa”, “bbb”, “ccc”};
  • 定义后初始化,逐个赋值
    • *p = “aaa”; (p可以理解为一个二维指针)
    • p[0] = “aaa”;

2.2 示例

如下代码演示如何将指针数组传递给函数形参,以及函数如何获取指针数组的值:

#include 

void Fun(char **pt)
{
	printf("%s\n", *pt);
	printf("%s\n", *(pt+ 1));
	
	printf("%s\n", pt[0]);
	printf("%s\n", pt[1]);
}

int main()
{
	char *p[] = {"aa", "bbb"};	//定义一个指针数组
	Fun(p);

	return 0;
}

2.3 运行

C--数组名与指针_第2张图片

2.4 说明

在函数形参需要接收指针数组时,除了可以使用char *p[]定义方式,还可以使用char **p定义方式,效果一样。


3.数组指针

数组指针的一般定义方式类似char (*p)[5];p优先和*结合,表示核心是指针,这个指针指向的是一个数组。

3.1 示例

定义一个数组指针,赋值为数组名,然后查看数组指针的运算性质:

#include 

int main()
{
	char a[10] = { 'a', 'b', 'c' };
	char(*p)[5];					//定义一个数组指针
	p = a;
	printf("%p %p\n", p, p + 1);
	printf("%c\n", *(*p + 1));

	return 0;
}

3.2 运行

C--数组名与指针_第3张图片

3.3 说明

如最开始所说,a代表数组首元素地址,a+1较a地址会偏移1个长度,但是赋值给p后,进行了类型转换,p相当于5元素数组的首地址,所以p+1较p地址会偏移5个长度。
char (*p1)[5];char *p2;的区别:

  • p1用于指向5个元素的首地址;p2用于指向单个元素的首地址。
  • p1可以理解为一个二维指针;p2则是一维指针。

你可能感兴趣的:(C语言)