浅谈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 不同类型的间接寻址 /// ...
随机推荐
- 自动工作负载库(Automatic Workload Repository,AWR)
自动工作负载库(Automatic Workload Repository,AWR)AWR的由来: 10g之前的oracle:用户的连接将产生会话,当前会话记录保存在v$session中:处于等 ...
- Flash Recovery Area 的备份
Flash Recovery Area 的备份 备份命令是Flash recovery Area,该命令是Oracle 10g以后才有的.10g引进了flash recovery area,同时在rm ...
- C语言中两个相等的char值比较 结果为false
unsigned char appendChar1[] = {0xD3, 0xD0, 0xCF, 0xDE, 0xB9, 0xAB, 0xCB, 0xBE}; char appendChar2[] = ...
- JQuery Ajax Options
参数名 类型 描述 url String (默认: 当前页地址) 发送请求的地址. type String (默认: "GET") 请求方式 ("POST" 或 ...
- JavaScript 面向对象思想 贪吃蛇游戏
js代码: 游戏的对象 ,食物,蛇 ,游戏控制思路如下 (完整代码在https://github.com/774044859yf/ObjectSnakeGame下载) var snake = { aS ...
- Spring-----3、Spring的核心机制(依赖注入)
转载自:http://blog.csdn.net/hekewangzi/article/details/41345237
- mysql5.7慢查询开启配置
1.问题 当然又被度娘(我冤枉)坑了噻,网友说配置文件写下面三行: log-slow-queries=D:\Program Files\mysql-5.7.11-winx64\data\low.log ...
- python2.X和python3.X在同一平台下的切换技巧
python2.X和python3.X在同一平台下的切换技巧 最近在自己的电脑上同时安装了python2.7.11和python3.5.1 在网上搜了一些答案,主要还是参照<learning p ...
- secedit
secedit /export /cfg mytemplate.inf /log mylog.txt http://www.oracle-base.com/dba/script.php?categor ...
- KEIL MDK环境下uCOS-II在LPC17xx上的移植实例
1. 知识准备 要想对ucos-ii的移植有较深的理解,需要两方面知识: (1)目标芯片,这里是lpc17xx系列芯片,它们都是基于ARMv7 Cortex-M3内核,所以这一类芯片的ucos-ii移 ...