C和C++C指针数组型数组

指针相关问题
using namespace
int main(){
//a) 一个整型数( An integer)
//b) 一个指向整型数的指针( A pointer to an integer)
//c) 一个指向指针的的指针,它指向的指针是指向一个整型数( A pointer to a pointer to an integer)
//d) 一个有 10 个整型数的数组( An array of 10 integers)
int d[10];
//e) 一个有 10 个指针的数组,该指针是指向一个整型数的( An array of 10 pointers to integers)
int *e[10]
//f) 一个指向有 10 个整型数数组的指针( A pointer to an array of 10 integers)
int (*f)[10];
//g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数( A pointer to a functionthat takes an integer as an argument and returns an integer)
int *g(int);
//h) 一个有 10 个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数( An array of ten pointers to functions that take an integer argument and return an integer
int (*h[10])(int);
我相信很多同学,都学习过指针数组、数组指针等,核心内容就是
[]优先级高于*
阅读(...) 评论()如何删除数组中的某个元素?比如数组a【10】,要删除元素a【2】,如何实现?;如何删除字符串指针指向的字符串中的某个字符?比如char *s="abcde";想删除b,也即输出acde
数组中的元素是不能删掉的,你只能去覆盖他,也就是用新元素代替以前的老元素。但是覆盖后要确保你有一个计数器或者标志来记录数组中的元素已经少了一个。比如整形数组a[5],你要将a[2]删掉,需要将a[3]和a[4]两个元素前移一位,同时记录有效数组元素为4,否则a[4]仍然有效;
要将字符串中某个元素删掉也是同样的道理,所不同的是字符串有规定的结束标志 ,那就是空白符0,因此你只需要将s[3]和s[4]前移一位,然后将a[4]值为0就可以了
其他答案(共2个回答)
char* solve(char *s, char *t)
char* c = (char*)...
需要获得一块内存区域之后指针数组才能使用
void main()
char *b = (char *)malloc(...
中文名数组指针运用领域计算机编程源于编程语言,如c,c++本质指针1数组指针与指针数组2二维数组指针3指向一维数组和二维数组的区别4举例数组指针数组指针与指针数...
数组指针举例编辑数组指针:inta{1,2,3,4,5,6,7,8,9,10,11,12};int(*p);for(inti0;i3;i++){for(i...
在这个类中声明数组:
static int itest[10];
在含有类的非inline函数定义的文件中定义:
int 类名::itest[10]={1,2,...
答: 汇编语言和c语言混编 用keil怎么写入单片机啊?求步骤!谢谢!
答: 可以看懂,我也是这样自学C语言的.但编好程序后最好要上机调试,才知道自已所编程序是否正确和实用.
答: 韩国网络语言中“掌柜的”表示对中国的蔑称。
规模以上工业企业是指全部国有企业(在工商局的登记注册类型为"110"的企业)和当年产品销售收入500万元以上(含)的非国有工业企业。
如果是下拉的,只有党员而没有预备党员一项,可填党员,但如果是填写的,你就老老实实填预备党员,填成党员对你没什么好处,填预备党员也不会有什么吃亏。
有可能搓纸轮需要清洗一下了,如果清洗了还是不行的话,那估计需要更换搓纸组件了
1、问:房地产开发企业拆迁补偿费是否也随土地价格一起交纳契税(以房易房部分的)?
答:是的,因为取得土地的成交价格包括:地出让金、土地补偿费、安置补助费、地上附着物和青苗补偿费、拆迁补偿费、市政建设配套费等承受者应支付的货币、实物、无形资产及其它经济利益,而契税中未对房地产企业有相关的减免政策
2、问:如果交,是就补给拆迁户交差价部分交税还是就全部回迁房价格交税?在什么环节,时间交纳?
答:所谓使用回迁房作为拆迁补偿的形式,就是开发商以原地或异地的房屋抵顶拆迁补偿费的一种方法,相当于延期或分期支付拆迁补偿款,而契税条例中规定是:“纳税义务发生时间在纳税人签订土地、房屋权属移交合同的当天,或者纳税人取得其他具有土地、房屋权属转移合同性质凭证的当天。纳税人应在自纳税义务起10日内,向土地、房屋所在地的税收征收机关办理纳税申报,并在税务征收机关核定的期限内缴纳税款。 ”所以需要在取得土地的时候就要缴纳契税,需要全额计税,不能以补偿款计税。
3、问:土地使用税在什么环节交?如何交?税法说确有困难的可以减或缓,各地有具体政策吗?
答:如果原土地属于耕地的,自取得土地后满一年开始征收,如果属于非耕地的,自取得土地之下月征收。
以前的土地使用税一般都予以减免,特殊情况例外,虽然国家税务总局《关于土地使用税若干具体问题的补充规定》,对于基建项目在建期间使用的土地可以免税,但很多地方的税务机关都认为这不适用房地产企业,因为现在国家是控制房地产过热,不属于鼓励范围。
4、问:回迁部分房屋的营业税在什么环节交?
答:在交付回迁房屋或被拆迁户全部支付差价的时候缴纳,如果不需要支付差价的,以成本价格作为计税依据,如果有差价的,不需要支付部分按成本价格计税,差价部分按实际计税。
考虑是由于天气比较干燥和身体上火导致的,建议不要吃香辣和煎炸的食物,多喝水,多吃点水果,不能吃牛肉和海鱼。可以服用(穿心莲片,维生素b2和b6)。也可以服用一些中药,如清热解毒的。
确实没有偿还能力的,应当与贷款机构进行协商,宽展还款期间或者分期归还; 如果贷款机构起诉到法院胜诉之后,在履行期未履行法院判决,会申请法院强制执行; 法院在受理强制执行时,会依法查询贷款人名下的房产、车辆、证券和存款;贷款人名下没有可供执行的财产而又拒绝履行法院的生效判决,则有逾期还款等负面信息记录在个人的信用报告中并被限制高消费及出入境,甚至有可能会被司法拘留。
第一步:教育引导
不同年龄阶段的孩子“吮指癖”的原因不尽相同,但于力认为,如果没有什么异常的症状,应该以教育引导为首要方式,并注意经常帮孩子洗手,以防细菌入侵引起胃肠道感染。
第二步:转移注意力
比起严厉指责、打骂,转移注意力是一种明智的做法。比如,多让孩子进行动手游戏,让他双手都不得闲,或者用其他的玩具吸引他,还可以多带孩子出去游玩,让他在五彩缤纷的世界里获得知识,增长见识,逐渐忘记原来的坏习惯。对于小婴儿,还可以做个小布手套,或者用纱布缠住手指,直接防止他吃手。但是,不主张给孩子手指上“涂味”,比如黄连水、辣椒水等,以免影响孩子的胃口,黄连有清热解毒的功效,吃多了还可导致腹泻、呕吐。
合肥政务区网络广告推广网络推广哪家公司比较好 一套能在互联网上跑业务的系统,被网络营销专家赞为目前最 有效的网络推广方式!
1、搜索引擎营销:分两种SEO和PPC,即搜索引擎优化,是通过对网站结构、高质量的网站主题内容、丰富而有价值的相关性外部链接进行优化而使网站为用户及搜索引擎更加友好,以获得在搜索引擎上的优势排名为网站引入流量。
良工拥有十多位资深制冷维修工程师,十二年生产与制造经验,技术力量雄厚,配有先进的测试仪器,建有系列低温测试设备,备有充足的零部件,包括大量品牌的压缩机,冷凝器,蒸发器,水泵,膨胀阀等备品库,能为客户提供迅捷,优质的工业冷水机及模温机维修和保养。
楼主,龙德教育就挺好的,你可以去试试,我们家孩子一直在龙德教育补习的,我觉得还不错。
成人可以学爵士舞。不过对柔软度的拒绝比较大。  不论跳什么舞,如果要跳得美,身体的柔软度必须要好,否则无法充分发挥出理应的线条美感,爵士舞也不值得注意。在展开暖身的弯曲动作必须注意,不适合在身体肌肉未几乎和暖前用弹振形式来做弯曲,否则更容易弄巧反拙,骨折肌肉。用静态方式弯曲较安全,不过也较必须耐性。柔软度的锻炼动作之幅度更不该超过疼痛的地步,肌肉有向上的感觉即可,动作(角度)保持的时间可由10馀秒至30-40秒平均,时间愈长对肌肉及关节附近的联结的组织之负荷也愈高。
正在加载...
Copyright &
Corporation, All Rights Reserved
确定举报此问题
举报原因(必选):
广告或垃圾信息
激进时政或意识形态话题
不雅词句或人身攻击
侵犯他人隐私
其它违法和不良信息
报告,这不是个问题
报告原因(必选):
这不是个问题
这个问题分类似乎错了
这个不是我熟悉的地区
相关问答:123456789101112131415C++中字符串以及数组和指针的互相使用讲解
转载 &更新时间:日 17:07:31 & 投稿:goldensun
这篇文章主要介绍了C++中字符串以及数组和指针的互相使用讲解,是C++入门学习中的基础知识,需要的朋友可以参考下
C++字符串与指针
在C++中可以用3种方法访问一个字符串(在第5章介绍了前两种方法)。
用字符数组存放一个字符串
【例】定义一个字符数组并初始化,然后输出其中的字符串。
#include &iostream&
int main( )
char str[]="I love CHINA!";
cout&&str&&
运行时输出:
I love CHINA!
用字符串变量存放字符串
【例】定义一个字符串变量并初始化,然后输出其中的字符串。
#include &string&
#include &iostream&
int main( )
string str="I love CHINA!";
cout&&str&&
用字符指针指向一个字符串
【例】定义一个字符指针变量并初始化,然后输出它指向的字符串。
#include &iostream&
int main( )
char *str="I love CHINA!";
cout&&str&&
对字符串中字符的存取,可以用下标方法,也可以用指针方法。
【例】将字符串str1复制为字符串str2。
定义两个字符数组str1和str2,再设两个指针变量p1和p2,分别指向两个字符数组中的有关字符,通过改变指针变量的值使它们指向字符串中的不同的字符,以实现字符的复制。
#include &iostream&
int main( )
char str1[]="I love CHINA!",str2[20],*p1,*p2;
p1=str1;p2=str2;
for(;*p1!='\\0';p1++,p2++)
*p2='\\0';
p1=str1;p2=str2;
cout&&"str1 is: "&&p1&&
cout&&"str2 is: "&&p2&&
运行结果为:
str1 is: I love CHINA!
str2 is: I love CHINA!
这个例子用来说明怎样使用字符指针。其实,对例6.13来说,用string变量来处理是十分简单的:
string str1=″I love CHINA!″,str2; //定义string变量
str2=str1; //将str1复制到str2
C++数组与指针
指向数组元素的指针
一个变量有地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。指针变量既然可以指向变量,当然也可以指向数组元素(把某一元素的地址放到一个指针变量中)。所谓数组元素的指针就是数组元素的地址。
int a[10];
//定义一个整型数组a,它有10个元素
int *p; //定义一个基类型为整型的指针变量p
p=&a[0]; //将元素a[0]的地址赋给指针变量p,使p指向a[0]
在C++中,数组名代表数组中第一个元素(即序号为0的元素)的地址。因此,下面两个语句等价:
在定义指针变量时可以给它赋初值:
int *p=&a[0]; //p的初值为a[0]的地址
也可以写成
int *p=a; //作用与前一行相同
可以通过指针引用数组元素。假设p已定义为一个基类型为整型的指针变量,并已将一个整型数组元素的地址赋给了它,使它指向某一个数组元素。如果有以下赋值语句:
*p=1; //对p当前所指向的数组元素赋予数值1
如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素。
如果p的初值为&a[0],则:
1) p+i和a+i就是a[i]的地址,或者说,它们指向a数组的第i个元素,见图6.12。
2) *(p+i)或*(a+i)是p+i或a+i所指向的数组元素,即a[i]。
可以看出,[]实际上是变址运算符。对a[i]的求解过程是: 先按a+i×d计算数组元素的地址,然后找出此地址所指向的单元中的值。
3) 指向数组元素的指针变量也可以带下标,如p[i]与*(p+i)等价。
根据以上叙述,引用一个数组元素,可用以下方法:
下标法,如a[i]形式;
指针法,如*(a+i)或*(p+i)。其中a是数组名,p是指向数组元素的指针变量。如果已使p的值为a,则*(p+i)就是a[i]。可以通过指向数组元素的指针找到所需的元素。使用指针法能使目标程序质量高。
【例】输出数组中的全部元素。假设有一个整型数组a,有10个元素。要输出各元素的值有3种方法:
1) 下标法。
#include &iostream&
int main( )
int a[10];
for(i=0;i&10;i++)
cin&&a[i]; //引用数组元素a[i]
for(i=0;i&10;i++)
cout&&a[i]&&" "; //引用数组元素a[i]
运行情况如下:
9 8 7 6 5 4 3 2 1 0↙
(输入10个元素的值)
9 8 7 6 5 4 3 2 1 0
(输出10个元素的值)
2) 指针法。
将上面程序第7行和第10行的“a[i]”改为“*(a+i)”,运行情况与(1)相同。
3) 用指针变量指向数组元素。
#include &iostream&
int main( )
int a[10];
int i,*p=a; //指针变量p指向数组a的首元素a[0]
for(i=0;i&10;i++)
cin&&*(p+i); //输入a[0]~a[9]共10个元素
for(p=a;p&(a+10);p++)
cout&&*p&&" "; //p先后指向a[0]~a[9]
运行情况与前相同。请仔细分析p值的变化和*p的值。
对3种方法的比较:
方法(1)和(2)的执行效率是相同的。第(3)种方法比方法(1)、(2)快。这种方法能提高执行效率。
用下标法比较直观,能直接知道是第几个元素。用地址法或指针变量的方法都不太直观,难以很快地判断出当前处理的是哪一个元素。在用指针变量指向数组元素时要注意: 指针变量p可以指向有效的数组元素,实际上也可以指向数组以后的内存单元。如果有
int a[10], *p=a;
//指针变量p的初值为&a[0]
cout&&*(p+10);
//要输出a[10]的值
在使用指针变量指向数组元素时,应切实保证指向数组中有效的元素。
指向数组元素的指针的运算比较灵活,务必小心谨慎。下面举几个例子。
如果先使p指向数组a的首元素(即p=a),则:
1) p++(或p+=1)。使p指向下一元素,即a[1]。如果用*p,得到下一个元素a[1]的值。
2) *p++。由于++和*同优先级,结合方向为自右而左,因此它等价于*(p++)。作用是: 先得到p指向的变量的值(即*p),然后再使p的值加1。例6.5(3)程序中最后一个for语句:
for(p=a;p&a+10;p++)
可以改写为
for(p=a;p&a+10;)
cout&&*p++;
3) *(p++)与*(++p)作用不同。前者是先取*p值,然后使p加1。后者是先使p加1,再取*p。若p的初值为a(即&a[0]),输出*(p++)得到a[0]的值,而输出*(++p)则得到a[1]的值。
4) (*p)++表示p所指向的元素值加1,即(a[0])++,如果a[0]=3,则(a[0])++的值为4。注意: 是元素值加1,而不是指针值加1。
5) 如果p当前指向a[i],则
&&& *(p--)&&& 先对p进行“*”运算,得到a[i],再使p减1,p指向a[i-1]。
&&& *(++p)&& 先使p自加1,再作*运算,得到a[i+1]。
&&& *(--p)&& 先使p自减1,再作*运算,得到a[i-1]。
将++和--运算符用于指向数组元素的指针变量十分有效,可以使指针变量自动向前或向后移动,指向下一个或上一个数组元素。例如,想输出a数组100个元素,可以用以下语句:
while(p&a+100)
cout&&*p++;
while(p&a+100)
在用*p++形式的运算时,很容易弄错,一定要十分小心,弄清楚先取p值还是先使p加1。
用指针变量作函数参数接收数组地址
在前面介绍过可以用数组名作函数的参数。前面已经多次强调: 数组名代表数组首元素的地址。用数组名作函数的参数,传递的是数组首元素的地址。很容易推想: 用指针变量作函数形参,同样可以接收从实参传递来的数组首元素的地址(此时,实参是数组名)。下面用指针变量作函数形参。
【例】将10个整数按由小到大的顺序排列。在例5.7程序的基础上,将形参改为指针变量。
#include &iostream&
int main( )
void select_sort(int *p,int n); //函数声明
int a[10],i;
cout&&"enter the originl array:"&&
for(i=0;i&10;i++) //输入10个数
cin&&a[i];
select_sort(a,10); //函数调用,数组名作实参
cout&&"the sorted array:"&&
for(i=0;i&10;i++) //输出10个已排好序的数
cout&&a[i]&&" ";
void select_sort(int *p,int n) //用指针变量作形参
int i,j,k,t;
for(i=0;i&n-1;i++)
for(j=i+1;j&n;j++)
if(*(p+j)&*(p+k)) k=j; //用指针法访问数组元素
t=*(p+k);*(p+k)=*(p+i);*(p+i)=t;
C++编译系统将形参数组名一律作为指针变量来处理。
实际上在函数调用时并不存在一个占有存储空间的形参数组,只有指针变量。
实参与形参的结合,有以下4种形式:
实& 参&&&&&&&&&&&&&&&& 形& 参
数组名&&&&&&&&&&&&& 数组名&&&&&&&
数组名&&&&&&&&&&& 指针变量&&&&&
指针变量&&&&&&&&& 数组名
指针变量&&&&&&& 指针变量
在此基础上,还要说明一个问题: 实参数组名a代表一个固定的地址,或者说是指针型常量,因此要改变a的值是不可能的。如:
a++; //语法错误,a是常量,不能改变
而形参数组名是指针变量,并不是一个固定的地址值。它的值是可以改变的。在函数调用开始时,它接收了实参数组首元素的地址,但在函数执行期间,它可以再被赋值。如:
f(array[], int n)
cout&& //输出array[0]的值
array=array+3; //指针变量array的值改变了,指向array[3]
cout&&*arr&& //输出array[3]的值
多维数组与指针
用指针变量可以指向一维数组中的元素,也可以指向多维数组中的元素。
1) 多维数组元素的地址
设有一个二维数组a,它有3行4列。它的定义为:
int a[3][4]={{1,3,5,7},{9,11,13,15},{17,18,21,23}};
a是一个数组名。a数组包含3行,即3个元素:a[0],a[1],a[2]。而每一元素又是一个一维数组,它包含4图6.14个元素(即4个列元素),例如,a[0]所代表的一维数组又包含4个元素: a[0][0], a[0][1], a[0][2], a[0][3]。可以认为二维数组是“数组的数组”,即数组a是由3个一维数组所组成的。
从二维数组的角度来看,a代表二维数组首元素的地址,现在的首元素不是一个整型变量,而是由4个整型元素所组成的一维数组,因此a代表的是首行的起始地址(即第0行的起始地址,&a[0]),a+1代表a[1]行的首地址,即&a[1]。
a[0],a[1],a[2]既然是一维数组名,而C++又规定了数组名代表数组首元素地址,因此a[0]代表一维数组a[0]中0列元素的地址,即&a[0][0]。a[1]的值是&a[1][0],a[2]的值是&a[2][0]。
0行1列元素的地址可以直接写为&a[0][1],也可以用指针法表示。a[0]为一维数组名,该一维数组中序号为1的元素显然可以用a[0]+1来表示。
欲得到a[0][1]的值,用地址法怎么表示呢?既然a[0]+1是a[0][1]元素的地址,那么,*(a[0]+1) 就是a[0][1]元素的值。而a[0]又是和*(a+0)无条件等价的,因此也可以用*(*(a+0)+1)表示a[0][1]元素的值。依此类推,*(a[i]+j)或*(*(a+i)+j)是a[i][j]的值。
2) 指向多维数组元素的指针变量
① 指向数组元素的指针变量
【例】输出二维数组各元素的值。这里采用的方法是用基类型为整型的指针变量先后指向各元素,逐个输出它们的值。
#include &iostream&
int main( )
int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
//p是基类型为整型的指针变量
for(p=a[0];p&a[0]+12;p++)
cout&&*p&&" ";
运行结果如下:
1 3 5 7 9 11 13 15 17 19 21 23
关于指向数组元素的指针变量的几点说明:
p是指向整型数据的指针变量,在for语句中对p赋初值a[0],也可以写成“p=&a[0][0]”。
循环结束的条件是“p&a[0]+12”,只要满足p&a[0]+12,就继续执行循环体。
执行“cout&&*p;”输出p当前所指的列元素的值,然后执行p++,使p指向下一个列元素。
②指向由m个元素组成的一维数组的指针变量
可以定义一个指针变量,它不是指向一个整型元素,而是指向一个包含m个元素的一维数组。这时,如果指针变量p先指向a[0](即p=&a[0]),则p+1不是指向a[0][1],而是指向a[1],p的增值以一维数组的长度为单位,见图6.17。
【例】输出二维数组任一行任一列元素的值。
#include &iostream&
int main( )
int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
int (*p)[4],i,j;
cin&&i&&j;
cout&&*(*(p+i)+j)&&
运行情况如下:
由于执行了“p=a”,使p指向a[0]。因此p+2是二维数组a中序号为2的行的起始地址(由于p是指向一维数组的指针变量,因此p加1,就指向下一个一维数组)。*(p+2)+3是a数组2行3列元素地址。*(*(p+2)+3)是a[2][3]的值。
3) 用指向数组的指针作函数参数
一维数组名可以作为函数参数传递,多维数组名也可作函数参数传递。
【例】输出二维数组各元素的值。题目与例6.7相同,但本题用一个函数实现输出,用多维数组名作函数参数。
#include &iostream&
int main( )
void output(int (*p)[4]); //函数声明
int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
output(a); //多维数组名作函数参数
void output(int (*p)[4]) //形参是指向一维数组的指针变量
for(i=0;i&3;i++)
for(j=0;j&4;j++)
cout&&*(*(p+i)+j)&&" ";
运行情况如下:
1 3 5 7 9 11 13 15 17 19 21 23
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具【c/c++】指针数组和数组指针
实例放在最上面的,这个能全部看懂,下面的知识也就不要再往下看的。如果不行,那么就好好看下去然后回来温习这个实例
#include&iostream&
#include&string.h&
char * cp = &hello world&;
cout && cp &&
//输出“hello world”
cout && *cp &&
//输出h单个字符
这个结果和之前char a[10],直接是cout&&a,结果是整个字符数组.但是别的类型的数组,其结果是首地址。
char *max(char *ps[], int n);
int main(){
char *s[5] = { &aaa&, &bbb&, &ccc&, &ddd&, &ccs& };
char(*q)[3];
p = max(s, 5);
//q = max(s,5);这样的出错原因是指针指向的类型不一样,前者是数组,后者是字符,因此出错
//*p的时候只出现一个值d,p的时候结果是ddd;要了解原因
//首先看到指针p定义最后指向的是一个字符,因此*p最后的结果肯定是单个字符,不是我们想要字符串
cout && &the max string:& && *p &&
cout && &the max string:& && p &&
char * max(char *ps[], int n){
//这样会报错,说不能将char**赋值给char*,也就是说指针数组的数组名不能像正常数组那样进行赋值,而是要用数组的第一个元素吗?
//这里终于明白了为什么ps不可以,而ps[0]就可以了。虽然ps是数组名可以代表首地址,但是你想想ps指向的数据类型是数组,而ps指向的数据类型是指针
//这样当然是不可以赋值的,指针指向的类型的不同就不同进行赋值操作
//那为什么ps[0]就可以呢,它不是一维数组吗,p=&a[0].那这里为什么不加取地址符啊,你看看之前a[0]存储的是数据,而这里的ps[0]里面
//存储是指针,也就是说ps[0]也是指针变量,最后指向的类型也是相同的,因此是可以赋值的。
q = ps[0];
for (int i = 0; i & i++){
//看strcmp的源代码定义:int
__cdecl strcmp(_In_z_ const char * _Str1, _In_z_ const char * _Str2);
if (strcmp(q, ps[i]) & 0)
q = ps[i];
1、指针数组和数组指针的内存布局
指针数组:首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身决定。它是“储存指针的数组”的简称。
数组指针:首先它是一个指针,它指向一个数组。在32 位系统下永远是占4 个字节,至于它指向的数组占多少字节,不知道。它是“指向数组的指针”的简称。
下面到底哪个是数组指针,哪个是指针数组呢:
int *p1[10];
int (*p2)[10];
这里需要明白一个符号之间的优先级问题。
“[]”的优先级比“*”要高。p1 先与“[]”结合,构成一个数组的定义,数组名为p1,int *修饰的是数组的内容,即数组的每个元素。那现在我们清楚,这是一个数组,其包含10 个指向int 类型数据的指针,即指针数组。至于p2 就更好理解了,在这里“()”的优先级比“[]”高,“*”号和p2 构成一个指针的定义,指针变量名为p2,int 修饰的是数组的内容,即数组的每个元素。数组在这里并没有名字,是个匿名数组。那现在我们清楚p2 是一个指针,它指向一个包含10 个int 类型数据的数组,即数组指针。我们可以借助下面的图加深理解:
2.论a 和&a 之间的区别
既然这样,那问题就来了。前面我们讲过a 和&a 之间的区别,现在再来看看下面的代码:
int main()
& &char a[5]={'A','B','C','D'};
& &char (*p3)[5] = &a;
& &char (*p4)[5] =
& &return 0;
上面对p3 和p4 的使用,哪个正确呢?p3+1 的值会是什么?p4+1 的值又会是什么?毫无疑问,p3 和p4 都是数组指针,指向的是整个数组。&a 是整个数组的首地址,a是数组首元素的首地址,其值相同但意义不同。在C 语言里,赋值符号“=”号两边的数据类型必须是相同的,如果不同需要显示或隐式的类型转换。p3 这个定义的“=”号两边的数据类型完全一致,而p4 这个定义的“=”号两边的数据类型就不一致了。左边的类型是指向整个数组的指针,右边的数据类型是指向单个字符的指针。在Visual
C++6.0 上给出如下警告:
& &warning C4047: 'initializing' : 'char (*)[5]' differs in levels of indirection from 'char *'。
还好,这里虽然给出了警告,但由于&a 和a 的值一样,而变量作为右值时编译器只是取变量的值,所以运行并没有什么问题。但是在最新的c++14中已经禁止这样写代码了,因此下面例子中关于p4+1这种情况就就不分析了
既然现在清楚了p3 和p4 都是指向整个数组的,那p3+1 和p4+1 的值就很好理解了。
#include &iostream&
int main() {
char a[5] = { 'A', 'B', 'C', 'D' };
char(*p3)[10] = &a;
// char (*p4)[5] =
cout && a &&
cout && &a &&
cout && p3 &&
cout && p3 + 1 &&
输出结果:ABCD
// 0xbfdf79fb
// 0xbfdf79fb
// 0xbfdf7a00
加一也就说加一整个字符数组的长度,即5个字节
//现在疑惑点来了,是用cout输出数组名的时候 居然能够直接输出数组中的内容而不是其首地址
//字符数组是可以用这种方式输出的, 因为数组名即代表首地址, 数组是一块连续的内存空间, 所以能直接输出.
//如果是其他类型的数组则输出的是一个地址.
int b[2] = {1,12};
cout&&b&&//这个时候输出的还真的是一个地址
这里有一个问题就是将char(*p3)[5]中的5改成别的数字可以吗?答案是肯定的,结果是程序出错,不允许运行
3.地址将强制类型转换
struct Test
& &char *pcN
& &short sD
& &char cha[2];
& &short sBa[4];
假设p 的值为0x100000。如下表表达式的值分别为多少?
& &p + 0x1 = 0x___ ?
& &(unsigned long)p + 0x1 = 0x___?
& &(unsigned int*)p + 0x1 = 0x___?
我相信会有很多人一开始没看明白这个问题是什么意思。其实我们再仔细看看,这个知识点似曾相识。一个指针变量与一个整数相加减,到底该怎么解析呢?
还记得前面我们的表达式“a+1”与“&a+1”之间的区别吗?其实这里也一样。指针变量与一个整数相加减并不是用指针变量里的地址直接加减这个整数。这个整数的单位不是byte 而是元素的个数。所以:p + 0x1 的值为0x;sizof(Test)*0x1。这个就好比地址对数字的加减运算是和数据类型是相关联的,只不过现在是换成结构体了
至于此结构体的大小为20byte,前面的章节已经详细讲解过。有边界补充,因此按照最大存储的字节乘以数量
所以p +0x1 的值为:0x100014。
(unsigned long)p + 0x1 的值呢?这里涉及到强制转换,将指针变量p 保存的值强制转换成无符号的长整型数。任何数值一旦被强制转换,其类型就改变了。所以这个表达式其实就是一个无符号的长整型数加上另一个整数。所以其值为:0x100001。
(unsigned int*)p + 0x1 的值呢?这里的p 被强制转换成一个指向无符号整型的指针。所以其值为:0x;sizof(unsigned int)*0x1,等于0x100004。当指针指向的数据类型发生变化,那么其关联数据类型基本单位存储大小也已经发生改变,因此,这里我们计算的基本单位的存储单元大小是要发生变化的。
首先去看指针指向数据的存储大小是多少,接着看地址要移动的数据大小是多少。然后相乘的结果加上原先的地址就是最后的结果。当然如果像中间的数据变换了,例如上面将其变为长整型的数据,那么你加减的结果就是常规的数据加减了
上面这个问题似乎还没啥技术含量,下面就来个有技术含量的:在x86 系统下,其值为多少?
& &int a[4]={1,2,3,4};
& &int *ptr1=(int *)(&a+1);
& &int *ptr2=(int *)((int)a+1);
& &printf(&%x,%x&,ptr1[-1],*ptr2);
& &return 0;
如果懂汇编,这道题目很简单
根据上面的讲解,&a+1 与a+1 的区别已经清楚。
ptr1:将&a+1 的值强制转换成int*类型,赋值给int* 类型的变量ptr,ptr1 肯定指到数组a 的下一个int 类型数据了。ptr1[-1]被解析成*(ptr1-1),即ptr1 往后退4 个byte。所以其值为0x4。
ptr2:按照上面的讲解,(int)a+1 的值是元素a[0]的第二个字节的地址。然后把这个地址强制转换成int*类型的值赋给ptr2,也就是说*ptr2 的值应该为元素a[0]的第二个字节开始的连续4 个byte 的内容。
其内存布局如下图:
好,问题就来了,这连续4 个byte 里到底存了什么东西呢?也就是说元素a[0],a[1]里面的值到底怎么存储的。这就涉及到系统的大小端模式了,如果懂汇编的话,这根本就不是问题。既然不知道当前系统是什么模式,那就得想办法测试。大小端模式与测试的方法在第一章讲解union 关键字时已经详细讨论过了,请翻到彼处参看,这里就不再详述。我们可以用下面这个函数来测试当前系统的模式。
int checkSystem( )
& &union check
& &c.i = 1;
& &return (c.ch ==1);
如果当前系统为大端模式这个函数返回0;如果为小端模式,函数返回1。也就是说如果此函数的返回值为1 的话,*ptr2 的值为0x2000000。如果此函数的返回值为0 的话,*ptr2 的值为0x100。
看过本文的人也看了:
我要留言技术领域:
取消收藏确定要取消收藏吗?
删除图谱提示你保存在该图谱下的知识内容也会被删除,建议你先将内容移到其他图谱中。你确定要删除知识图谱及其内容吗?
删除节点提示无法删除该知识节点,因该节点下仍保存有相关知识内容!
删除节点提示你确定要删除该知识节点吗?

我要回帖

更多关于 C/C++字符数组的输入输出 的文章

 

随机推荐