目录
三,数据类型与变量
一,C程序结构
1.预处理指令 #include<stdio.h>
2.主函数 int main()
3.输出函数 (print打印) printf()
4.终止main()函数,并返回值0 return 0
5.注释 /* */(单/多行),//(单行)
二,基础语法知识
1.语句结束符 分号;
2.标识符(第一个符号不能是数字)
3.数据类型(详细)
| auto | 声明自动变量 |
| break | 跳出当前循环 |
| case | 开关语句分支 |
| char | 声明字符型变量或函数返回值类型 |
| const | 定义常量,如果一个变量被 const 修饰,那么它的值就不能再被改变 |
| continue | 结束当前循环,开始下一轮循环 |
| default | 开关语句中的"其它"分支 |
| do | 循环语句的循环体 |
| double | 声明双精度浮点型变量或函数返回值类型 |
| else | 条件语句否定分支(与 if 连用) |
| enum | 声明枚举类型 |
| extern | 声明变量或函数是在其它文件或本文件的其他位置定义 |
| float | 声明浮点型变量或函数返回值类型 |
| for | 一种循环语句 |
| goto | 无条件跳转语句 |
| if | 条件语句 |
| int | 声明整型变量或函数 |
| long | 声明长整型变量或函数返回值类型 |
| register | 声明寄存器变量 |
| return | 子程序返回语句(可以带参数,也可不带参数) |
| short | 声明短整型变量或函数 |
| signed | 声明有符号类型变量或函数 |
| sizeof | 计算数据类型或变量长度(即所占字节数) |
| static | 声明静态变量 |
| struct | 声明结构体类型 |
| switch | 用于开关语句 |
| typedef | 用以给数据类型取别名 |
| unsigned | 声明无符号类型变量或函数 |
| union | 声明共用体类型 |
| void | 声明函数无返回值或无参数,声明无类型指针 |
| volatile | 说明变量在程序执行中可被隐含地改变 |
| while | 循环语句的循环条件 |
三,数据类型与变量
1,数据类型(主要)

2,常用数据类型占用空间
char:1个字节
int : 4个字节
float:4个字节
double:8个字节
3,基本类型书写
1.整数
(1) 默认为十进制
(2)以0开头的为八进制
(3)以0b开头为2进制
(4)以0x开头为16进制
2.小数
(1)单精度: 例:2.2f
(2)双精度: 例:2.2,默认为双精度
3.字符型常量
例: 'a' 、'*'、'\n'
4.字符串常量
例:''ily''
注:在C语言中,计算时,会将数据强制转换成一种类型(浮点转整形小数全舍去;整形转小数,数值会储存到相应的浮点类型变量中)
四,C变量
1,变量定义 :在何处创建变量的存储,以及如何创建变量的存储。(指定一个数据类型,并包含了该类型的一个或多个变量的列表)(定义只能出现在一处)
2,变量声明:确认指定的类型和名称存在(可以出现多次)【extern】
注:给出全局变量初值的一定是定义。
extern int a; //声明
int a; //定义
extern int a = 0; //该处即是定义了一个全局变量a,并给初值,是定义(定义才会分配处置空间)
int a = 0; //定义
3,左值(Lvalues):内存位置的表达式(可在赋值号的左或右)
4,右值(Rvalues): 储存在内存中某些地址的数值(赋值号的右边)
注:lvalues有时可自动切换成rvalues,但rvalues不可切换成lvalues!
5,全局变量:在函数外部定义,具有全局的生存期和作用域,与任何函数都无关,且可以在任何函数内部都可以使用。(没有做初始化的全局变量会得到0值)(指针会得到NULLA值)(只能用编译时可以指的值来初始化变量)(他们的初始化发生在main函数之前)
6,静态本地变量,本地变量前加static,当函数离开时,静态变量值保持不变且一直存在,在刚进入函数时初始化,以后进入函数时会保持上次离开时的值。
补:变量的内存寻址,(1)内存寻址由大到小,因此在前面定义的变量比后面定义的变量要大.(2)变量获取地址方式:&变量名(3)输出地址方式:%p (4)变量需要初始化。
补:*返回指针的函数
(1)返回本地变量的地址是危险的
(2)返回全局能量或静态本地变量的地址是安全的
(3)返回在函数内malloc的内存是安全的,但是容易造成问题
(4)最好的做法是返回传入指针
tips
(1)不要使用全局变量来在函数间传递参数和结果
(2)尽量避免使用全局能量
(3)使用全局变量和静态本地变量的函数多线程的环境是不安全的
五,C常量
1,整数常量:不同进制的常量以及U(unsigned)和L(long)的后缀
注:后缀可大写可小写
2,浮点常量: 必须包含小数
3,字符常量:
| 转义序列 | 含义 |
|---|---|
| \\ | \ 字符 |
| \' | ' 字符 |
| \" | " 字符 |
| \? | ? 字符 |
| \a | 警报铃声 |
| \b | 退格键 |
| \f | 换页符 |
| \n | 换行符 |
| \r | 回车 |
| \t | 水平制表符 |
| \v | 垂直制表符 |
| \ooo | 一到三位的八进制数 |
| \xhh | 一个或多个数字的十六进制数 |
4,字符串常量
一个字符串包含类似于字符常量的字符:普通的字符、转义序列和通用的字符。
分行时仅可以用空格
"hello"
"he\
llo"
"h","ell","0"
//以上代码,均为相同效果
5,定义常量
(1)使用#define预处理器
(2)使用const关键字
const int var = 5; //声明常量
注:#define 宏定义,不可定义常量 ,定义的是不带类型的常数,只进行简单的字符替换。在编译的时候起作用,不存在类型检查。【预处理也可理解为替换】
const定义的是变量(常变量,此后值不变,也就是定义变量时就需要初始化赋值)不是常量,之后会在编译阶段会执行类型检查。
宏定义不分配内存,变量定义分配内存。
可以把#define理解为仅仅是替换,在运算等过程中不会有其他特殊的地方。
例:
#include <stdio.h>
#define f(x) x*x
int main()
{
int a =15,b = 1, c = 2;
a /= f(b+c)/f(b+c);
printf("a = %d",a);
return 0;
}

运算过程为:a/(1+2*1+2/1+2*1+2) = 15/11=1
这里这个代码就是因为忘记#define仅仅是替换作用,不会改变运算顺序,只要在原文里加上括号就行了。
如下:
#define f(x) (x*x)
六,C存储类
1,auto存储类 :局部变量默认存储类,函数内使用,修饰局部变量
2,register存储类:寄存器的变量(用于快速访问的变量)
3,static存储类:全局变量的默认存储类,表示变量在程序生命周期内可见;
4,extern存储类:全局变量,对所有文件可见。
七,C运算符
1,算术运算符
(+,加; -,减; *,乘; /,除; %,取余; ++,自增一; --,自减一)
注:a++是起缓存作用,缓存自加后的结果,用于下次与a相关的计算,++a相当于a+1。
2,关系运算符
| == | 两个数的值是否相等 |
| != | 两个数的值是否相等 |
| > | 左值是否大于值 |
| < | 左值是否小于右值 |
| >= | 左值是否大于或等于右值 |
| <= | 3左值是否小于或等于右值 |
3,逻辑运算符
| && | 逻辑与运算符 |
| || | 逻辑或运算符 |
| ! | 逻辑非运算符 |
4,位运算符
#include <stdio.h>
int main()
{
unsigned int a = 60; /* 60 = 0011 1100 */
unsigned int b = 13; /* 13 = 0000 1101 */
int c = 0;
c = a & b; /* 12 = 0000 1100 */
printf("Line 1 - c 的值是 %d\n", c );
c = a | b; /* 61 = 0011 1101 */
printf("Line 2 - c 的值是 %d\n", c );
c = a ^ b; /* 49 = 0011 0001 */
printf("Line 3 - c 的值是 %d\n", c );
c = ~a; /*-61 = 1100 0011 */
printf("Line 4 - c 的值是 %d\n", c );
c = a << 2; /* 240 = 1111 0000 */
printf("Line 5 - c 的值是 %d\n", c );
c = a >> 2; /* 15 = 0000 1111 */
printf("Line 6 - c 的值是 %d\n", c );
}
Line 1 - c 的值是 12 Line 2 - c 的值是 61 Line 3 - c 的值是 49 Line 4 - c 的值是 -61 Line 5 - c 的值是 240 Line 6 - c 的值是 15
5,赋值运算
| 运算符 | 描述 | 实例 |
|---|---|---|
| = | 简单的赋值运算符,把右边操作数的值赋给左边操作数 | C = A + B 将把 A + B 的值赋给 C |
| += | 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 | C += A 相当于 C = C + A |
| -= | 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 | C -= A 相当于 C = C - A |
| *= | 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 | C *= A 相当于 C = C * A |
| /= | 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 | C /= A 相当于 C = C / A |
| %= | 求模且赋值运算符,求两个操作数的模赋值给左边操作数 | C %= A 相当于 C = C % A |
| <<= | 左移且赋值运算符 | C <<= 2 等同于 C = C << 2 |
| >>= | 右移且赋值运算符 | C >>= 2 等同于 C = C >> 2 |
| &= | 按位与且赋值运算符 | C &= 2 等同于 C = C & 2 |
| ^= | 按位异或且赋值运算符 | C ^= 2 等同于 C = C ^ 2 |
| |= | 按位或且赋值运算符 | C |= 2 等同于 C = C | 2 |
6,杂项运算符
| 运算符 | 描述 | 实例 |
|---|---|---|
| sizeof() | 返回变量的大小。 | sizeof(a) 将返回 4,其中 a 是整数。 |
| & | 返回变量的地址。 | &a; 将给出变量的实际地址。 |
| * | 指向一个变量。 | *a; 将指向一个变量。 |
| ? : | 条件表达式 | 如果条件为真 ? 则值为 X : 否则值为 Y |
7,运算符优先级
| 类别 | 运算符 | 结合性 |
|---|---|---|
| 后缀 | () [] -> . ++ - - | 从左到右 |
| 一元 | + - ! ~ ++ - - (type)* & sizeof | 从右到左 |
| 乘除 | * / % | 从左到右 |
| 加减 | + - | 从左到右 |
| 移位 | << >> | 从左到右 |
| 关系 | < <= > >= | 从左到右 |
| 相等 | == != | 从左到右 |
| 位与 AND | & | 从左到右 |
| 位异或 XOR | ^ | 从左到右 |
| 位或 OR | | | 从左到右 |
| 逻辑与 AND | && | 从左到右 |
| 逻辑或 OR | || | 从左到右 |
| 条件 | ?: | 从右到左 |
| 赋值 | = += -= *= /= %=>>= <<= &= ^= |= | 从右到左 |
| 逗号 | , | 从左到右 |
总结:
初等运算符>单目运算符>算术运算符>关系运算符>逻辑运算符>条件运算符>赋值运算符
初等运算符有:()、[ ]、->、. (后两者均为结构体成员运算符); 单目运算符有:!、~、++、--、sizeof、&、*; 算术运算符有:*、/、+、-、<<、>>; 关系运算符有:<、<=、>、>=、==、!=、&、^、|;(此栏排列仍有优先级顺序哦); 逻辑运算符有:&&、||; 条件运算符有:?:(即三目运算符); 赋值运算符有:=、+=、-=、*=、/=、%=、>>=、<<=;等
另外,单目运算符的优先级都高于双目运算符。
八,C判断
1,判断语句
(嵌套)if(…else)语句
(嵌套)switch 语句
2,三元运算符(? :)

#include<stdio.h>
int main()
{
int num;
printf("输入一个数字 : ");
scanf("%d",&num);
(num%2==0)?printf("偶数"):printf("奇数");
}
//判断数字是否为偶数
九,C循环
(1)循环类型
1,while循环:当给定条件为真时,重复语句或语句组。它会在执行循环主体之前测试条件。
2,for循环:多次执行一个语句序列,简化管理循环变量的代码。
3,do…while循环:除了它是在循环主体结尾测试条件外,其他与 while 语句类似。
4,嵌套循环:在while、for或do…while循环内使用一个或者多个循环。
(2)循环控制语句
1,break语句:终止循环或switch语句,程序流将继续执行紧接着循环或switch的下一条语句。
2,beContinue语句:告诉一个循环体立刻停止本次循环迭代,重新开始下次循环迭代。
3,goto控制转移带被标记的语句。但是不建议在程序中使用goto语句。
补:for可以实现无限循环。
注:Ctrl + C是终止无限循环的键。
十,函数
函数:一组一起执行一个任务的语句。每个C程序都至少有一个函数,即主函数main()
(1)定义函数
1,返回类型:一个函数可以返回一个值。return_type是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return_type是关键字viod。
2,函数名称:函数实际名称。和参数列表一起构成了函数签名。
3,参数:参数就像是占位符。当函数被调用时,向参数传递一个值,其值被称为实际参数,参数列表包括函数参数。
4,函数主体:函数主题包含一组定义函数执行任务的语句。
(2)函数声明
函数声明:声明编译器函数名称及如何调用函数。函数实际主体可单独定义。
注:当在一个源文件中定义函数且在另一个文件中调用函数中,必须在文件顶部声明函数。
(3)调用函数
当程序调用函数时,程序控制权会转移给被调用的函数。被调用的函数执行已定义的任务,当函数的返回语句被执行时,或到达函数结束括号时,会把程序控制权交给主程序。
调用函数时,传递函数时,传递所需参数,如果函数返回一个值,则可以储存返回值。
(4)函数参数
形式参数:如果函数要使用参数,则必须声明接受参数值的变量,变量称为函数的形式参数。
| 调用类型 | 描述 |
|---|---|
| 传值调用 | 该方法把参数的实际值复制给函数的形式参数。在这种情况下,修改函数内的形式参数不会影响实际参数。 |
| 引用调用 | 通过指针传递方式,形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作。 |
十一,C作用域规则
可以声明变量的三处:
(1)局部变量:在某个函数或块的内部声明的变量称为全局变量(只可在该函数或该代码内部语句使用)
(2)全局变量:在函数的外部(顶部)
注:全局变量在整个程序周期都是有效的。
注:在初始化变量时,若全局变量和局部变量中的形参的名称相同,则会优先使用局部变量初始化的值。
(3)形式参数:可作为函数内的局部变量。
(4)初始化据变量和全局变量
| 数据类型 | 初始化默认值 |
|---|---|
| int | 0 |
| char | '\0' |
| float | 0 |
| double | 0 |
| pointer | NULL |
十二,C数组
数组:用来储存一系列的数据,可以储存一个固定大小的相同类型元素的顺序集合。
补:所有的数组都是由连续的内存组成。最低地址对应第一个元素,最高地址对应最后一个元素。
注:数组中的特定元素可以通过索引访问,第一个索引值为0。


(1)声明数组
格式: type arrayName [ arraySize ];
例:int runoob [6];
这是一个类型为int的包含6个元素的数组runoob
注:arraySize必须为正整数。
(2)初始化数组
初始化数组时,可以一个一个元素初始化,也可以直接使用一个初始化语句,初始化完所有的元素。
例:int runoob [6] = {7, 3, 5, 2, 198, 32};
例:int runoob [ ] = {7, 3, 5, 2, 198, 32}
此时该数组arraySize直接默认为6。
且int runoob[0] = 7
注:当{ }中缺少一定的元素时,只给前面的元素赋值,后面的自动初始化为零。
对于short、int、long,就是整数0; 对于char,就是字符‘\0’; 对于float、double,就是小数0.0。
(3)访问数组元素
int salary = runoob[5];
该语句是把数组第六个元素的值赋给salary变量。
(4)C中数组详解
概念
描述 多维数组 C 支持多维数组。多维数组最简单的形式是二维数组。 传递数组给函数 您可以通过指定不带索引的数组名称来给函数传递一个指向数组的指针。 从函数返回数组 C 允许从函数返回数组。 指向数组的指针 您可以通过指定不带索引的数组名称来生成一个指向数组中第一个元素的指针。
补:数组变量是特殊的指针,数组变量本身表达地址,所以
int a[10]; int *p = a;
但是数组的单元表达的是变量,需要用&取地址
a == &a[0]
[]运算符可以对数组做,也可以对指针做:
p[0] <==> a[0]
*运算符可以对指针做,也可以对数组做:
*a = 25;
数组变量是const的指针,所以不能被赋值
int a[] <==> int *const a=…
十三,C enum(枚举)
(1)枚举定义格式:enum 枚举名 {枚举元素1, 枚举元素2,……};
注:枚举时,第一个若被定义,则其后元素的数值都在前一个的基础上加一,若第一个未被定义,则数值默认为0,其他为在已定义的数值上,加或减。
(2)枚举变量的定义
1,先定义枚举类型,再定义枚举变量
enum COLOR
{
red = 1, green, black, white, bule, yellow
};
enum COLOR color;
2,定义枚举类型的同时定义枚举变量
enum COLOR
{
red = 1, green, black, white, bule, yellow
}color;
3,省略枚举名称,直接定义枚举变量
enum
{
red = 1, green, black, white, bule, yellow
}color;
十四,指针
指针:是内存地址,用来存放内存地址的变量。
格式:type *var_name;
例:int *ip; /* 一个整型的指针 */
double *dp; /* 一个 double 型的指针 */
float *fp; /* 一个浮点型的指针 */
char *ch; /* 一个字符型的指针 */
(1)C中的NULL指针
NULL指针是一个空指针
(2)C指针详解
1.C指针的算术运算
指针递减时,就会指向上一个元素储存单元,反之,指向下一个元素的储存单元。(增减的字数取决于指针所指向变量数据类型长度)
————————递增一个指针
回调函数:通过函数指针调用的函数
补:size_t 是一种数据类型,近似于无符号整型,容量范围一般大于Int和unsigned.(为了使arraysize变量能够有足够大的容量来储存数组)
十五,字符串
(1)以0(整数0)结尾的一串字符
(2)0或'\0'是一样的,但是和'0'不同
(3)0标志字符串的结束,但它不是字符串的一部分
(4)计算字符串长度的时候不包含这个0
(5)字符串以数组的形式存在,以数组或指针的形式访问
(6)更多的是以指针的形式
(7)string.h里有很多处理字符串的函数
(8)两个相邻的字符串常量会被自动连接起来
《1》字符串变量
例:
char *str = "Hello"; 指一个名叫str的指针指向一个字符数组(该字符数组的内容是Hello)的地址 不知道字符串的地址在哪里,可以用来处理参数和动态分配空间
char world[] = "Hello"; 一个名叫world的数组的内容是Hello 知道字符串在哪里,作为本地变量自动被回收
char line[10] = "Hello"; 一个名叫line的字符数组,line的大小是十个字节,而'Hello'只占6(5+1)个字节。
构造字符串用数组
处理字符串用指针
(9)C语言的字符串十一字符数组的形态存在的
(10)不能用字符串做运算
(11)通过数组的方式可以遍历字符串
(12)唯一特殊的地方是字符串字面可以用来初始化数组
(13)以及标准库提供了一系列字符串函数
关于char*
字符串可以表达为char*的形式
char*不一定是字符串
本意是指向字符的指针,可能指向的是字符的数组(就像int*一样)
只有它所指的字符数组有结尾的0,才能说它所指的是字符串
char*只有结尾为'\0'的才为字符串
字符串的输入输出
例:char *t = "title";
char *s;
s = t;
该代码中并没有产生新的代码,只是让指针s和t指向相同的字符串,对s的任何操作,对t也会有同样的影响。
例:char string[8];
scanf("%s", string);
printf("%s", string);
scanf读入一个单词(到空格、tab或回车为止)
注:scanf是不安全的,因为不知道要读入的内容和长度
(1)安全的输入
char string [8];
scanf("%7s", string);
在%和s之间的数字表示最多允许读入的字符的数量,这个数字应该比数组的大小小一(因为结尾的'\0'也占了一个字节)
常见错误:
例:
char *string; //该string变量值是一个指针变量
scanf("%s",string);
以为char*是字符串类型,定义了一个字符串类型的变量string就直接可以用了
由于没有对string初始化为0(野指针有很大的危险性),所以不一定每次运行都出错
(2)空字符串
char buffer[100] = " ";
这是一个空的字符串,buffer[0] == '\0'
char buffer[] = " ";
这个数组的长度只有1!(只有buffer[0]是有效的,buffer[1][2][3]等都是无效的,且buffer[0] = 0)
(3)字符串数组
char **a
a是一个指针,指向另一个指针,另一个指针指向一个字符(串)
char a[][]
(4)程序参数
int main(int argc,char const *argv[]) 注:一个是整数,一个是数组,整数是为了告诉后面的数组到底有多少字符串
argv[0]是一个命令本身
当使用Unix的符号链接时,反应符号链接的名字
(5)putchar
int putchar(int c);
向标准输出写一个字符
返回写了几个字符,EOF(-1)表示写失败 注:EOF全称(end of file)
>>>putchar()用法
(1)putchar就是用来输出(显示到屏幕的)的。
(2)putchar的适用对象是字符数据。(从putchar名字末尾的char也可以看出。)
(3)一个putchar只能输出一个字符。
(4)头文件:<stdio.h>
格式:putchar函数的基本格式为:putchar(c)。
(1)当C为一个被单引号(英文状态下)引起来的字符时,输出该字符(注:该字符也可为转义字符);
例:putchar('a'); ————>a
(2)当c为一个介于0~127(包括0及127)之间的十进制整型数时,(此时没有单引号起来)他会被视为对应字符的ASCII代码,输出该ASCII代码对应的字符;
例:putchar(65);————>A
(3)当c为一个事先用char定义好的字符变量时,(此时没有单引号起来),输出该变量所指向的字符。
例:
#include<stdio.h>
int main()
{
char ch1 = 'a';
char ch2 = 97;
putchar(ch1);
putchar(ch2);
}
输出结果:
aa
(6)getchar
getchar()函数 = int getchar(void);
getchar返回的是ASCII码,在调用getchar()函数时,编译器会依次读取用户间缓存区的一个字符
从标准输入读入一个字符,如果编译器没有输入里面字符,编译器会等待用户输入回车后再执行下一步(回车键算一个字符,但是依旧会换行)
返回类型是int是为了返回EOF(-1)(表示输入结束了)(end of file,文件结束),EOF是定义在头文件
补:该函数以无符号char强制转换为int的形式返回读取的字符,如果达到文件末尾或发生读错误,则返回EOF。
Windows ——>Ctrl-Z
Unix——>Ctrl-D
(7)字符串函数strlen
例:
size_t strlen(const char *s); 注:const是为了程序不会被修改
返回s的字符串长度(不包括结尾的0)
(8)strcmp
int strcmp(const char *s1, const char *s2);
比较两个字符串,返回:
0:s1 == s2
1: s1 > s2
-1 : s1<s2
(9)strcpy
char * strcpy(char *restrict dst, const char *restrict src);
把src的字符串拷贝到dst
restrict表明scr和dst不重叠(C99)
返回dst
为了能炼起代码来t
(10)strcat
char * strcat(char *restrict s1, const char * restrict s2);
把s2拷贝到s1的后面,接成一个长的字符串
返回s1
s1必须有足够空间
(11)字符串中找字符
char * strchr(const char *s , int c);
char * strrchr(const char *s , int c);
返回NULL表示没有找到
十五,枚举
(1)结构成员
#include<stdio.h>
struct date{ //date是我们定义的数据类型,该数据类型中均为相同的类型(int)
int month;
int day;
int year;
}; //声明一种结构类型,且分号后面可以添加结构体变量,结合下面可以写为 }; today, day;
int main(int argc, char const *argv[])
{
struct date today; //定义一个结构变量
today.month = 07;
today.day = 31;
today.year = 2014;
printf("Today's date is %i-%i-%i.\n",today.year,today.month,today.day);
return 0;
}
另一种结构体定义方式
#include<stdio.h>
typedef struct date{ //date是被创建的新类型,在这段代码后面可以将date作为类型声明新的结构体变量
int month;
int day;
int year;
};date; //这里的date也可以省略
结构和数组有点像
注:每个结构体都是不同的类型,即使成员的名字相同,但是也均为不同的个体。
数组用[]运算符和下标访问其成员
a[0] = 10;
结构用 . 运算符和名字访问其成员
today.day
student.firstName
p l.x
p l.y
(2)结构运算
要访问整个结构,直接用结构变量的名字
对于整个结构,可以做赋值、取地址,也可以传递给函数参数
pl = (struct point){5,10}; //相当于pl.x = 5;
pl.y =10;
pl = p2; //相当于pl.x = p2.x;pl.y = p2.y;
注:数组无法做这两种运算!
(3)结构指针
和数组不同,结构变量的名字并不是结构变量的地址,必须使用&运算符
struct date *pDate = & today;
(4)结构与函数
结构作为函数参数有三种传递方式
1.传递结构成员
2.传递结构
3.传递结构的地址
例:
#include<stdio.h>
struct student
{
int age;
double Onceweight;
double Newweight;
char * name[20];
}
double lose (double w1, double w2)
{
return w1 - w2;
} //传递结构成员
/*double lose(struct student students )
{
return students.Onceweight - students.Newweight;
}
*/ //传递结构
/*
double lose(const struct student * students)
{
return students->Onceweight - students->Newweight;
}
*/ //传递地址
int main(void)
{
struct student Tom{19, 90, 75, "Tom Smith"};
double Loseweight = lose(Tom.Onceweight, Tom.Newweight); //传递结构成员
/*double Loseweight = lose(Tom);*/ //传递结构
/*double Loseweight = lose(&Tom)*/ //传递结构地址 注:这里因为要用到地址,而Tom仅仅是一个变量的名称,所以要加上&,传递地址
printf("Tom has lost %1f by losing weight.\n", Loseweight);
}
例:int number0fDays(struct date d) (该参数为一个结构变量)
1.作为一个整体复制和赋值,
2.通过&运算符取地址,
3.访问其成员
复制和赋值包括向函数传递参数以及从函数返回值
结构之间不可相互比较
(5)scanf函数
传递函数的方法:
在这个输入函数中,可以创建一个临时的结构变量———> 结构返回给调用者(->是指针才可以使用的访问结构体成员的运算符)
(6)指向结构的指针
用->表示指针所指的结构变量中的成员
例:
struct date{
int month;
int day;
int year;
} myday;
struct date *p = &myday;
(*p).month = 12;
p->month = 12;
#include<stdio.h>
struct point{
int x;
int y;
};
struct point getStruct(void);
void output(struct point);
int main(int argc, char const *argv[])
{
struct point y = {0, 0};
getStruct(y);
output(y);
output(*getStruct(&y));
printf(getStruct(&y));
}
struct point* getStruct(struct point *p )
{
scanf("%d", &p->x );
scanf("%d", &p->y);
printf("%d, %d\n", p->x, p->y );
return p;
}
void output(struct point p)
{
printf("%d, %d", p.x, p.y );
}
void print(const struct point *p)
{
printf("%d, %d", p->x, p->y);
}
(7)结构中的结构
结构数组
结构中的结构
struct dateAndTime{
struct date sdate;
struct date sdate;
};
嵌套的结构
struct point{
int x;
int y;
};
struct rectangle{
struct point pt1;
struct point pt2;
}; //如果有变量 struct rectangle r;就可以有:r.ptl.x、 r.ptl.y, r.pt2.x和r.pt2.y
如果有变量定义:
struct rectangle r, *p;
rp = &r;
那么下面的四种形式是等价的:
r.ptl.x
rp->ptl.x
(r.ptl).x
(rp->ptl).x
但是没有rp->ptl->x (因为ptl不是指针)
结构中的结构的数组
#include<stdio.h>
struct point{
int x;
int y;
};
struct rectangle{
struct point p1;
struct point p2;
};
void printRect(struct rectangle r)
{
printf("<%d, %d> to <%d, %d>\n ", r.pl.x, r.pl.y, r.p2.x, r.p2.y);
}
int main(int argc, char const *argv[])
{
int i;
struct rectangle rects[] = {{{1,2}, {3, 4}},{{5, 6},{7, 8}}};
for (i =0; i< 2; i++) printRect()rects[i];
}
(8)
<1>自定义数据类型(typedef)
typedef作用:简化复杂的声明(已出现的),并且其定义的别名可以代替这个复杂的声明。
例如:typedef int Length;
Length为int的别名
Length a,b; 相当于 int a, b;
typedef long int64_t; //long原来名字,int64_t别名 (重载已有的类型名字,新名字的含义更清晰,,具有可移植性)
typedef struct ADate { //struct ADate原来名字,Date简化后的名字
int month;
int day;
int year;
} Date;
/*
或
typedef struct ADate Date;
*/
int64_t i = 100000000000;
Datee d = {9, 1, 2005};
typedef *char[10] Strings //String 是10个字符串的数组的类型
<2>联合
#include<stdio.h>
typedef union{
int i;
char ch[sizeof(int)];
}CHI;
int main(int argc, char const *argv[])
{
CHI chi;
int i;
chi.i = 1234;
for (i = 0; i<sizeof(int); i++)
{
printf("%02hhX", chi.ch[i]); //02不够2位数就用0补齐,超过时就显示实际的数, hhx的意思是只输出2位数,即便超了也只显示两位数
}
printf("\n");
return 0;
}
存储:所有的成员共享一个空间,同一时间只有一个成员是有效的,union的大小是其最大的成员
初始化:只对第一个成员做初始化
十七,宏定义
(1)编译预处理指令
1,编译预处理语句以#开头
2,每个预处理命令独占一行
3,语句末尾无分号
4,预处理需要有宏,条件编译和文件包含
5,#define用来定义一个宏
注:它们不是C语言的成分,但是C语言程序不可以离开它们
带参数的宏的原则
1,一切都要括号
2,整个只要括号
3,参数出现的每个地方都要括号
例:#define RADTODEG(x)((x) * 57.29578)
1431

被折叠的 条评论
为什么被折叠?



