C语言中的 *p[2] 与 (*p)[2] 的截然不同
C语言运算符优先级表(由上至下, 优先级依次递减)
运算符 | 结合性 |
() [] -> . | 自左向右 |
! ~ ++ -- - (type) * & sizeof | 自右至左 |
* / % | 自左向右 |
+ - | 自左向右 |
<< >> | 自左向右 |
< <= > >= | 自左向右 |
== != | 自左向右 |
& | 自左向右 |
^ | 自左向右 |
| | 自左向右 |
&& | 自左向右 |
|| | 自左向右 |
?: | 自右至左 |
assignments | 自右至左 |
, | 自左向右 |
(来自C陷阱与缺陷)
对于( ) 或者 [ ] 的优先级是最高的
于是对于 *p[2] 结合的方式应该是 *(p[2]) 对于 (*p)[2] 显然结合方式是括号中的 *p 优先于 [2]
具体:
char *p[2] 表示p是一个存储指向char类型数据的指针的数组
char (*p)[2] 则表示*p是一个拥有两个char类型元素的数组,那么p则表示指向这个数组的指针
- void test(){
- char *p1[];
- char (*p2)[];
- printf("p1----%d\n", sizeof(p1));
- printf("p2----%d\n", sizeof(p2));
- return;
- }
得到的结果是
可以看到p1表示的是一个拥有两个(char *)类型的数组,一个指针占有4个字节,俩个当然是8个字节
而p2仅仅就只是一个指针,只占有4个字节
常用用途:
对于 *p[]
在main函数的参数中有使用到,其中的 char *argv[]的argv就是一个指针数组,用来存储函数调用时传进来可变个数的参数
(详细:利用 gdb 探究main(int argc, char *argv[]){} 中的char *argv[])
- int main(int argc, char *argv[])
- {
- something you want to do;
- return ;
- }
比如可以这样
- char *pp[] = {"hello", "world",};
pp[0]存储字符串"hello"的第一个字符的地址,pp[1] 存储字符串"world"的第一个字符的地址
- printf("%s\n", pp[]);
将会打印出 hello
对于 (*p)[]
无疑就是可以作为二维数组的引用
其实二维数组的本质也是一维数组,那么当我们定义一个二维数组的时候为什么不可以使用像引用一维数组的那样的指针来引用二维数组呢?
错误样例
- void arrays(){
- int nums[][] = {};
- int *pn = nums;
- }
原因就是二维数组其实就是一个成员是一维数组的一维数组,所以它的类型是应该是数组类型
而这里的pn所指的类型是int,就会出现类型不匹配的问题
正确的方式是
- void arrays(){
- int nums[][] = {};
- int (*p_nums)[] = nums;
- }
这样的p_num是指向类型为数组的指针,与nums的类型相匹配
补充:
二维数组在内存中的存储问题
示例代码
- #include <stdio.h>
- #include <stdlib.h>
- int main()
- {
- /*定义char类型便于观察地址,因为char只占一个byte*/
- char chars[][] = {{, , , }, {, , , }, {, , , },};
- printf("-------------------------------------------------------------------\n\n");
- for(int i = ; i < ; ++i){
- for(int j = ; j < ; ++j){
- printf("%5d(%d)", chars[i][j], (int)&chars[i][j]);
- }
- printf("\n");
- }
- printf("\n-------------------------------------------------------------------\n");
- printf("%d\n", sizeof(chars));
- printf("%d\n", (int)chars);
- printf("%d\n", (int)(chars + ));/*移动了4个元素,行移动*/
- printf("-------------------------------------------------------------------\n");
- printf("%d\n", sizeof(chars[]));
- /*可以看作是一维数组的第一个元素的地址 形如 一维数组中的 &array[0]*/
- printf("%d\n", (int)&chars[]);
- /*可以看作就是一维数组里的第一个元素是数组,它相当于一个数组名表示数组地址 形如 array*/
- printf("%d\n", (int)chars[]);
- printf("-------------------------------------------------------------------\n");
- return ;
- }
输出
得到的结果以及代码注释已经可以说明一些问题了,就不再重复
本节完......
C语言中的 *p[2] 与 (*p)[2] 的截然不同的更多相关文章
- JAVA语言中的修饰符
JAVA语言中的修饰符 -----------------------------------------------01--------------------------------------- ...
- Java语言中的面向对象特性总结
Java语言中的面向对象特性 (总结得不错) [课前思考] 1. 什么是对象?什么是类?什么是包?什么是接口?什么是内部类? 2. 面向对象编程的特性有哪三个?它们各自又有哪些特性? 3. 你知 ...
- python语言中的编码问题
在编程的过程当中,常常会遇到莫名其妙的乱码问题.很多人选择出了问题直接在网上找答案,把别人的例子照搬过来,这是快速解决问题的一个好办法.然而,作为一个严谨求实的开发者,如果不从源头上彻底理解乱码产生的 ...
- 在C语言中利用PCRE实现正则表达式
1. PCRE简介 2. 正则表达式定义 3. PCRE正则表达式的定义 4. PCRE的函数简介 5. 使用PCRE在C语言中实现正则表达式的解析 6. PCRE函数在C语言中的使用小例子 1. P ...
- C语言中函数声明实现的位置
在学习C语言的时候我遇到了这么个事情,因为之前先学习的C#,在C#编译器中,函数的声明位置不会影响编译的结果,但是在C语言中却发生了错误 先看一段代码: #include <stdio.h> ...
- C语言中的栈和堆
原文出处<http://blog.csdn.net/xiayufeng520/article/details/45956305#t0> 栈内存由编译器分配和释放,堆内存由程序分配和释放. ...
- 在易语言中调用MS SQL SERVER数据库存储过程方法总结
Microsoft SQL SERVER 数据库存储过程,根据其输入输出数据,笼统的可以分为以下几种情况或其组合:无输入,有一个或多个输入参数,无输出,直接返回(return)一个值,通过output ...
- C语言中结构体赋值问题的讨论
今天帮师姐调一个程序的BUG,师姐的程序中有个结构体直接赋值的语句,在我印象中结构体好像是不能直接赋值的,正如数组不能直接赋值那样,我怀疑这个地方有问题,但最后证明并不是这个问题.那么就总结一下C语言 ...
- Coursera-Getting and Cleaning Data-week4-R语言中的正则表达式以及文本处理
博客总目录:http://www.cnblogs.com/weibaar/p/4507801.html Thursday, January 29, 2015 补上第四周笔记,以及本次课程总结. 第四周 ...
随机推荐
- PostgreSQL(一)教程 -----从头开始
一.安装 自然,在你能开始使用PostgreSQL之前, 你必须安装它.PostgreSQL很有可能已经安装到你的节点上了, 因为它可能包含在你的操作系统的发布里, 或者是系统管理员已经安装了它.如果 ...
- Access与SQL Server 语法差异
序号 简述 Access语法 SqlServer语法 Oracle语法 解决方案 01 系统时间 Now(),Date() GETDATE() SYSDATE GetSysTimeStr 02 连接字 ...
- spring boot 分布式事务实现(XA方式)
关于spring boot 支持分布式事务,XA是常用的一种方式. 这里把相关的配置记下,方便以后使用. 首先配置两个不同的数据源 : 订单库.持仓库. /** * Created by zhangj ...
- 使用Arraylist将数组中元素随机均等乱序分为N个子数组
使用Arraylist将数组中元素随机均等乱序分为N个子数组 觉得有用的话,欢迎一起讨论相互学习~Follow Me 为了将数组中的元素 随机地 ,均等地, 不重复地 ,划分到N个子数组中 使用Arr ...
- Spark记录-Scala异常处理与文件I/O
Scala的异常处理类似许多其他语言(如Java).它不是以正常方式返回值,方法可以通过抛出异常来终止. 但是,Scala实际上并没有检查异常. 当您想要处理异常时,要像Java一样使用try {.. ...
- 前端 ajax 改写登录界面
SSM 整合项目开发到一个阶段,想慢慢地把前台框架等技术引入进来 突然碰到一个困惑好久的问题: ajax 替换原本 form 表单 post 提交登录: 一直 404 错误,心塞.... 最后发现原来 ...
- scala 基础到高阶
本文打算对这小段时间学习 scala 以及 spark 编程技术做个小结,一来温故而知新,而来为以后查阅方便 spark scala 入门小例子 文本文件 UserPurchaseHistory.c ...
- 从数据库存储,文件结构谈到B树,散列
昨天俱乐部内部办了一个讲座,关于常规数据库系统实现,听了之后有点混乱,于是花了很多时间特地查了一些资料,基本上自己感觉自己是明白了.特地写下来. 文章开头说明三点, 第一点,本文针对常规数据库,是为了 ...
- [原]Android Fragment 入门介绍
Fragment Fragment 产生,优点,用途,使用方法简介 1 Fragmeng简介 自从Android 3.0中引入fragments 的概念,根据词海的翻译可以译为:碎片.片段.其上的是为 ...
- 如何使用 grunt
1>. 首先要有nodejs环境, 至少0.8.0版本: 2>. 转到 项目文件夹下: >npm install –g grunt-cli >npm init #生成一个基本的 ...