1.auto
编译器在默认的缺省情况下,所有变量都是auto.
2.register
2-1.这个关键字的作用:
请求编译器尽可能的将变量存在 CPU 内部寄存器中而不是通过内存寻址访问以提高效率.
其访问速度比内存还要快得多.
2-2.被这个关键字修饰的特性:
于或等于整型的长度;
2-2-2.register 变量可能不存放在内存中. 所以不能用取址运算符“&"来获取 register 变量的地址.
3.static
在C语言中这个关键字主要有两个作用.
3-1.修饰变量:
变量又分为局部和全局变量,被static修饰的变量特性如下:
3-1-1:存放在内存的静态区域;
3-1-2:作用域是从定义之处开始,到文件结尾处结束,在定义之处前面的那些代码行也不能使用它,想要使用就得在前面再加 extern;
3-1-3:静态局部变量,在函数体里面定义的,就只能在这个函数里用了,同一个文档中的其他函数也用不了;3-2.修饰函数:
被static修饰的函数,函数的作用域仅局限于本文件(所以又称内部函数).
4.数据类型
short、int、long、char、float、double 这六个关键字代表 C 语言里的六种基本数据类型.
4-1.变量的命名规则:
规则一:命名应当直观且可以拼读,可望文知意,便于记忆和阅读;
规则二:当标识符由多个词组成时,每个词的第一个字母大写,其余全部小写;
如:int CurrentVal;
规则三:尽量避免名字中出现数字编号,如 Value1,Value2 等;
规则四:对在多个文件之间共同使用的全局变量或函数要加范围限定符(建议使用模块名
(缩写)作为范围限定符).(GUI_ ,etc);
规则五:一个函数名禁止被用于其它之处.意指函数名和变量名同一个名字;
规则六:所有宏定义、枚举常数、只读变量全用大写字母命名,用下划线分割单词;
规则七:一般来说习惯上用 n,m,i,j,k 等表示 int 类型的变量;c,ch 等表示字符类型变量;a 等表
示数组;p 等表示指针.当然这仅仅是一般习惯,除了 i,j,k 等可以用来表示循环变量外,别
的字符变量名尽量不要使用;
规则八:定义变量的同时千万千万别忘了初始化.定义变量时编译器并不一定清空了
这块内存,它的值可能是无效的数据.
5.sizeof
sizeof 的作用是算出一个内存存在对象占用内存的大小.是关键字不是函数.例如下面的语句是编译出错的:
sizeof int;
因为编译器没办法知道这两个关键字放一起(typedef除外)是什么意思.
由于sizeof工作编译中比较常用,下面给出一个示例来解析sizeof的各种用法:
sizeof.c
#include
#include
void func(int b[100])
{
printf("sizeof(b) = %d\n",sizeof(b));
}
int main(int argc,char **argv)
{
int *p = NULL;
int a[100];
printf("sizeof(p) = %d\n",sizeof(p));
printf("sizeof(*p) = %d\n",sizeof(*p));
printf("sizeof(a) = %d\n",sizeof(a));
printf("sizeof(a[100]) = %d\n",sizeof(a[100]));
printf("sizeof(&a) = %d\n",sizeof(&a));
printf("sizeof(&a[0]) = %d\n",sizeof(&a[0]));
func(a);
return 0;
}
输出结果如下:
root@seven-laptop:~/learn/C_Program# ./sizeof
sizeof(p) = 4
sizeof(*p) = 4
sizeof(a) = 400
sizeof(a[100]) = 4
sizeof(&a) = 4
sizeof(&a[0]) = 4
sizeof(b) = 4
root@seven-laptop:~/learn/C_Program#
注:想掌握sizeof的用法,深刻理解其定义是王道:sizeof的作用是算出一个内存存在对象占用内存的大小.一定
要明确"内存存在对象"是什么?例如把上述sizeof.c中把所有int 数据类型换成char.代码如下:
sizeof.c
#include
#include
void func(char b[100])
{
printf("sizeof(b) = %d\n",sizeof(b));
}
int main(int argc,char **argv)
{
char *p = NULL;
char a[100];
printf("sizeof(p) = %d\n",sizeof(p));
printf("sizeof(*p) = %d\n",sizeof(*p));
printf("sizeof(a) = %d\n",sizeof(a));
printf("sizeof(a[100]) = %d\n",sizeof(a[100]));
printf("sizeof(&a) = %d\n",sizeof(&a));
printf("sizeof(&a[0]) = %d\n",sizeof(&a[0]));
func(a);
return 0;
}
输出结果如下:
root@seven-laptop:~/learn/C_Program# ./sizeof
sizeof(p) = 4
sizeof(*p) = 1
sizeof(a) = 100
sizeof(a[100]) = 1
sizeof(&a) = 4
sizeof(&a[0]) = 4
sizeof(b) = 4
root@seven-laptop:~/learn/C_Program# vim sizeof.c
对比输出结果的不同之外有:
sizeof(*p)、sizeof(a)、sizeof(a[100])三个.只要明确sizeof处理的"内存存在对象"就很好理解为什么输出的结果不一样:
*p分别指向int、char;
a分别代表100个整型的数组、100个字符型的数组;
void func(int b[100])是一个比较奇葩的例子.其参数int b[100]可以分开下面两步理解:
首先是一个整型数组(这里可以理解成指针);其次这个数组是有要求的,数组大小是100个元素.
6.signed 和unsigned:
计算机内部都是以补码来表示存储.
正数的补码是它本身;
负数的补码是它的符号位外的所有位取反再加1.例如:
-7的补码是:11111001;
下面给出一个示例:
include
#include
#include
int main(int argc,char **argv)
{
char a[1000];
int i;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%d\n",strlen(a));
return 0;
}
输出结果:255.
下面解释这个结果的由来:
按照负数补码的规则,可以知道-1 的补码为 0xff,-2 的补码为 0xfe......当 i 的值为 127时,
a[127]的值为-128,而-128 是 char 类型数据能表示的最小的负数.当 i 继续增加,a[128]
的值肯定不能是-129.因为这时候发生了溢出,-129 需要 9 位才能存储下来,而 char 类型
数据只有 8 位,所以最高位被丢弃.剩下的 8 位是原来 9 位补码的低 8 位的值,即 0x7f.
当 i 继续增加到 255 的时候,-256 的补码的低 8 位为 0。然后当 i 增加到 256 时,-257 的
补码的低 8 位全为 1,即低八位的补码为 0xff,如此又开始一轮新的循环......
按照上面的分析,a[0]到 a[254]里面的值都不为 0,而 a[255]的值为 0.strlen 函数是计
算字符串长度的,并不包含字符串最后的‘\0’.而判断一个字符串是否结束的标志就是看
是否遇到‘\0’.如果遇到‘\0’.则认为本字符串结束.
示例二:
include
#include
#include
int main(int argc,char **argv)
{
unsigned i ;
for (i=9;i>=0;i--)
{
printf("%u\n",i);
}
return 0;
}
这个程序其实是个死循环.因为i是无符号数据类型.当i=0时条件满足,继续执行,随即变成-1.
但是i是一个无符号数据类型,当其等于-1时,在内存在以补码存储时,变成了一个很大的正数.
因此,"i>=0"依然被满足.
7.bool类型
bool类型定义的变量只有两个逻辑值:要么是"真",要么是"假".实际编程中最常用的就是用bool
类型的变量作为if判断条件.实际的使用最规范的习惯是用取反运算符“!”,这样更能表现其逻辑值
的意义.下面给出示例:
#include
#include
#include
#include
int main(int argc,char **argv)
{
bool bTestFlag = false;
if(!bTestFlag)
{
printf("The Really World Is False!\n");
}
return 0;
}
输出结果:
The Really World Is False!
[注:]GNU C中要使用bool类型,需要包含头文件stdbool.h.
8.float
float类型变量和double类型变量是有精度要求的.因此这种类型比较时要特别注意.
下面给出一个示例:
#include
#include
int main(int argc,char **argv)
{
float fTestVal = 0.001;
printf("fTestVal = %f\n",fTestVal);
if(0.001 == fTestVal)
{
printf("fTestVal = 0.001\n");
}
else
{
printf("fTestVal != 0.001\n");
}
return 0;
}
输出结果:
fTestVal = 0.001000
fTestVal != 0.001
虽然二者的值在我们日常的数学知识里面是一样,但是在编程里面却不是那么一回事.
另外还要注意一点的就是:不要在很大的浮点数和很小的浮点数之间进行运算.
9.空指针比较的规范写法:
if(NULL == p); if(NULL != p);
这样可以避免手误出现少写一个"="号的情况.例如上述的if(NULL==p)如果是写成if(p==NULL)它们
的效果是一样的.但是后者很容易手误写成了if(p=NULL).编译器是不会报错的.
10.空执行语句:
有时候我们需要在满足一定的条件下执行一个空语句.如下:
if(!bTestVal);
其实际等价于:
if(!bTestVal)
{
;
}
if(!bTestVal)由于一时手误很有可能导致后面多了个分号.而导致程序不在我们的预期内执行.类似这样的写法
也很容易让人疑惑if(!bTestVal);.到底if后面的分号是故意的还是无意的.很让人迷惑.如果确实需要用到空语句.建
议写法如下:
if()
{
;
}
或者:
if()NULL;
10.switch case组合
case后面只能是常量,可以是整型或字符型的常量,也可以是常量表达式.
11.do、while、for关键字
11-1.break和continue的区别:
break:表示终结本层循环,contiune表示结束本轮循环.
示例:
#include
#include
int main(int argc,char **argv)
{
int i = 0,j = 0;
for(j = 0; j < 3; ++j)
{
for(i = 0; i < 5; ++i)
{
if(3 == i)
{
break;
// continue;
}
printf("i = %d\t",i);
}
printf("\n");
printf("j = %d\t",j);
}
printf("\n");
return 0;
}
输出结果:
i = 0 i = 1 i = 2
j = 0 i = 0 i = 1 i = 2
j = 1 i = 0 i = 1 i = 2
j = 2
示例:
#include
#include
int main(int argc,char **argv)
{
int i = 0,j = 0;
for(j = 0; j < 3; ++j)
{
for(i = 0; i < 5; ++i)
{
if(3 == i)
{
// break;
continue;
}
printf("i = %d\t",i);
}
printf("\n");
printf("j = %d\t",j);
}
printf("\n");
return 0;
}
输出结果:
i = 0 i = 1 i = 2 i = 4
j = 0 i = 0 i = 1 i = 2 i = 4
j = 1 i = 0 i = 1 i = 2 i = 4
j = 2
可见,break是跳出本层循环;而continue是结束本轮循环重新继续下一轮循环.
11-2:在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放
在最外层,以减少 CPU 跨切循环层的次数.
11-3:建议 for 语句的循环控制变量的取值采用“半开半闭区间"写法.
"半开半闭区间"的方式写法如下:
for (n = 0; n < 10; n++)
11-4:goto关键字
尽可能不要用goto关键字.
11-5:void关键字
11-5-1.有容奶大
在LINUX内核中,有时我们传入的数据是不定的,比如有可能是一个结构体的地址、有可能是一个int型
变量的地址.这时候我们定义的函数参数可以定义为void*类型.再根据具体的传入指针类型再把相应的数据
给拿出来操作.下面给出一个示例:
#include
#include
typedef struct __sTestVal
{
const char *name;
int age;
}sTestVal,*psTestVal;
void func_test(void *p)
{
psTestVal q;
q = p;
printf("q->name = %s\n",q->name);
printf("q->age = %d\n",q->age);
}
int main(int argc,char **argv)
{
sTestVal student;
student.name = "Seven";
student.age = 24;
func_test(&student);
return 0;
}
输出结果:
q->name = Seven
q->age = 24
简析:
上述代码中func_test()的参数是void*类型.我们可以根据传进来的具体类型再提取数据出来处理.
11-5-2:如果函数没有返回值一定要加void声明,不能在函数前面什么都没有.比如:
good_luck();
要声明成:
void good_luck();
如果一个函数声明前面什么都没有修饰词,默认返回值是int型.
11-5-3:void不能代表一个真实的变量.
当我们定义一个变量时,编译器是需要为我们这个变量分配内存的.但是如果声明为void类型,那么编译器就不知道
应该为我们这个变量分配多大的内存.如下面的定义是错误的:
void a;
12.return 关键字.
这个没啥好说的,主要是返回指针时要特别注意是不是栈区的.如下面的语句是非常危险的:
char * Func(void)
{
char str[30];
...
return str;
}
str 属于局部变量,位于栈内存中,在 Func 结束的时候被释放,所以返回 str 将导致错误.
13.const关键字
const意味着只读变量.它本质上还是变量而不是常量,只不过是只读的.因此,case语句后面不能带
被const修饰的变量,因为case后面只能跟常量.必须在定义的时候初始化,如下面的示例:
#include
#include
int main(int argc,char **argv)
{
const int iTestVal;
iTestVal = 100;
printf("iTestVal = %d\n",iTestVal);
return 0;
}
编译出错:
root@seven-laptop:~/learn/C_Program# gcc const.c -o const
const.c: In function ‘main’:
const.c:8: error: assignment of read-only variable ‘iTestVal’
root@seven-laptop:~/learn/C_Program#
13-1.const与define的区别:
1).const只有一份拷贝,而define有多份拷贝;
2).define在预编译阶段进行替换,const修饰的只读变量是在编译的时候确定其值;
3).define宏没有类型,const修饰的只读变量是有类型的.
13-2.const到底修饰谁?
下面给出一个容易的记忆方法:
先忽略类型名, const离谁近就修饰谁.例如:
const int *p; //去掉"int",const 修饰*p,p 是指针,*p 是指针指向的对象,不可变
int const *p; //去掉"int",const 修饰*p,p 是指针,*p 是指针指向的对象,不可变
int *const p; //去掉"int",const 修饰 p,p 不可变,p 指向的对象可变
const int *const p;//去掉"int",前一个 const 修饰*p,后一个const修饰p,指针p和p指向的对象都不可变
13-3.const修饰函数参数.
const 修饰符也可以修饰函数的参数,当不希望这个参数值被函数体内意外改变时使用.例如:
void Fun(const int i);
告诉编译器 i 在函数体中的不能改变,从而防止了使用者的一些无意的或错误的修改.
13-4.const 修饰符也可以修饰函数的返回值,返回值不可被改变.
小结:
在代码中灵活运用const关键字可以提高代码的效率和可读性.
14.volatile关键字
volatile 关键字和 const 一样是一种类型修饰符,用它修饰的变量表示可以被某些编译器
未知的因素更改,比如操作系统、硬件或者其它线程等.遇到这个关键字声明的变量,编译器
对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问.
通过下面两个示例对比volatile关键字的作用.
示例一:
int i=10;
int j = i;//(1)语句
int k = i;//(2)语句
这时候编译器对代码进行优化,因为在(1)(2)两条语句中,i没有被用作左值.这时候
编译器认为i的值没有发生改变,所以在(1)语句时从内存中取出i的值赋给j之后,这个
值并没有被丢掉,而是在(2)语句时继续用这个值给k赋值.编译器不会生成出汇编代码
重新从内存里取i的值,这样提高了效率.但要注意:(1)(2)语句之间 i 没有被用作左
、
值才行.
volatile int i=10;
int j = i;//(3)语句
int k = i;//(4)语句
volatile关键字告诉编译器i是随时可能发生变化的,每次使用它的时候必须从内存中取出 i
的值,因而编译器生成的汇编代码会重新从 i 的地址处读取数据放在 k 中.这样看来,如果i是一个
寄存器变量或者表示一个端口数据或者是多个线程的共享数据,就容易出错,所以说volatile可以保
证对特殊地址的稳定访问.
15.extern关键字
extern 可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,下面的代码用到的这些
变量或函数是外来的,不是本文件定义的,提示编译器遇到此变量和函数时在其他模块中寻找其定义.
16.struct关键字
当我们要传输的数据不是简单的字节,我们要用到struct关键字,比如网络协议、LINUX底层开发等;
当我们函数的参数超过4个时,可以借用结构体来压缩参数个数.因为如果函数的参数多于 4 个使用
起来非常容易出错(包括每个参数的意义和顺序都容易弄错) 效率也会降低,(与具体 CPU 有关,ARM
芯片对于超过 4 个参数的处理就有讲究,具体请参考相关资料).
17.union关键字
union 维护足够的空间来置放多个数据成员中的“一种”,而不是为每一个数据成员配置
空间.
17-1.在 union 中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所
有的数据成员具有相同的起始地址.如果同时对union成员赋值,则只有最后的成员有效.例如下面两个
对比示例:
示例一:
#include
#include
typedef union __uniontest
{
unsigned char ca;
unsigned short sb;
unsigned int ic;
}uniontest,*puiontest;
int main(int argc,char **argv)
{
char cTestVal1 = 'I';
char *sTestVal2 = "Love";
char *sTestVal3 = "You";
uniontest unionVal;
unionVal.sb = 520;
unionVal.ic = 20131314;
unionVal.ca = 'c';
printf("%c\n",cTestVal1);
printf("%s\n",sTestVal2);
printf("%s\n",sTestVal3);
printf("Value of unionVal.ca = %c\nAddress of unionVal.ca = %p\n",unionVal.ca,&unionVal.ca);
printf("Value of unionVal.sb = %d\nAddress of unionVal.sb = %p\n",unionVal.sb,&unionVal.sb);
printf("Value of unionVal.ic = %d\nAddress of unionVal.ic = %p\n",unionVal.ic,&unionVal.ic);
return 0;
}
输出结果:
root@seven-laptop:~/learn/C_Program# ./union
I
Love
You
Value of unionVal.ca = c
Address of unionVal.ca = 0xbfab0ac4
Value of unionVal.sb = 11619
Address of unionVal.sb = 0xbfab0ac4
Value of unionVal.ic = 20131171
Address of unionVal.ic = 0xbfab0ac4
root@seven-laptop:~/learn/C_Program#
示例二:
#include
#include
typedef union __uniontest
{
unsigned char ca;
unsigned short sb;
unsigned int ic;
}uniontest,*puiontest;
int main(int argc,char **argv)
{
char cTestVal1 = 'I';
char *sTestVal2 = "Love";
char *sTestVal3 = "You";
uniontest unionVal;
unionVal.ca = 'c';
unionVal.sb = 520;
unionVal.ic = 20131314;
printf("%c\n",cTestVal1);
printf("%s\n",sTestVal2);
printf("%s\n",sTestVal3);
printf("Value of unionVal.ca = %c\nAddress of unionVal.ca = %p\n",unionVal.ca,&unionVal.ca);
printf("Value of unionVal.sb = %d\nAddress of unionVal.sb = %p\n",unionVal.sb,&unionVal.sb);
printf("Value of unionVal.ic = %d\nAddress of unionVal.ic = %p\n",unionVal.ic,&unionVal.ic);
return 0;
}
输出结果:
root@seven-laptop:~/learn/C_Program# ./union
I
Love
You
Value of unionVal.ca =
Address of unionVal.ca = 0xbfe1e624
Value of unionVal.sb = 11762
Address of unionVal.sb = 0xbfe1e624
Value of unionVal.ic = 20131314
Address of unionVal.ic = 0xbfe1e624
root@seven-laptop:~/learn/C_Program#
上述两个示例中只是把语句"unionVal.ca = 'c';"换一下位置,输出结果截然不同.
17-2.巧用union来判断系统的大小端
大端:是指字数据的高字节存放在低地址中,而字数据的低字节则存放在高地址中;
小端:是指字数据的高字节存放在高地址中,而字数据的低字节则存放在低地址中.
union 型数据所占的空间等于其最大的成员所占的空间.对 union 型的成员的存取
都是相对于该联合体基地址的偏移量为 0 处开始, 也就是联合体的访问不论对哪个变
量的存取都是从 union 的首地址位置开始.
也就是说,如果我们定义一个字类型数据,往这个字类型数据的内存地址空间的一个
字节处写入一个值.然后根据这个字节存放在这个字地址的高低地址来判断这个系统
是大端还是小端.代码如下:
#include
#include
int checkSystem(void)
{
union check
{
int i;
char ch;
}c;
c.i = 1;
return (1 == c.ch);
}
int main(int argc,char **argv)
{
int ret = -1;
ret = checkSystem();
if(1 == ret)
{
printf("Your System Is Little_Endian.\n");
}
else
{
printf("Your System Is Big_Endian.\n");
}
return 0;
}
代码简析:
变量 i 占 4 个字节,但只有一个字节的值为 1,另外三个字节的值都为 0.如果取出低
地址上的值为 0,毫无疑问,这是大端模式;如果取出低地址上的值为 1,毫无疑问,这是
小端模式.
18.enum关键字
一般的定义方式如下:
enum enum_type_name
{
ENUM_CONST_1,
ENUM_CONST_2,
...
ENUM_CONST_n
} enum_variable_name;
2).enum_type_name是enum_type_name类型的一个变量,只是这个变量的取值作了限定,只能是"{}"括号里面的某个常量;
3).enum类型中"{}"里面是元素是常量,不能在程序过程在再次赋值;
4).总的来说,enum枚举类型是针对一些编程中需要处理一些有取值范围的情况,如一个星期有七天,一年有12个月等.对编程
规范起了很大的作用.
示例:
#include
#include
typedef enum Week
{
SUN,
MON,
TUE,
WED,
THU,
FRI,
STA
}WeekVal;
int main(int argc,char **argv)
{
WeekVal enumVal0,enumVal1,enumVal2,enumVal3,enumVal4,enumVal5,enumVal6;
enumVal0 = SUN;
enumVal1 = MON;
enumVal2 = TUE;
enumVal3 = WED;
enumVal4 = THU;
enumVal5 = FRI;
enumVal6 = STA;
printf("WeekVa0 = %d\n",enumVal0);
printf("WeekVa1 = %d\n",enumVal1);
printf("WeekVa2 = %d\n",enumVal2);
printf("WeekVa3 = %d\n",enumVal3);
printf("WeekVa4 = %d\n",enumVal4);
printf("WeekVa5 = %d\n",enumVal5);
printf("WeekVa6 = %d\n",enumVal6);
return 0;
}
输出结果:
root@seven-laptop:~/learn/C_Program# ./enum
WeekVa0 = 0
WeekVa1 = 1
WeekVa2 = 2
WeekVa3 = 3
WeekVa4 = 4
WeekVa5 = 5
WeekVa6 = 6
root@seven-laptop:~/learn/C_Program# vim enum.c
[注:]enum是基本数据类型,相当于UNIT,不是结构.enum只是定义了一个常量集合,里面没有"元素".因此,上述代码中
sizeof(WeekVal)是等于4的.
19.typedef关键字
给一个已经存在的数据类型(注意:是类型不是变量)取一个别名,而非定义一个新的数据类型.语法如下:
typedef struct student
{
//code
}Stu_st,*Stu_pst;
Stu_st,*Stu_pst可以理解为一种和int性质一样,都是数据类型.因此,当判断const修饰被typedef修饰的数据类型别名时,
可以像int型一样"抹掉"就可以了.如下面两个语句:
const Stu_pst stu3;
Stu_pst const stu4;
均可把Stu_pst"抹掉",显而易见,const均修饰stu3和stu4的地址.
如下面代码是编译不过的:
1 #include
2 #include
3
4 typedef struct __student
5 {
6 char *name;
7 unsigned int age;
8 }student,*pstudent;
9
10 int main(int argc,char **argv)
11 {
12 pstudent stu1 = (pstudent)malloc(sizeof(student));
13 pstudent stu2 = (pstudent)malloc(sizeof(student));
14
15 stu1->name = "Seven";
16 stu1->age = 24;
17
18 stu2->name = "Melin";
19 stu2->age = 22;
20
21 const pstudent stutmp1 = stu1;
22 pstudent const stutmp2 = stu2;
23
24 stutmp1->name = "Melin";
25 stutmp1->age = 22;
26
27 stutmp2->name = "Seven";
28 stutmp2->age = 24;
29
30 stutmp1 = stu2;
31 stutmp2 = stu1;
32
33 free(stu1);
34 free(stu2);
35 stu1 = NULL;
36 stu2 = NULL;
37
38 return 0;
39 }
编译报错:
root@seven-laptop:~/learn/C_Program# gcc typedef.c -o typedef
typedef.c: In function ‘main’:
typedef.c:30: error: assignment of read-only variable ‘stutmp1’
typedef.c:31: error: assignment of read-only variable ‘stutmp2’
root@seven-laptop:~/learn/C_Program#
[注:]当计算一个指针指向类型的大小时,这个指针必须有指向对象.如上面语句
"pstudent stu1 = (pstudent)malloc(sizeof(student));"
修改为
"pstudent stu1 = (pstudent)malloc(sizeof(*pstudent));"
编译报错:
typedef.c:12: error: expected expression before ‘pstudent’
其实只要深刻明白sizeof()的定义即可:sizeof是计算一个内存存在对象占用内存的大小.*pstudent指向
的内存存在对象是未知的,自然为难sizeof了.
19-1.typedef与define的区别:
1).声明形式不一样,define后面没有分号,而typedef后面要加分号.如下:
#define INT32 int
typedef int int32;
2).修饰指针不一样,define只是简单的替换,不能像int i,j;那样定义一系列变量.如下:
#define PCHAR char*
PCHAR p3,p4;//p3是指针,p4只是一个普通的字符
typedef char* pchar;
pchar p1,p2;//p3、p4都是一个指针