C语言复习第三天
enum,sizeof,typedef 分析
enum类型的使用方法
1、enum是C语言中的一种自定义类型
2、enum值是可以根据需要自定义的整型值
3、第一个定义的enum值默认是 0
4、默认情况下的enum值是在前一个定义值的基础上加1
5、enum类型的变量只能取定义时的离散值
#include <stdio.h>
enum color
{
red,
green=2,
blue,
black
};
int main()
{
enum color c = blue;
printf(" c is %d\n",c);
return 0;
}
enum类型的特殊意义
1、enum中定义的值是C语言中真正意义上的常量
2、在工程中enum多用于定义整形常量
enum使用实例
#include <stdio.h>
enum //无名枚举,用于定义常量
{
ARRAY_SIZE = 10
};
enum Color
{
RED = 0x00FF0000,
GREEN = 0x0000FF00,
BLUE = 0x000000FF
};
void PrintColor(enum Color c)
{
switch( c )
{
case RED:
printf("Color: RED (0x%08X)\n", c);
break;
case GREEN:
printf("Color: GREEN (0x%08X)\n", c);
break;
case BLUE:
printf("Color: BLUE(0x%08X)\n", c);
break;
}
}
void InitArray(int array[])
{
int i = 0;
for(i=0; i<ARRAY_SIZE; i++)
{
array[i] = i + 1;
}
}
void PrintArray(int array[])
{
int i = 0;
for(i=0; i<ARRAY_SIZE; i++)
{
printf("%d\n", array[i]);
}
}
int main()
{
enum Color c = GREEN;
int array[ARRAY_SIZE] = {0};
PrintColor(c);
InitArray(array);
PrintArray(array);
return 0;
}
sizeof 分析
1、sizeof是C语言内置关键字而不是函数,相当于宏
——在编译过程中所有的sizeof将被具体的值所替代
——程序执行的过程与sizeof没有任何关系
int f()
{
printf("Delphi Tang\n");
return 0;
}
int main()
{
int var = 0;
int size = sizeof(var++);
printf("var = %d, size = %d\n", var, size);
size = sizeof(f());
printf("size = %d\n", size);
return 0;
}
结果:
var++,func函数并没有执行并没有执行,因为在编译过程中sizeof已经被具体的值替代。
typedef 分析
1、typedef 用于给一个已经存在的数据类型重命名
2、typedef 本质上不能产生新的类型
3、typedef 重命名的类型:
——可以在typedef 语句之后定义
——不能被unsigned和signed修饰
用法: typedef type new_name;
使用示列
#include <stdio.h>
typedef int Int32;
struct _tag_point
{
int x;
int y;
};
typedef struct _tag_point Point;
typedef struct
{
int length;
int array[];
} SoftArray;
typedef struct _tag_list_node ListNode;
struct _tag_list_node
{
ListNode* next;
};
int main()
{
Int32 i = -100; // int
//unsigned Int32 ii = 0;
Point p; // struct _tag_point
SoftArray* sa = NULL;
ListNode* node = NULL; // struct _tag_list_node*
return 0;
}
注释符号
1、注释应该准确易懂,防止 二义性
2、注释是对代码的提示,避免臃肿和喧宾夺主
3、注释用于阐述原因和意图而不是描述程序的运行过程
tips
注释在预编译期间会被当成空格。
#include <stdio.h>
int main()
{
int/*...*/i;
char* s = "abcdefgh //hijklmn";
//Is it a \
valid comment?
in/*...*/t i;
return 0;
}
预处理命令:gcc -E -o tt.i tt.c
接续符和转义符
接续符
1、C语言中的接续符(\)是指示编译器行为的利器
2、编译器会将反斜杠剔除,跟在反斜杠后面的字符自动接续到前一行
3、在接续单词时,反斜杠之后不能有空格,反斜杠的下一行之前也不能有空格
4、接续符适合在定义宏代码块时使用
#in\
clud\
e <st\
dio.h>
in\
t m\
ain(\
)
{
pri\
ntf\
(\
"Hello D.T.\n"
)\
;
ret\
urn 0;
}
预编译后的结果
接续符的应用
定义宏定义模块:
#define SWAP(a,b)\
{ \
int temp=a; \
a=b; \
b=temp; \
}
int main()
{
int a = 1;
int b = 2;
int c = 3;
SWAP(a,b);
printf("a = %d, b = %d\n", a, b);
SWAP(b,c);
printf("b = %d, c = %d\n", b, c);
return 0;
}
tips
宏定义的本质就是替换
预处理后的代码:
结果:
转义符
1、C语言的转义符(\)主要用于表示无回显字符,也可以用于表示常规字符
2、当分斜杠(\n)作为作为转义符使用时必须出现在单引号或者双引号之间。
#include <stdio.h>
int main()
{
char enter = '\n';
char* p = "\141\t\x62";
printf("%s", p);
printf("%c", enter);
return 0;
}
单引号和双引号
1、C语言中的单引号用来表示字符字面量
’a‘表示字符字面量
在内存中占一个字节
'a'+1表示'a'的ASCII码加1,结果为'b'
2、C语言中的双引号用来表示字符串字面量
"a"表示字符串字面量
在内存占两个字节
“a”+1表示指针运算,结果指向"a"结束符’\0‘
实例:
tips
1、字符字面量被编译程对应的ASCII码
2、字符串字面量被编译为对应的内存地址
3、printf的第一个参数被当成字符串字面量内存地址
4、内存的低地址空间不能在程序中随意访问
#include <stdio.h>
int main()
{
char* p1 = 1 ;
char* p2 = '1';
char* p3 = "1";
printf("p1 adress is 0x%x\n",p1); //p1指针指向的地址
printf("p2 adress is 0x%x\n",p2); //p2指针指向的地址 0x31为字符1的ASCII码值
printf("p3 adress is 0x%x\n",p3); //p3指针指向的地址
printf("p3 value is %s\n",p3); //访问p3地址 p2,p1地址访问会出段错误
//printf('\n') 出错
printf("\n");
return 0;
}
tips
这段代码发生了什么?
char C="string"
分析:
1、编译后字符串"string"的内存地址被赋值给变量c
2、内存地址占用4个字节,而变量c只占用1个字节
3、由于类型不同,赋值后产生截断
小结
1、单引号括起来的单个字符代表整数
2、双引号括起来字符代表指针
3、C编译器接受字符和字符串的比较,无意义
4、C编译器允许字符串对字符变量赋值,只能得到错误结果
逻辑运算符分析
1、逻辑运算符
&& , || , !
示列:
#include <stdio.h>
int main()
{
int i = 0;
int j = 0;
int k = 0;
++i || ++j && ++k;
printf("%d\n", i);
printf("%d\n", j);
printf("%d\n", k);
return 0;
}
结果?
1 0 0
程序中的短路
-||从左往右开始计算:
当遇到真的条件是停止计算,整个表达式为真
所有条件为假时表达式才为假
-&& 从左往右开始计算:
当遇到假的条件是停止计算,整个表达式为假
所有条件为真时表达式才为真
示列程序分析:
tips
! 分析
C语言中的逻辑非"!"只认得0,只有0返回1 ,其余全返回0
位运算符分析
1、位运算符直接对bit位进行操作,其效率最高
左移和右移的注意点
1、左操作数必须为整数类型
char 和 short 被隐式转换为int 进行移位操作
2、右操作数的范围必须为:【0,31】
3、左移运算符<<将运算数的二进制位左移
规则 :高位丢弃,低位补0
4、右移运算符<<将运算数的二进制位右移
规则 :高位补符号位,低位丢弃。
示列:
tips
-1再怎么右移始终是-1
#include <stdio.h>
int main()
{
printf("%d\n", 3 << 2);
printf("%d\n", 3 >> 3);
printf("%d\n", -1 >> 2); //-1再怎么右移始终是-1
printf("%d\n", 0x01 << 2 + 3); //运算符的优先级
printf("%d\n", 3 << -1); // oops!
return 0;
}
实例:交换两个整形变量的值(三种方法):
#include <stdio.h>
#define SWAP(a,b)\
{ \
int temp=a; \
a=b; \
b=temp; \
}
#define SWAP1(a,b)\
{ \
a=a+b; \
b=a-b; \
a=a-b; \
}
#define SWAP2(a,b)\
{ \
a=a^b; \
b=a^b; \
a=a^b; \
}
int main()
{
int i=-3;
int j=9;
printf("i=%d ,j=%d\n",i,j);
SWAP2(i,j);
printf("i=%d ,j=%d\n",i,j);
return 0;
}
小结
1、位运算符只能用于整数类型
2、左右移位运算符的右操作数必须位【0,31】
——在gcc编译器上超过 位数,该段程序不会执行
3、位运算没有短路规则,所有操作数均会求值
4、位运算效率最高
5、运算优先级:
——四则运算 > 位运算 > 逻辑运算