浅谈C中的指针和数组(六)
数组和指针,原本不想在写了,觉得这部分差不多了,但是自己在写程序的时候还是发现了一个错误。首先说一下我的要求:
给一个函数传递一个二维数组,然后我想在这个函数里面计算这个数组的行数。
写个类似的错误DEMO代码弄上来:
#include <stdio.h>
#include <stdlib.h> void func(int a[][])
{
printf("%p\n", a);
printf("%p\n", a[]);
printf("%p\n", &a); printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a[]));
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a)/sizeof(a[]));
printf("%d\n", a[][]);
}
int main()
{
int a[][] = {{,,},{,,}}; printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a[]));
printf("%d\n", sizeof(a)/sizeof(a[])); func(a); system("pause"); return ;
}
数组名本身是个地址常量,但是某些特殊情况下它的语义可以发生改变。例如sizeof(a),这时a表示整个数组对象(这里指语法对象,不是指类的实例)而不是这个常量本身。
基于这个语义,对数组名取地址也是合法的,对于数组a来说&a的结果等于a这个地址常量本身的值。这是C/C++标准委员会为了维护语法对象a作为一个左值(l-value)总可以取地址这条原则的
妥协。
#include <stdio.h>
int main(void)
{
char str[] = "world";
char * pstr = "world";
printf("%d %d",sizeof(str),sizeof(pstr));
getchar();
return ;
}
运行结果6 4。
解释:
char str[] = "world";
这里初始化不限定长度,而"world"包含结束符'\0'后为6个字符,因此初始化str的长度是6;又因为char数组中每个元素(char变量)占用1个字节的空间,所以str[]数组的大小是6字节。
char *pstr = "world";
由于pstr是指针,无论是否指向字符串,指向什么字符串,sizeof(pstr)等于sizeof(int),32位平台上等于4。
造成差别的原因:
这里char str[] = "world";声明并定义了一个数组str[](当然,C语言的语法不允许在定义之外这样引用整个数组,以下这样的写法只是为了区分语义),之后标识符str有双重语义:一是类
型为char* const的地址常量,它的值等于数组中首个元素的地址,即str等价于(char* const)&str[0];二是表示整个str[]数组这个语法对象。在sizeof(str)中,str表示的含义是str[],因
此返回整个数组的大小(这个大小在之前的数组定义中已经确定了);而pstr只是个指针,sizeof(pstr)只能返回指针本身占用的字节数而不能确定为它指向的内容分配的空间的大小。
(注意,地址常量绝不是指针,类型不同!虽然在函数的参数传递过程中,地址常量可以退化成对应的指针。这里LZ和2L显然由于这个错误理解导致对数组的sizeof()结果判断有误。)
关于数组名语义规定以及“数组名实际上就表示一个指针(错的!!!!)”的原因 以后需要注意哈···
数组什么时候会"退化":
下面是C99中原话:
Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array
of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.
上面这句话说的很清楚了, 数组在除了3种情况外, 其他时候都要"退化"成指向首元素的指针.
比如对 char s[10] = "china";
这3中例外情况是:
(1) sizeof(s)
(2) &s;
(3) 用来初始化s的"china";
除了上述3种情况外,s都会退化成&s[0], 这就是数组变量的操作方式。
下面分析前面的那个程序:
#include <stdio.h>
#include <stdlib.h> void func(int a[][3])//数组名退化为一个普通的指针int* (*a)[3],所以a就是一个普通的指针,是一个数组指针。
{
printf("%p\n", a);
printf("%p\n", a[0]);
printf("%p\n", &a); printf("%d\n", sizeof(a));//a是一个数组指针,sizeof当然是一个指针的大小4
printf("%d\n", sizeof(a[0]));//数组指针a有2个元素,因为int a[2][3],每个元素都是一个int*,这个int*的a[0]是数组名,它是内层的,并没有退化 printf("%d\n", a[1][2]);
}
int main()
{
int a[2][3] = {{1,2,3},{4,5,6}}; printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a[0])); int (*p)[3] = a; printf("%d\n", sizeof(p));//p是一个数组指针,它是个指针,所以为4
printf("%d\n", sizeof(p[0]));//p[0]相当于*(p+0)也就是*p,p指向a[0],所以*p就是a[0] func(a); system("pause"); return 0;
}
浅谈C中的指针和数组(六)的更多相关文章
- 浅谈C中的指针和数组(一)
本文转载地址:http://www.cnblogs.com/dolphin0520/archive/2011/11/09/2242138.html 在原文的基础上加入自己的想法作为修改. 指针是C/C ...
- 浅谈C中的指针和数组(五)
前面写了一些C指针和数组的一些知识,但是还有一些很重要的知识没有交代,这里做一个补充. 首先看一下,普通变量(指针也是变量)和数组名查看地址的方式是不同的. 查看数组变量的地址,不需要使用 & ...
- 浅谈C中的指针和数组(二)
原文转载地址:http://see.xidian.edu.cn/cpp/html/475.html 在原文的基础上增加自己的想法作为修改 很多初学者弄不清指针和数组到底有什么样的关系.我现在就告诉你: ...
- 浅谈C中的指针和数组(三)
上一个博客我们得到了一个结论: 指针和数组根本就是两个完全不一样的东西.只是它们都可以“以指针形式”或“以下标形式”进行访问.一个是完全的匿名访问,一个是典型的具名+匿名访问.一定要注意的是这个“以X ...
- 浅谈C中的指针和数组(四)
原文转载地址:http://see.xidian.edu.cn/cpp/html/476.html 在原文的基础上增加自己的思想作为自己的修改 指针数组和数组指针的内存布局 初学者总是分不出指针数组与 ...
- 浅谈C中的指针和数组(七)
现在到揭露数组名本质的时候了,先给出三个结论: (1)数组名的内涵在于其指代实体是一种数据结构,这种数据结构就是数组: (2)数组名的外延在于其可以转换为指向其指代实体的指针,而且是一个指针常量: ( ...
- 浅谈C语言 extern 指针与数组
/* * d.c * * Created on: Nov 15, 2011 * Author: root */ #include "apue.h" int a[] = {3,2}; ...
- 转: 浅谈C/C++中的指针和数组(二)
转自:http://www.cnblogs.com/dolphin0520/archive/2011/11/09/2242419.html 浅谈C/C++中的指针和数组(二) 前面已经讨论了指针和数组 ...
- 转:浅谈C/C++中的指针和数组(一)
再次读的时候实践了一下代码,结果和原文不一致 error C2372: 'p' : redefinition; different types of indirection 不同类型的间接寻址 /// ...
随机推荐
- Apple Swift学习资料汇总
今年的苹果开发者大会(WWDC)上,公布了ios8的几个新特性,其中包括引入了群聊功能,支持第三方输入法等功能.但更让开发者感兴趣的莫过于Swift语言的发布了. Swift是apple自创的一门转为 ...
- ORACLE Recyclebin管理及flashback recyclebin中的对象
Flashback用于恢复用户误删除的对象(包括表,索引等), 不支持sys用户. system表空间下的对象,也不能从回收站里拿到.故使用SYS 或者SYSTEM用户登陆时, show recycl ...
- asp.net 总结
asp.net 是服务器段控件,运行是返回一个客户端html 页面给服务器
- VS2012 黑色护眼主题
在黑色主题基础上,更改了字体 Ms Comic Sans 字号也增大了 附件中有两个 一个是原版主题下载自https://studiostyl.es/ 第二个是如下改完后的主题 vssettings. ...
- iOS开发那些事儿(五)Objective-C浅拷贝与深拷贝
浅拷贝:copy操作出来的对象指针直接指向模板的地址.即两个对象公用一块内存地址 #import <Foundation/Foundation.h> int main(int argc, ...
- TextField的所有属性和方法(转)
转自:http://tsyouaschen.iteye.com/blog/600255 表一 TextField 对象的方法 方法 说明TextField.addListener 加入接收触发事件如文 ...
- jQuery 动态绑定的点击事件
$(function () { , $_div = $('#test'); $('input[name=addbtn]').on('click', function () { $_div.append ...
- JavaScript判断IE各版本完美解决方案
解决方案 IE知道自身毛病很多,于是提供的一套官方的HTML hack方式: <!--[if IE]> // 全部IE版本可见 <![endif]--> <!--[if ...
- python-md5加密
python实现:md5_hash.py #-*- coding: UTF-8 -*- ' __date__ = '2016/4/11' from Tkinter import * import ha ...
- java小型科学计算器
/** * 1.先转换为逆波兰顺序 * 数字直接存入list,符号压入栈中,但是如果栈底元素不大于该运算符的运算顺序,则将栈底pop,直到大于栈底运算符为止,再压入栈中, * 最后将运算符依次全部po ...