浅谈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 不同类型的间接寻址 /// ...
随机推荐
- IE6、7下获得offset值跟其他浏览器不一样问题
大家都知道,offset是元素的位置坐标,那位置坐标又和文档流有关系.如果position默认不设置的话,其值是static.static是个什么东东呢?下面我详细介绍一下: 语法: position ...
- ubuntu下nvm,node以及npm的安装与使用
一:安装nvm 首先下载nvm,这里我们需要使用git,如果没有安装git,可以使用 sudo apt-get install git 来安装 git clone https://github.com ...
- TcpClient
public class TcpClientSession { protected TcpClient Client { get; set; } /// <summary> /// 远程地 ...
- DBI && MySQL lock
DBI: url set isolation to dirty read my $npmdb_dbh = DBI->connect("DBI:ODBC:npmdb", &qu ...
- MySql中游标使用总是多循环一次的解决方法
CREATE DEFINER = 'root'@'%' PROCEDURE deyestest.procedure2() BEGIN DECLARE v_id INT; DECLARE v_userN ...
- 解决chrome下上传文件 返回值带 <pre style="word-wrap:break-word;white-space:prewrap;"></pre>
解决办法:后台 response.setContentType("text/html");
- model、dao、 service 和Comtroll层的关系
首先这是现在最基本的分层方式,结合了SSH架构.modle层就是对应的数据库表的实体类.Dao层是使用了Hibernate连接数据库.操作数据库(增删改查).Service层:引用对应的Dao数据库操 ...
- Flink Program Guide (8) -- Working with State :Fault Tolerance(DataStream API编程指导 -- For Java)
Working with State 本文翻译自Streaming Guide/ Fault Tolerance / Working with State ---------------------- ...
- python-凯撒密码
凯撒密码 简介:凯撒密码(Caesar)是最早的代换密码,对称密码的一种 算法:将每个字母用字母表中它之后的第k(称作位移值)个字母替代 代码: #-*-coding:utf-8-*- __autho ...
- 2014第11周四Eclipse开发问题记
今天开发中eclipse工具使用上又学到几点: 1.去除代码空行:在Find输入框中输入:^\s*\n然后替换为空即可: 2.eclipse插件的加载:对于单一个jar文件的插件,直接放在plugin ...