(二) 数据对象
所以我们先来说说这个数据对象,数据对象大概包含一下特征.
(1) 属性
数据对象包含哪些属性?
名称
值
类型
长度(尺寸)
内存占用
还有吗?.
我这里不按照数据对象是常量,变量还是数据类型(typedef 关键词定义 pascal 中用 type定义,数据类型暂不考虑,她只有名称和类型,像是类型的代号),我也搞不清常量和变量的确切定义(依据编译后机器语言的处理形式?比如说常量不占用内存,比方立即数,立即数是编码在代码中的,浮点数又有区别,立即数故名思意,当时有效,过后无效了,也就是没有生存期,作用域也是一个点),其实似乎搞清楚也没有什么太大用处.通常我们都是通过对象(数据对象简称对象吧)名称访问对象的值,但是立即数没有名称,还有一种比如通过手动分配内存(如malloc 函数)的变量也没有名称,需要通过间接引用访问其值.
对象的值是根据对象类型做出的解释,当然一般值都有内存占用,内存占用的空间就是其类型的长度(尺寸),当然实际尺寸和宿主有关,我们不用考虑,姑且认为char占用一个字节(8bit).不同长度(尺寸)的对象类型肯定不同,相同长度(尺寸)的对象类型也可能不同,比如 long(认为是4个字节) 和float.
C语言基本数据类型非常简单(其实,计算机的数据原本就简单,都是二进制表示的数),依据计算机处理的不同就两种类型 整型和浮点型!
整型根据长度和有无符号表示的不同分为一下几种类型
unsigned char
8位
无符号char
unsigned short int
一般位16位
无符号 int
unsigned long int
一般为32位
无符号 long
unsigned int
根据计算机字长,32位机是32位
无符号 int
signed char
8位
符号char
signed short int
一般位16位
符号 int
signed long int
一般为32位
符号 long
signed int
根据计算机字长,32位机是32位
符号 int
long 和short 修饰int时 int可以省略
另外c99支持long long 用来表示64位整型.(其实在64位机器上int就是64位,c设计者为了编译器的效率没有规定各种类型必须的长度,只是说short不长于int,int不长于long,所以有可能short=int=long,由编译器决定长度对程序性能来讲是有很大优势的)
无符号整型比较简单就是2的n次幂 -1 最大可以表示2的n次幂个数(n是位长)
有符号整型采用二进制补码格式表示!
浮点类型 采用IEEE格式
根据长度分为 float (32位) double (64位) 还有IA32CPU体系上的long double (80位)
由基本数据类型可以组成复合数据类型,比如
数组:有若干个相同数据类型组成(基本数据类型或复合数据类型,比如二维数组其实是两个一维数组组成)
记录

借用pascal的称呼,因为”结构”有数据结构的意思)有若干个不同数据类型.
联合:和记录一样只是组成元素基于相同的偏移开始(其实知道内存结构,数据类型就跟清楚了)
枚举 只是一种整型常量的表示方式,不是真正的类型.
最后一个有意思的类型是指针(pointer),指针是一种对内存占用(上面说过)的间接引用.其实指针不能算作一种数据类型(函数指针是引用函数的入口地址,先不讨论),指针其实就是汇编语言中的间接寻址. 看看一个指针的定义:
int *pSize;
所有指针变量占用的内存长度都一样(一般位字长,32体系中是32位),指针变量的值是一个整型(尺寸是字长),她表示一个地址,而这个地址存放的是一个数据对象.所以我们说指针的类型其实是地址存放数据对象的类型,我们在定义时候说明的,比如上面说明pSize变量中存放的地址(pSize的值)处为一个int型的数据对象.如此而已.没有类型的指针只能传递,不能操作的比如void *;
指针的设计是c语言的灵魂,但也是把双刃剑!除了指针存放数据对象的地址这一特性,还有就是编译器提供的指针运算为指针的使用提供了广泛的用途!
先看一个例子:
比如++运算对于指针来讲是什么意思呢? 对于一个整型
int a = 10;
int b=a++; //b =11
a++表达式求值结果还是一个整型的数据对象.
上面的pSize 一样
int *pNext=pSize++;
pSize++表达式求值结果还是一个整型指针(地址),但这个地址是多少呢?
c语言是这样定的:pNext的地址是pSize地址+int数据类型的长度(比如4个字节,记住,字节是cpu处理地址的原子单位)
[图片]
对于数组
char str[]=”hello,world”;
str是一个char数组长度初始化为”hello,world”的长度12,字符11一个’\ 0’.
char *pStr = &str[0];
利用指针运算,比如 *(pStr+4) 和 str[4] 是一样的!
pStr+4意味着第0个字符地址+4个字节后的地址,这个地址上的值(类型是char已经说明).
简单总结一下指针的运算
a 指针与相同类型指针的赋值和比较(一般指针在同一个数组中比较有意义).
b 将指针赋值为0,以及指针与0 的比较运算(将指针赋值为空,以及判断指针是否为空)
c 指针与整数之间的加减运算(相当于地址向后或向前移动sizeof(指针类型)字节).
d 两个指针的减法(一般在同一个数组中有意义)
打住….
(2) 作用域
其实应该先说生存期.不过这两个概念在任何语言中都是有的.作用域其实是一个编译时期的概念. 作用域与数据对象的声明有关系:
先说说代码块,作用域的空间(生存期是时间特性,哈哈难以避免的时空).
c语言的代码块(为了简单不考虑#include情况了,其实#include是在预编译时将引用的代码展开在文件处,所以按源文件考虑是一样的.一般c语言的声明在.h文件中,后来的语言为了避免引用的命名冲突,使用了namespace).
一个源文件是最大的代码块(其实整个程序是最大的代码块),包含在里面的函数是一层代码块,函数内部包含
{ }的语句也是代码块. 小的代码块总是被大的代码块包含.代码块中包含的代码块我们暂且成为子代码块.
C语言(后来的标准)允许在任何位置声明变量(数据对象).
理解了代码块就理解作用域了.
作用域范围就是从声明开始之后的代码块中,包含子代码块.这里说的是声明,不是定义.
函数的局部变量定义就是声明.声明外部变量用关键字extern
比如:
void print(void)
int main(int argc,char *argv[])
{
if (argc>2)
{
extern a;
printf("%d\n",a);
}
//int b = a; //这里不属于a的作用域
print();
return 0;
}
int a =100; //定义在这里 这以后默认声明了 ,所以下面的子代码块中都是可见的
void print(void)
{
printf("%d\n",a);
}
如果是定义在另外一个文件中的外部变量(哈哈,函数都是外部的),我们能不能可见呢?
先看看生存期.()
[
本帖最后由 hotplum 于 2008-2-3 22:27 编辑 ]