数组和指针

原创 2016年06月02日 10:45:16

1,一维数组 

先看一下一个整型数组关于数组名的表达式在内存中所占的字节数

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int a[] = { 1, 2, 3, 4 };
	printf("%d\n", sizeof(a)); //  16  在sizeof中,数组名a不发生降级,代表整个数组
	printf("%d\n", sizeof(a+0)); //  4   在sizeof中,如果是关于a的表达式,那a就代表数组首元素的地址,就是一个整型指针,向后偏移0,不变
	printf("%d\n", sizeof(*a));  //  4   a代表数组首元素的地址,解引用a访问a[0]的内容,一个整型
	printf("%d\n", sizeof(a+1));  //  4  a代表数组首元素的地址,加1向后偏移一个整型空间,表示a[1]的地址
	printf("%d\n", sizeof(a[1]));  //  4  a[1]是整型,占4个字节
	printf("%d\n", sizeof(&a));  //  4  数组名在取地址时也不发生降级,&a取出的是整个数组的地址,与a[0]的地址相同
	printf("%d\n", sizeof(&a+1));  //  4  &a是数组的地址,类型是数组指针,&a+1要跳过整个数组,即跳过16个字节,但依然是个地址,所以还是4个字节
	printf("%d\n", sizeof(&a[0]));  //  4   取出a[0]的地址,占4个字节
	printf("%d\n", sizeof(&a[0]+1));  //  4  取出a[0]的地址,向后偏移4个字节,指向a[1]的地址
	printf("%d\n", sizeof(*&a));  //  4  取出整个数组的地址,再解引用,相当于访问整个数组
	system("pause");
	return 0;
}

wKioL1Zhhr6Ak_RWAABPbUmgCGk551.png

注意:数组名在以下两个情况下不发生降级,代表整个数组,

(1)sizeof(a)中,a代表整个数组;

(2)在&a中,代表整个数组的地址;

在其他地方,数组名都代表数组首元素的地址。

    关于为什么&a+1,&a是数组的地址,&a+1就要跳过整个数组,可以这样理解

int *p = NULL;
	p + 1;

p是一个整型指针,给p+1就是加上一个整型指针所占的字节数,那么同样&a+1就要加上整个数组所占的字节数,即跳过整个数组。

    上面说了&a取出来的地址和a的地址相同,但是有一点不同的是,它们向后偏移的字节数并不相同。例如:

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int a[] = { 1, 2, 3, 4 };
	printf("%p\n", a);
	printf("%p\n", &a);
	printf("%p\n", a+1);
	printf("%p\n", &a+1);
	system("pause");
	return 0;
}

wKioL1ZhhniCuWurAABVd4YozGI195.png

从上面就可以看出来,在&a+1加了整个数组所占字节数,对a+1就向后偏移了一个整型空间。

数组名做左值和右值:

(1)数组名做右值代表数组首元素的地址,与&a[0]相同,而不是数组的首地址。但编译器没有为a开辟一个空间来存放a的地址。这与指针变量是不同的。对于指针变量p,内存开辟了一块空间来存放p的地址。

(2)数组名不能做为左值!对数组进行访问要对它的元素访问,不能通过数组名对整个数组进行访问。

对关于字符数组的表达式在内存中所占的字节数:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	char ch[] = "abcdef";
	printf("%d\n", sizeof(ch[0])); //  1  代表字符'a'
	printf("%d\n", sizeof(&ch)); //  4   是数组地址,放在指针变量里,占4个字节
	printf("%d\n", sizeof(*ch));  //  1  在这儿ch代表数组首元素地址,*ch访问ch[0]='a'
	printf("%d\n", sizeof(&ch+1));  //  4  &ch+1向后偏移整个数组所占字节数
	printf("%d\n", sizeof(ch+1));  //  4  ch代表数组首元素地址,是一个指针,加1依然是个指针
	printf("%d\n", sizeof(ch));  //  7  六个字符还有一个'\n'
	printf("%d\n", strlen(ch));  //  6  有效字符长度  
	printf("%d\n", strlen(&ch));  //  6   &ch与ch的地址相同,从这个位置开始向后找'\0'
	printf("%d\n", strlen(&ch + 1));  //  随机值 ,因为&ch+1向后偏移整个数组的大小,不确定在什么时候遇到'\0'
	printf("%d\n", strlen(ch+1));  //  5  首元素地址加1,向后偏移一个字节,从ch[1]到ch[5],长度为5
	system("pause");
	return 0;
}

wKiom1ZhjnOA0m8zAABVwtL7Yyo048.png

2,指针

在定义指针时,

int arr[]={ 1, 2, 3, 4 };
int *p = arr;//*与p结合,不是和类型int结合
*p=20;//这样的赋值是错误的,因为不知道p到底指向哪里
*p++;//无意义,先解引用,再对p所指向的内容自加 
p++;//有意义,访问下一个空间

指针加1等价于加(1*sizeof(arr))

int *p=NULL与*p=NULL有区别吗?

(1)

int *p=NULL;//定义一个指针变量,并且将它的值赋为NULL,也就是对p进行了初始化,在内存中查看p的值为0x00000000

(2)

int *p;//定义了一个指针变量,它的值并不知道,有可能是一个非法的地址
*p=NULL;//对一块非法的内存进行赋值当然会出现错误了。编译器可能会报一个内存访问出错

(3)

int a=10;
int *p=&a;
*p=NULL;//这样就正确了。就可以成功的将a的内容改为0啦!

再看看这样的代码:

int arr[4]={1,2,3,4};
int *p=&arr;//错误 &arr代表整个数组的地址,是一个数组指针,*p是一个整型指针,间接级别不同
int (*p)[4]=&arr;//这就对了,指针数组用来存放整个数组的地址
int *p=arr;//arr代表数组首元素的地址,刚好赋给一个整型指针

对关于指针的表达式在内存中所占的字节数:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	char *ch = "abcdef";  //ch是一个指向abcdef的字符指针,里面存了a的地址。
	printf("%d\n", sizeof(ch[0])); //  1  ch[0]相当于*(ch+0),代表字符'a'
	printf("%d\n", sizeof(&ch)); //  4   取一个指针变量的地址,地址占4个字节
	printf("%d\n", sizeof(*ch));  //  1   在这儿ch代表数组首元素地址,*ch访问ch[0]='a'
	printf("%d\n", sizeof(&ch+1));  //  4  &ch+1是一个二级指针,还是一个地址
	printf("%d\n", sizeof(ch+1));  //  4  ch代表数组首元素地址,是一个字符指针,加1还是个地址
	printf("%d\n", sizeof(ch));  //  4  ch是一个指针变量,所以是4个字节
	printf("%d\n", strlen(ch));  //  6  有效字符长度  
	printf("%d\n", strlen(&ch));  //  随机值   &ch取出来是name的地址,从这个位置开始向后找'\0'不确定
	printf("%d\n", strlen(&ch + 1));  //  随机值 ,原因同上
	printf("%d\n", strlen(ch+1));  //  5  首元素地址加1,向后偏移一个字节,长度为5
	system("pause");
	return 0;
}

wKiom1ZioySw4hYnAAA7HxWwvZ4577.png

利用常量指针操控内存:

wKioL1ZitnGDHmMoAAEq6DAt-4Q166.png原因:在没有执行p=NULL之前,p的值就被赋成了0,这也是必然的结果,在p中存放的就是0x0018ff44;那再对p进行解引用,访问p的内容将它赋为空也就是将p直接赋成0;

3,数组和指针

int  i=0;
char arr[]="abcdef";
char *parr="abcdef";

使用数组下标访问指针:

printf("%c",arr[i]);

使用指针访问数组:

printf("%c",*(arr+i));

使用数组下标访问指针:

printf("%c",parr[i]);

使用指针访问指针:

printf("%c",*(parr+i));

数组指针和指针数组:

(1)数组指针:

int arr[10] = { 0 };
int *p1 = arr;
int *p2 = &arr;//错误,&arr取出来的是整个数组地址,报出int *与int (*)[10]的间接级别不同
int(*p3)[10] = &arr;//数组地址放在数组指针里面
**p=&arr;//错误,**p用来存放一级指针的地址

int (*p3)[10]中,[]不能省略,它代表数组的类型和大小。

接下来看两个例子:

例一

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int *ptr = (int *)(&a + 1);
	printf("%d %d\n", *(a + 1), *(ptr - 1));
	system("pause");
	return 0;
}

wKiom1ZiwSCCFGCMAAA2lfocZh8183.png

结果分析:

*(a+1)中a代表数组首元素的地址,加1向后偏移一个整型空间到a[1]的地址,再解引用访问a[1]。

吧一个数组指针强制类型转换为整型指针,(&a+1)是向后偏移一个数组a的大小。*(ptr-1)就是向前偏移一个整型空间访问到a[4]。

例二

在sum.c中:

char arr[] = "abcdef";

在test.c中:

#include<stdio.h>
#include<stdlib.h>
extern char arr[];
int main()
{
	printf("%s\n", arr);
	system("pause");
	return 0;
}

正常输出abcdef

#include<stdio.h>
#include<stdlib.h>
extern char *arr;
int main()
{
	printf("%s\n", arr);
	system("pause");
	return 0;
}

运行后崩溃了,因为arr被声明为一个指针变量,占4个字节,所以它只能访问数组arr中的前4个元素abcd,并且把它当成了一个地址,指针变量arr的内容就不知道了。所以定义成数组,声明为指针是不合理的。

#include<stdio.h>
#include<stdlib.h>
extern char *arr;
int main()
{
	printf("%s\n", (char *)(&arr));
	system("pause");
	return 0;
}

正常输出abcdef,对指针变量arr取地址,就相当于取出'a'的地址,但是它是一个char **类的指针,所以强制类型转换为一级指针就可以访问arr的内容了。

由上面的例子,也可以看出数组和指针并不是一回事!

本文出自 “Stand out or Get out” 博客,请务必保留此出处http://jiazhenzhen.blog.51cto.com/10781724/1719729

C语言中指针与数组的区别与联系

好久不写东西了,从毕业以来,整个人都懒散了很多。今天终于鼓起勇气,来写一点儿东西…… 指针与数组对于C语言程序员来说肯定不会陌生,一说起这个话题,我就想起了曾经被内存、地址、地址里的内容这些概念狂虐时...
  • cyfcsd
  • cyfcsd
  • 2017年02月03日 17:29
  • 4488

C语言:数组和指针的区别

实际上关于数组与指针的区别这个问题在《C专家编程》已经有很详细的阐释,但我想用自己的语言说一说我的理解。数组是指针?最近在做数据结构课设,其中一个函数发生了令人费解的错误,简化后的代码如下:#incl...
  • imred
  • imred
  • 2015年05月02日 19:08
  • 13956

数组与指针关系

1
  • App_12062011
  • App_12062011
  • 2013年09月15日 20:25
  • 3339

关于C语言你不知道的事(1)–指针和数组的区别

关于C语言你不知道的事(1)–指针和数组的区别 Table of Contents 1 一个很多人都会做错的面试题 2 数组与指针的差别 2.1 数组和指针是如何访问的 2.2 数组和指针可...
  • huangkangying
  • huangkangying
  • 2014年12月29日 21:59
  • 3585

C/C++数组和指针详解

/****************************************************************/ /*            学习是合作和分享式的! /* Au...
  • wdzxl198
  • wdzxl198
  • 2013年06月13日 16:16
  • 7067

C语言指针与数组易混淆知识点(一)

一指针与数组 二指针与函数 三指针数组数组指针指向指针的指针 四程序陷阱 一、指针与数组指针:指针本身也是一个变量,它的内容是指向的内容的地址。指针同样有类型的区分,char 的指针只能指向char型...
  • woshimalingyi
  • woshimalingyi
  • 2016年03月25日 15:59
  • 3035

探讨下C++中的数组和指针的区别

最近一段时间在研究虚拟现实方面的内容,有一段时间没写代码,重拾C++,顺便记录下C++中容易出错的内容,数组和指针的区别。很多新手都抱怨说C++难,尤其是指针和数组,傻傻分不清楚,那么我就从我对数组和...
  • transferli
  • transferli
  • 2016年03月24日 13:04
  • 310

指针,数组转换漫谈

先给出几个定义: int a [10] :即是说明 a 是一个连续的内存块,有10个结构,这个结构被看成 int 去解析。 int * b = a;即是说明 b 是一个内存块,有 1 个结构,这个...
  • lizhihaoweiwei
  • lizhihaoweiwei
  • 2014年07月19日 12:42
  • 1180

《C专家编程》:指针和数组的区别详解(四)

C语言编程新手常听到的说法之一就是“数组和指针是相同的”。不幸的是,这是一种非常危险的说法,并不完全正确。 一、什么是声明,什么是定义。 注意下面声明的区别: extern int...
  • gogoky
  • gogoky
  • 2016年05月24日 10:21
  • 1020

数组与指针间的转换浅析

可以允许把指针好像数组名一样进行标记 #define N 100 int a[N],i,sum=0,*p=a; for(i=0;i sum+=p[i]; 对待p[i]就像对待*(p+i)一样...
  • Moon_K_H
  • Moon_K_H
  • 2015年01月09日 22:35
  • 2325
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:数组和指针
举报原因:
原因补充:

(最多只允许输入30个字)