指针进阶----指针和数组

1.简单介绍sizeof和strlen

1.sizeof

首先,sizeof并不是C语言中的一个内置函数,而是一个运算符。在这里我们看几个sizeof的应用:

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	char arr2[] = "abcde";
	int sz1 = sizeof(arr1);
	int sz2 = sizeof(arr2);
	printf("sz1=%d\n", sz1);
	printf("sz2=%d\n", sz2);
	return 0;
}

这段代码输出结果为:

sz1=20

sz2=6

如果你不了解sizeof这一运算符,你可能会疑惑:sz2为什么是6而不是5呢?

那是因为,sizeof的本质是获取了数据在内存中所占用的空间,并以字节为单位来计数。

当计算“ ”(双引号)中的字符串所占空间的大小时,C语言会在这一串字符串的末尾自动添上一个‘\0’来作为结束标志,并对应0的ASCII码值。当sizeof遇到‘\0’时,也要将‘\0’视为占用了内存空间。

了解到这里,我们就能明白为什么sz2输出的结果是6而不是5了。

2.strlen

strlen()是C语言中的内置函数。

size_t strlen ( const char * str );

strlen函数接收字符串的地址,并返回这个字符串的长度。以下是他的简单应用:

int main()
{
	char arr1[] = "abcde";
	int len1 = strlen(arr1);
	printf("%d\n", len1);
	return 0;
}

这段代码的输出结果是:

len1=5

但是,当我们把字符放在数组中,再调用这个函数时:

int main()
{
	char arr1[] = { 'a','e','q'};
	char arr2[] = "abcde";
	int len1 = strlen(arr1);
	int len2 = strlen(arr2);
	printf("%d\n", len1);
	printf("%d\n", len2);
	return 0;
}

输出结果:

我们看到,len1输出的结果为37,那这是为什么呢?

因为我们将a 、e、q放在了一个数组中,而数组中并不会在动加上‘\0’这一元素,所以strlen会在arr1这一数组后边的内存空间里找‘\0’,直到找到为止。所以字符串的长度自然就不准确了。

2.指针和数组

了解完sizeof和strlen,我们来看他们和指针、数组结合时的用法。

下面请看这一段代码:

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

第一条语句:当我们使用sizeof(数组名)时,这里的数组名代表的就是整个数组的。所以sizeof(a)这一语句,计算的是整个数组所占内存空间的大小。

数组中一共4个整形元素,每个整形元素占用4个字节,所以总共是16个字节

应输出:16

第二条语句:a+0看似和a相同,但实际上完全不同。这里的a是数组名,所以表示的是数组首元素的地址,也就是a[0]的地址。地址加0之后不变,所以这里的(a+0)表示的还是首元素的地址。而地址的大小在32位系统下,是4个字节;在64位系统下,是8个字节。

输出:4

第三条语句:a是数组首元素的地址,*是解引用,所以*a就代表这数组的第一个元素,也就是1。也就是sizeof(int),整形所占内存大小为4个字节。

输出:4

第四条语句:a是首元素的地址,加1表示第二个元素的地址,既然是地址,那么在内存中就占4/8个字节。

输出:4

第五条语句:a[1]是数组的第2个元素,也就是2,计算的是整形所占内存空间。

输出:4

第六条语句:&a中,a表示的是整个数组,是取出整个数组的地址的意思。所以&a本质上还是指针类型,占4/8个字节。

输出:4

第七条语句:&a表示整个数组的地址,但是*解引用之后,又变成a,sizeof(a)表示的是整个数组的大小。

输出:16

第八条语句:&a表示整个数组的地址,加1指向的是另外一个数组的起始地址。所以也占用4/8个字节。

输出:4

第九条语句:a[0]表示数组的首元素1,&a[0]表示取出数组首元素1的地址。占用4/8个字节。

输出:4

第十条语句:a[0]表示数组的首元素1,&a[0]表示取出数组首元素1的地址。加1指向下一个元素的地址。占4/8个字节。

输出:4

上边是在一维数组中的应用,下面我们来看在字符数组中的应用:

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));//1
printf("%d\n", sizeof(arr+0));//2
printf("%d\n", sizeof(*arr));//3
printf("%d\n", sizeof(arr[1]));//4
printf("%d\n", sizeof(&arr));//5
printf("%d\n", sizeof(&arr+1));//6
printf("%d\n", sizeof(&arr[0]+1));//7

1: arr作为数组名,单独放在sizeof()里时,代表整个数组,所以计算的是整个字符数组的大小。

输出:6

2:与上边一维数组相同,arr在这里表示的是首元素的地址,加0后地址不变。地址也就是指针,指针变量所占空间大小为4/8个字节。

输出:4

3:arr在这里是数组名,且不是单独放在sizeof()中,所以表示数组首元素的地址。解引用操作后表示的是数组的首元素,也就是‘a’。

输出:1

4:arr[1]表示数组中下标为1的元素,也就是第二个元素‘b’。

输出:1

5:&arr表示取出整个数组的地址,而地址就是指针,指针所占内存的大小一律为4/8个字节。

输出:4

6:&arr是当前整个数组的地址,加1指向了下一个数组的首地址,但本质还是地址,所以所占内存仍是4/8。

输出:4

7:arr[0]表示数组的首元素,&arr[0]取出首元素的地址,加1则指向第二个元素的地址。

输出:4

接着我们看strlen在字符数组里的应用:

char arr[]={'a','b','c','d','e','f'};
printf("%d\n", strlen(arr));//1
printf("%d\n", strlen(arr + 0));//2
printf("%d\n", strlen(*arr));//3
printf("%d\n", strlen(arr[1]));//4
printf("%d\n", strlen(&arr));//5
printf("%d\n", strlen(&arr + 1));//6
printf("%d\n", strlen(&arr[0] + 1));//7

1:strlen函数从字符串的开头开始访问,直到遇到‘\0’才停下来。然而在arr数组中,只是单纯存放了字符,并没有存放\0,所以会越界访问,直到遇到\0才会停止。所以输出结果应是一个随机数。

输出:随机数

2:arr表示首元素地址,加0后不变,所以仍然是从首元素开始访问,遇到\0停止,仍是返回一个随机数。

输出:随机数

3:这里需要注意的是,arr是数组首元素的地址,*arr是数组的首元素,‘a’的ASCII码值为97.然而strlen函数的参数必须传一个地址,当我们传递‘a’-97时,97就作为一个地址,从而无法正确访问内存

输出:err

4:与上一条语句相似,arr[1]也是数组元素,传输的是该元素的ASCII码值,造成无法正确访问内存

输出:err

5:&arr表示整个数组的地址,strlen访问全部的元素,遇到\0停止,所以会越界

输出:随机值

6:&arr表示当前字符数组的地址,加1后变成了下一个数组的地址,而下一个数组是未知的,所以返回一个随机值

输出:随机值

7:&arr[0]是数组里第一个元素的地址,加1表示下一个元素的地址。然而数组中并没有\0元素,所以数组会一直访问,最终返回一个随机值

输出:随机值

char arr[] = "abcdef";
	printf("%d\n", sizeof(arr));//1
	printf("%d\n", sizeof(arr + 0));//2
	printf("%d\n", sizeof(*arr));//3
	printf("%d\n", sizeof(arr[1]));//4
	printf("%d\n", sizeof(&arr));//5
	printf("%d\n", sizeof(&arr + 1));//6
	printf("%d\n", sizeof(&arr[0] + 1));//7
	

1:当数组名arr单独放在sizeof里,表示整个数组的大小。而这里将“ ”双引号里的字符串传给字符数组,所以自带‘\0’,在计算数组大小时,‘\0’也占用内存空间

输出:7

2:此时arr表示首元素的地址,加0后仍指向首元素。是指针变量,应输出4/8.

输出:4

3:arr是首元素的地址,解引用之后变成首元素的值a。

输出:1

4:arr[1]表示下标为1 的元素,也就是数组中的第二个元素b

输出:1

5:&arr取出的是整个元素的地址,但本质上还是地址,输出4/8.

输出:4

6:&arr+1表示下一个数组的首地址,应输出:4/8.

输出:4

7:&arr[0]表示首元素的地址,加1之后指针向右挪1位,指向第二个元素。但仍是指针。

输出:4

char arr[] = "abcdef";
printf("%d\n", strlen(arr));//1
printf("%d\n", strlen(arr + 0));//2
printf("%d\n", strlen(*arr));//3
printf("%d\n", strlen(arr[1]));//4
printf("%d\n", strlen(&arr));//5
printf("%d\n", strlen(&arr + 1));//6
printf("%d\n", strlen(&arr[0] + 1));//7

1:arr是数组首元素的地址,且数组中元素包括\0,所以strlen不会越界访问,而是返回字符串的真实长度。

输出:6

2:arr表示数组首元素地址,加0后指针位置不变,所以还是访问整个字符串,并返回字符串长度。

输出:6

3:因为我们知道strlen需要接收一个地址,arr是首元素的地址,然而解引用后变成了元素,所以无法正确访问字符串。

输出:err

4:arr[1]是数组中下标为1的元素,不是地址,所以无法正确访问。

输出:err

5:&arr取出整个数组的地址,然而在数值上仍然是首元素的地址,所以访问整个元素,返回元素个数。

输出:6

6:&arr加1指向下一个数组的首元素地址,由于不知道‘\0’的具体位置,所以一直访问,输出随机值。

输出:随机值

7:&arr[0]取出首元素的地址,加1后指向第二个元素,所以是从第二个元素开始访问,返回字符串里字符的个数。

输出:5

以上是利用sizeof()和strlen()来计算数组的大小和长度。总结来说有以下要点:

  1. sizeof(数组名)。当出现这样的形式,数组名单独作为参数时,这里的数组名是整个数组的地址,表示的也是整个数组的大小
  2. &数组名。这里取出的是整个数组的地址。
  3. strlen()在传参时,应传入数组的地址,而不是一个元素。并且当数组中没有‘\0’时,会一直向后访问,直到遇到‘\0’为止。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值