转至:http://my.oschina.net/ypimgt/blog/108265

 
Technorati 标签:  指针, typedef, const, define

我们都知道,至少听说过指针对于C语言中的重要意义,但是在使用指针时却常常让我们痛不欲生,这里有几个在声明指针有关的变量时易错的地方。

1. int* 和 int  * (注意空格的位置)

对于单变量声明,即一条语句中只声明一个指针变量的情况,没有区别;原因是C语言允许形式的自由性。即以下两种声明方式效果相同。

int  *a;
int* a;

对于一条语句中声明多个指针变量的情况,有很大区别。

int*  a, b,c;

对于这条语句,常会造成我们的误解:认为声明了三个整型指针。但是正解是:只有a是整型指针,b和c都是普通的整数。 
这里的星号“*”号只是声明变量a的一部分,以上的变量声明相当于:

int *a;
int b;
int c;

如果希望在一条语句中声明多个整型指针,正确的方式应该是:

int *a, *b, *c;

2.  typedef 和 #define 在创建类型别名时的区别

在C语言中实现创建类型别名的方法有两种:一种是使用typedef;一种是使用#define。使用方法也类似。

typedef int NEW_INT_TYPE1; /*int在前*/
NEW_INT_TYPE1 a1 = 1;
#define NEW_INT_TYPE2 int /*int在后*/
NEW_INT_TYPE2 a2 = 2; printf("%d /n",a1);
printf("%d /n",a2);

但是如果需要创建新类型名时,我们只应该使用typedef,而不是#define。因为#define仅仅是在编译的时候做简单的替换工作,所以在处理一些问题上会有缺陷。

int m=2;
typedef int* NEW_INT_TYPE3; /*int在前*/
NEW_INT_TYPE3 a3, a4;
a3 = &m; /*指针赋值*/
a4 = &m; /*指针赋值*/
#define NEW_INT_TYPE4 int* /*int在后*/
NEW_INT_TYPE4 a5, a6=6;
a5 = &m; /*指针赋值*/
printf("%d /n",*a3);
printf("%d /n",*a4);
printf("%d /n",*a5);
printf("%d /n",a6); /*运行结果:
2
2
2
6*/

分析:a3和a4是整型指针,a5是整型指针,但是a6只是整型(只要记住#define 仅仅是做替换操作,将NEW_INT_TYPE4替换为int*,而int* a5, a6; 的结果是“a5是整型指针,a6是整数”);

3. “常量指针”和”指向常量的指针”

对于常量变量:int const a 和const int a
效果相同;都是声明一个整型的变量a,且a是常量,其值不能改变(由于其值不能改变,其赋值方式只有两种:一种是声明时初始化,如int const
a=1; 一种是其作为函数的形式参数,函数被调用时用实参来初始化)。

对于含有指针时,根据声明时const和星号"*" 的位置,有三种形式:

形式

名称

说明

分析方法

int const *p 指向常量的指针 能修改指针本身的值,但是不能修改其指向的值 从变量标识符开始(即从右向左),①*p指向一个整数;②const修饰”*p”,表示*p是一个常量,即p指向的值是一个常量。所以,不可以修改”*p”,即不可修改p指向的值。
const int *p 指向常量的指针 同上 同上
int * const p 指针常量 能修改其指向的整型的值,但是不能修改指针本身的值 从变量标识符开始(即从右向左),const修饰p,表示p是常量,即不能修改p本身,但p指向的值可以修改。

总结,区分这两种类型的顺序是:从右向左看,一步一步的确定。 
       衍生的更为特殊的指针:指向常量的常量指针,声明方式是 int const * const p; 对于它,“指针本身的值”和“指向的值”都不能修改。
       注意:有常量声明的变量只有两种赋值方式;一种是在声明时直接赋值,如int m; int * const p = &m;
另一种方法针对在函数中声明的形式参数,在函数被调用时被赋值,例如:当是不需要修改数组的元素时,形式参数使用int const
a[],即a指向的内容不能修改。

void firstTest(){
int m = 2;
int * const p = &m;/*指针p 是常量指针,要在声明时赋值*/
/*不能写为 int * const p; p = &m;*/ printf("%d /n",*p);
*p = 5; /*可以改变指针p 指向的值*/
printf("%d /n",*p);
getchar();
p=&m; /*编译报错,因为不能改变指针p本身 的值,*/
}
void secondTest(){
int m = 2;
int n = 3;
int const *p; /*指向常量的指针*/
p = &m;
/*也可以写为 int const *p = &m; */
printf("%d /n",*p);
p = &n; /*可以改变指针p本身的值*/
printf("%d /n", *p);
*p = 3;/* 编译报错,不能修改它指向的值。虽然这里*p的值本来就是2*/
}

*C语言有关指针的变量声明中的几个易错点的更多相关文章

  1. Go语言规格说明书 之 变量声明(Variable/Short variable declarations)

    go version go1.11 windows/amd64 本文为阅读Go语言中文官网的规则说明书(https://golang.google.cn/ref/spec)而做的笔记,完整的介绍Go语 ...

  2. scala学习笔记:变量声明中的模式

    先看个正常的写法: scala> val x = 1 x: Int = 1 体会一下元组的写法: scala> val (x,y,z)=(1,2,3) x: Int = 1 y: Int ...

  3. go语言入门教程:基本语法之变量声明及注意事项

    一.变量的使用 1.1 什么是变量 变量是为存储特定类型的值而提供给内存位置的名称.在go中声明变量有多种语法. 所以变量的本质就是一小块内存,用于存储数据,在程序运行过程中数值可以改变 1.2 声明 ...

  4. C语言讲义——指针(pointer)

    指针是C语言最重要的特性之一, 也是最容易被误解的特性之一. 现代计算机把内存分割为字节(Byte), 每个字节都有唯一的地址(Address), 如果内存中有n个字节,可以把地址看做0~n-1的数. ...

  5. C语言全局变量的定义与声明

    C语言中全局变量的定义与声明困扰着许多C语言初学者.本文讲述了全局变量定义与声明的用法,而且本为也将阐述这种用法的内在原理.我们先从两个错误例子引入,以下两个例程都在vc6.0平台上测试. 两种错误例 ...

  6. 浅谈C语言变量声明的解析

    C语言本身提供了一种不甚明确的变量声明方式——基于使用的声明,如int *a,本质上是声明了*a的类型为int,所以得到了a的类型为指向int的指针.对于简单类型,这样声明并不会对代码产生多大的阅读障 ...

  7. C语言指针与数组的定义与声明易错分析

    部分摘自<C语言深度解剖> 1.定义为数组,声明为指针 在文件1中定义: char a[100]; 在文件2中声明: extern char *a; //这样是错误的 这里的extern告 ...

  8. 【C语言探索之旅】 第一部分第四课第二章:变量的世界之变量声明

    内容简介 1.课程大纲 2.第一部分第四课第二章:变量的世界之变量声明 3.第一部分第四课第三章预告:变量的世界之显示变量内容 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布 ...

  9. C语言变量声明内存分配

    转载: C语言变量声明内存分配   一个由c/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)— 程序运行时由编译器自动分配,存放函数的参数值,局部变量的值等.其操作方式类似于数据结 ...

随机推荐

  1. [PHP] PHP源码中的条件编译定义

    根据不同情况编译不同代码.产生不同目标文件的机制,称为条件编译有这些预处理命令:#if.#elif.#else #endif :#ifdef #else #endif PHP源码: #ifdef SE ...

  2. Machine Learning - week 4 - 编程练习

    = X' * (h - y) LrCostFunction 与上一周的有什么不同? 与 week3 的 costFunctionReg 是一样的.Week3 中参考答案没有排除 theta 第一行,但 ...

  3. python制作wifi破解(跑字典(单线程))

    很鸡巴简单,接上一篇文章 import pywifi import sys import time from pywifi import const def test_wifi_connect(pas ...

  4. 浏览器的统一指针事件:Pointer Event

    在早期的浏览器,输入的事件其实相对单纯,只有考虑到鼠标和键盘两种:而当时的鼠标事件,其实就是 click.mousedown.mouseup 等等的事件.但是当手机.平板开始流行时候,再移动装置上的主 ...

  5. 程序员之殇 —— (The Beginning of the End)噩梦、崩坏

    Look at all those faces out there (当我环视周遭的一张张脸孔) We are so different(我们是如此的不同) But we have one thing ...

  6. Element类型知识大全

    Element类型 除了Document类型之外,Element类型就要算是Web编程中最常用的类型了.Element类型用于表现XML或HTML元素,提供了对元素标签名.子节点及特性的访问.   要 ...

  7. Spring MVC集成Swagger

    什么是Swagger? 大部分 Web 应用程序都支持 RESTful API,但不同于 SOAP API——REST API 依赖于 HTTP 方法,缺少与 Web 服务描述语言(Web Servi ...

  8. 在Android studio模拟器中运行apk文件

    菜鸟级玩家比看文. win平台下下载的apk文件,怎么能模拟运行出来. 首先得安装Android SDK,不会的自行百度一下. 接下来,打开AVD模拟器,自己创建一个模拟器(过程自己实践) 然后,将你 ...

  9. 新版Azure Automation Account 浅析(二) --- 更新Powershell模块和创建Runbook

    前篇我们讲了怎样创建一个自动化账户以及创建时候"Run As Account"选项背后的奥秘.这一篇针对在Azure自动化账户中使用Powershell Runbook的用户讲一下 ...

  10. SQL中MAX()

    列column_name中的数据可以是数值.字符串或是日期时间数据类型.