C语言
概述
#include <stdio.h>
int main(int argc, const char * argv[])
{
printf("Hello, World!\n");
return 0;
}
return
return代表函数执行完毕,返回return代表函数的终止
如果main定义的时候前面是int,那么return后面就需要写一个整数;如果main定义的时候前面是void,那么return后面什么也不需要写
在main函数中return 0代表程序执行成功,return -1代表程序执行失败
int main()和void main()在C语言中是一样的,但C++只接受int main这种定义方式
include
#include的意思是头文件包含,#include <stdio.h>代表包含stdio.h这个头文件
使用C语言库函数需要提前包含库函数对应的头文件,如这里使用了printf()函数,需要包含stdio.h头文件
#include< > 与 #include ""的区别:
< > 表示系统直接按系统指定的目录检索
"" 表示系统先在 "" 指定的路径(没写路径代表当前路径)查找头文件,如果找不到,再按系统指定的目录检索
C代码编译成可执行程序经过4步.c
:
预处理:宏定义展开、头文件展开、条件编译等,同时将代码中的注释删除,这里并不会检查语法(.i
)
编译:检查语法,将预处理后文件编译生成汇编文件(.s
)
汇编:将汇编文件生成目标文件(二进制文件)(.o
)
链接:C语言写的程序是需要依赖各种库的,所以编译之后还需要把库链接到最终的可执行程序中去()
32个关键字
数据类型关键字(12个)
char、short、int、long、float、double、unsigned、signed、struct、union、enum、void
控制语句关键字(12个)
if、else、switch、case、default、for、do、while、break、continue、goto、return
存储类关键字(5个)
auto、extern、register、static、constant
其他关键字(3个)
sizeof、typedef、volatile
变量
声明变量不需要建立存储空间,如:extern int a;
。定义变量需要建立存储空间,如:int b;
。
#include <stdio.h>
int main(int argc, const char* argv[])
{
{
//extern 关键字只做声明,不能做任何定义
//声明一个变量a,a在这里没有建立存储空间
extern int a;
//a = 10; //err, 没有空间,就不可以赋值
int b = 10; //定义一个变量b,b的类型为int,b赋值为10
return 0;
}
}
define、const
#include <stdio.h>
#define MAX 10 //声明了一个常量,名字叫MAX,值是10,常量的值一旦初始化不可改
int main()
{
int a; //定义了一个变量,其类型为int,名字叫a
const int b = 10; //定义一个const常量,名为叫b,值为10
//b = 11; //err,常量的值不能改变
//MAX = 100; //err,常量的值不能改变
a = MAX;//将abc的值设置为MAX的值
a = 123;
printf("%d\n", a); //打印变量a的值
return 0;
}
通过 #define
定义的常量,是根据值来匹配数据类型的。const修饰的常量是不安全,可以通过指针来修改。
进制
#include <stdio.h>
int main()
{
int a = 123; //十进制方式赋值
int b = 0123; //八进制方式赋值, 以数字0开头
int c = 0xABC; //十六进制方式赋值
//如果在printf中输出一个十进制数那么用%d,八进制用%o,十六进制是%x
printf("十进制:%d\n", a);
printf("八进制:%o\n", b); //%o,为字母o,不是数字
printf("十六进制:%x\n", c);
return 0;
}
sizeof
sizeof不是函数,所以不需要包含任何头文件,它的功能是计算一个数据类型的大小,单位为字节。sizeof的返回值为size_t。size_t类型在32位操作系统下是unsigned int,是一个无符号的整数。
#include <stdio.h>
int main()
{
int a;
int b = sizeof(a);//sizeof得到指定值占用内存的大小,单位:字节
printf("b = %d\n", b);
size_t c = sizeof(a);
printf("c = %u\n", c);//用无符号数的方式输出c的值
return 0;
}
int
打印格式
%hd 输出short类型
%d 输出int类型
%l 输出long类型
%ll 输出long long类型
%hu 输出unsigned short类型
%u 输出unsigned int类型
%lu 输出unsigned long类型
%llu 输出unsigned long long类型
代码
#include <stdio.h>
int main()
{
short a = 10;
int b = 10;
long c = 10l; //或者10L
long long d = 10ll; //或者10LL
printf("sizeof(a) = %u\n", sizeof(a));
printf("sizeof(b) = %u\n", sizeof(b));
printf("sizeof(c) = %u\n", sizeof(c));
printf("sizeof(c) = %u\n", sizeof(d));
printf("short a = %hd\n", a);
printf("int b = %d\n", b);
printf("long c = %ld\n", c);
printf("long long d = %lld\n", d);
unsigned short a2 = 20u;
unsigned int b2 = 20u;
unsigned long c2 = 20ul;
unsigned long long d2 = 20ull;
printf("unsigned short a = %hu\n", a2);
printf("unsigned int b = %u\n", b2);
printf("unsigned long c = %lu\n", c2);
printf("unsigned long long d = %llu\n", d2);
return 0;
}
有符号数是最高位为符号位,0代表正数,1代表负数。
#include <stdio.h>
int main()
{
signed int a = -1089474374; //定义有符号整型变量a
printf("%X\n", a); //结果为 BF0FF0BA
//B F 0 F F 0 B A
//1011 1111 0000 1111 1111 0000 1011 1010
return 0;
}
无符号数最高位不是符号位,而就是数的一部分,无符号数不可能是负数。无符号数,可以增大数的表达最大值。
#include <stdio.h>
int main()
{
unsigned int a = 3236958022; //定义无符号整型变量a
printf("%X\n", a); //结果为 C0F00F46
return 0;
}
char
字符变量实际上并不是把该字符本身放到变量的内存单元中去,而是将该字符对应的ASCII编码放到变量的存储单元中。char的本质就是一个1字节大小的整型。
#include <stdio.h>
int main()
{
char ch = 'a';
printf("sizeof(ch) = %u\n", sizeof(ch));
printf("ch[%%c] = %c\n", ch); //打印字符
printf("ch[%%d] = %d\n", ch); //打印‘a’ ASCII的值
char A = 'A';
char a = 'a';
printf("a = %d\n", a); //97
printf("A = %d\n", A); //65
printf("A = %c\n", 'a' - 32); //小写a转大写A
printf("a = %c\n", 'A' + 32); //大写A转小写a
ch = ' ';
printf("空字符:%d\n", ch); //空字符ASCII的值为32
printf("A = %c\n", 'a' - ' '); //小写a转大写A
printf("a = %c\n", 'A' + ' '); //大写A转小写a
return 0;
}
float、double
#include <stdio.h>
int main()
{
//传统方式赋值
float a = 3.14f; //或3.14F
double b = 3.14;
printf("a = %f\n", a);
printf("b = %lf\n", b);
//科学法赋值,e3相当于1000,e-3相当于0.001
a = 3.2e3f; //3.2*1000 = 32000,e可以写E
printf("a1 = %f\n", a);
a = 100e-3f; //100*0.001 = 0.1
printf("a2 = %f\n", a);
a = 3.1415926f;
printf("a3 = %f\n", a); //结果为3.141593
return 0;
}
类型限定符
//extern:声明一个变量,extern声明的变量没有建立存储空间
extern int a;
//const:定义一个常量,常量的值不能修改。
const int a = 10;
//volatile 防止编译器优化代码
//register 定义寄存器变量,提高效率。register是建议型的指令,而不是命令型的指令,如果CPU有空闲寄存器,那么register就生效,如果没有空闲寄存器,那么register无效。
字符串常量
字符串是内存中一段连续的char空间,以'\0'
(数字0)结尾。
每个字符串的结尾,编译器会自动的添加一个结束标志位'\0'
,即 "a"
包含两个字符'a'
和'\0'
。
运算符
C语言的比较运算中,“真”用数字“1”来表示,“假”用数字“0”来表示。
-> 对象指针->成员名 //成员选择(指针)
& &变量名 //取地址运算符
三目运算符
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
int c;
c = (a > b ? a : b);
printf("c = %d\n", c);
return 0;
}
冒泡排序
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
int arr[10] = { 7,4,2,3,5,8,9,6,1,10 };
int len = sizeof(arr) / sizeof(arr[0]) - 1;
//冒泡排序 从小到大
for (int i = 0; i <= len; i++)
{
for (int j = 0; j < len - i; j++)
{
if (arr[j] < arr[j + 1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
for (int i = 0; i < 10; i++)
{
printf("%d\n", arr[i]);
}
system("pause");
return EXIT_SUCCESS;
}
goto语句
无条件跳转,尽量少用。
#include <stdio.h>
int main()
{
goto End; //无条件跳转到End的标识
printf("aaaaaaaaa\n");
End:
printf("bbbbbbbb\n");
return 0;
}
数组
数组就是在内存中连续的相同类型的变量空间。同一个数组所有的成员都是相同的数据类型,同时所有的成员在内存中的地址是连续的。
#include <stdio.h>
int main()
{
int a[10];//定义了一个数组,名字叫a,有10个成员,每个成员都是int类型
//a[0]…… a[9],没有a[10]
//没有a这个变量,a是数组的名字,但不是变量名,它是常量
int i = 0;
for (i = 0; i < 10; i++)
{
a[i] = i; //给数组赋值
}
//遍历数组,并输出每个成员的值
for (i = 0; i < 10; i++)
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
一维数组的初始化
在定义数组的同时进行赋值,称为初始化。全局数组若不初始化,编译器将其初始化为零。局部数组若不初始化,内容为随机值。
int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//定义一个数组,同时初始化所有成员变量
int a[10] = { 1, 2, 3 };//初始化前三个成员,后面所有元素都设置为0
int a[10] = { 0 };//所有的成员都设置为0
//[]中不定义元素个数,定义时必须初始化
int a[] = { 1, 2, 3, 4, 5 };//定义了一个数组,有5个成员
数组名
数组名是一个地址的常量,代表数组中首元素的地址。
#include <stdio.h>
int main()
{
int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//定义一个数组,同时初始化所有成员变量
printf("a = %p\n", a);
printf("&a[0] = %p\n", &a[0]);//相等的
int n = sizeof(a); //数组占用内存的大小,10个int类型,10 * 4 = 40
int n0 = sizeof(a[0]);//数组第0个元素占用内存大小,第0个元素为int,4
//遍历数组
int i = 0;
for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
数组元素个数:
int (size_t) unsigned int 个数 = sizeof(数组名)/sizeof(数组元素 | 数组数据类型)
数组地址
int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//定义一个数组,同时初始化所有成员变量
printf("a = %p\n", a);
printf("&a[0] = %p\n", &a[0]);
一维数组的最值
#include <stdio.h>
int main()
{
int a[] = { 1, -2, 3,-4, 5, -6, 7, -8, -9, 10 };//定义一个数组,同时初始化所有成员变量
int i = 0;
int max = a[0];
for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
if (a[i] > max)
{
max = a[i];
}
}
printf("数组中最大值为:%d\n", max);
return 0;
}
一维数组的逆置
#include <stdio.h>
int main()
{
int a[] = { 1, -2, 3,-4, 5, -6, 7, -8, -9, 10 };//定义一个数组,同时初始化所有成员变量
int i = 0;
int j = sizeof(a) / sizeof(a[0]) - 1;
int tmp;
while (i < j)
{
tmp = a[i];
a[i] = a[j];
a[j] = tmp;
i++;
j--;
}
for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
printf("%d ", a[i]);//10 -9 -8 7 -6 5 -4 3 -2 1
}
printf("\n");
return 0;
}
冒泡法排序
#include <stdio.h>
int main()
{
int a[] = { 1, -2, 3,-4, 5, -6, 7, -8, -9, 10 };//定义一个数组,同时初始化所有成员变量
int i = 0;
int j = 0;
int n = sizeof(a) / sizeof(a[0]);
int tmp;
for (i = 0; i < n - 1; i++)
{
for (j = 0; j < n - i - 1; j++)//内循环的目的是比较相邻的元素,把大的放到后面
{
if (a[j] > a[j + 1])
{
tmp = a[j];
a[j] = a[j + 1];
a[j + 1] = tmp;
}
}
}
for (i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
二维数组
//常量表达式1表示第一维下标的长度,常量表达式2表示第二维下标的长度。
类型说明符 数组名[常量表达式1][常量表达式2]
在内存中并不存在二维数组,二维数组实际的硬件存储器是连续编址的,也就是说内存中只有一维数组,即放完一行之后顺次放入第二行,和一维数组存放方式是一样的。
实现
#include <stdio.h>
int main()
{
//定义了一个二维数组,名字叫a
//由3个一维数组组成,这个一维数组是int [4]
//这3个一维数组的数组名分别为a[0],a[1],a[2]
int a[3][4];
//给数组每个元素赋值
int i = 0;
int j = 0;
int num = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
a[i][j] = num++;
}
}
//遍历数组,并输出每个成员的值
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
printf("%d, ", a[i][j]);
}
printf("\n");
}
return 0;
}
二维数组的初始化
//分段赋值
int a[3][4] = {{ 1, 2, 3, 4 },{ 5, 6, 7, 8, },{ 9, 10, 11, 12 }};
//连续赋值
int a[3][4] = { 1, 2, 3, 4 , 5, 6, 7, 8, 9, 10, 11, 12};
//可以只给部分元素赋初值,未初始化则为0
int a[3][4] = { 1, 2, 3, 4};
//所有的成员都设置为0
int a[3][4] = {0};
//[]中不定义元素个数,定义时必须初始化
int a[][4] = { 1, 2, 3, 4, 5, 6, 7, 8};
数组名
数组名是一个地址的常量,代表数组中首元素的地址。
#include <stdio.h>
int main()
{
//定义了一个二维数组,名字叫a。二维数组是本质上还是一维数组,此一维数组有3个元素。每个元素又是一个一维数组int[4]
int a[3][4] = { 1, 2, 3, 4 , 5, 6, 7, 8, 9, 10, 11, 12 };
//数组名为数组首元素地址,二维数组的第0个元素为一维数组。第0个一维数组的数组名为a[0]
printf("a = %p\n", a);
printf("a[0] = %p\n", a[0]);//二者相等
//测二维数组所占内存空间,有3个一维数组,每个一维数组的空间为4*4。sizeof(a) = 3 * 4 * 4 = 48
printf("sizeof(a) = %d\n", sizeof(a));
//测第0个元素所占内存空间,a[0]为第0个一维数组int[4]的数组名,4*4=16
printf("sizeof(a[0]) = %d\n", sizeof(a[0]));
//测第0行0列元素所占内存空间,第0行0列元素为一个int类型,4字节
printf("sizeof(a[0][0]) = %d\n", sizeof(a[0][0]));
//求二维数组行数,3
printf("i = %d\n", sizeof(a) / sizeof(a[0]));
// 求二维数组列数,4
printf("j = %d\n", sizeof(a[0]) / sizeof(a[0][0]));
//求二维数组行*列总数,12
printf("n = %d\n", sizeof(a) / sizeof(a[0][0]));
return 0;
}
字符数组与字符串
C语言中没有字符串这种数据类型,可以通过char的数组来替代;字符串一定是一个char的数组,但char的数组未必是字符串;数字0(和字符‘\0’等价)结尾的char数组就是一个字符串,但如果char数组没有以数字0结尾,那么就不是一个字符串,只是普通字符数组,所以字符串是一种特殊的char的数组。
#include <stdio.h>
int main()
{
char c1[] = { 'c', ' ', 'p', 'r', 'o', 'g' }; //普通字符数组
printf("c1 = %s\n", c1); //乱码,因为没有’\0’结束符
//以‘\0’(‘\0’就是数字0)结尾的字符数组是字符串
char c2[] = { 'c', ' ', 'p', 'r', 'o', 'g', '\0' };
printf("c2 = %s\n", c2);
//字符串处理以‘\0’(数字0)作为结束符,后面的'h', 'l', 'l', 'e', 'o'不会输出
char c3[] = { 'c', ' ', 'p', 'r', 'o', 'g', '\0', 'h', 'l', 'l', 'e', 'o', '\0' };
printf("c3 = %s\n", c3);
return 0;
}
字符串初始化
#include <stdio.h>
// C语言没有字符串类型,通过字符数组模拟
// C语言字符串,以字符‘\0’, 数字0
int main()
{
//不指定长度, 没有0结束符,有多少个元素就有多长
char buf[] = { 'a', 'b', 'c' };
printf("buf = %s\n", buf); //乱码
//指定长度,后面没有赋值的元素,自动补0
char buf2[100] = { 'a', 'b', 'c' };
printf("buf2 = %s\n", buf2);//buf2 = abc
//所有元素赋值为0
char buf3[100] = { 0 };
//char buf4[2] = { '1', '2', '3' };//数组越界
char buf5[50] = { '1', 'a', 'b', '0', '7' };
printf("buf5 = %s\n", buf5);//buf5 = 1ab07
char buf6[50] = { '1', 'a', 'b', 0, '7' };
printf("buf6 = %s\n", buf6);// 1ab
char buf7[50] = { '1', 'a', 'b', '\0', '7' };
printf("buf7 = %s\n", buf7);// 1ab
//使用字符串初始化,编译器自动在后面补0,常用
char buf8[] = "agjdslgjlsdjg";
//'\0'后面最好不要连着数字,有可能几个数字连起来刚好是一个转义字符
//'\ddd'八进制字义字符,'\xdd'十六进制转移字符
// \012相当于\n
char str[] = "\012abc";
printf("str == %s\n", str);
return 0;
}
字符串追加拼接
#include <stdio.h>
int main()
{
char str1[] = "abcdef";
char str2[] = "123456";
char dst[100];
int i = 0;
while (str1[i] != 0)
{
dst[i] = str1[i];
i++;
}
int j = 0;
while (str2[j] != 0)
{
dst[i + j] = str2[j];
j++;
}
dst[i + j] = 0; //字符串结束符
printf("dst = %s\n", dst);
return 0;
}
随机数
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int main()
{
time_t tm = time(NULL);//得到系统时间
srand((unsigned int)tm);//随机种子只需要设置一次即可
int r = rand();
printf("r = %d\n", r);
return 0;
}
strlen()
#include <string.h>
计算指定指定字符串的长度,不包含字符串结束符‘\0’
。
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "abcdefg";
int n = strlen(str);
printf("n = %d\n", n);
return 0;
}
strcpy_s
include <string.h> char *strcpy_s(char *dest, const char *src);
功能:把src所指向的字符串复制到dest所指向的空间中,’\0’也会拷贝过去。返回值:成功:返回dest字符串的首地址;失败:NULL。
注意:如果参数dest所指的内存空间不够大,可能会造成缓冲溢出的错误情况。
#include <stdio.h>
#include <string.h>
int main()
{
char dest[20] = "123456789";
char src[] = "hello world";
strcpy_s(dest, src);
printf("%s\n", dest);
return 0;
}
strncpy_s
#include <string.h> char *strncpy_s(char *dest, const char *src, size_t n);
把src指向字符串的前n个字符复制到dest所指向的空间中,是否拷贝结束符看指定的长度是否包含’\0’。返回值:成功:返回dest字符串的首地址;失败:NULL。
#include <stdio.h>
#include <string.h>
int main()
{
char dest[20];
char src[] = "hello world";
strncpy_s(dest, src, 5);
printf("%s\n", dest);
dest[5] = '\0';
printf("%s\n", dest);
return 0;
}
strcat_s
#include <string.h> char *strcat_s(char *dest, const char *src);
将src字符串连接到dest的尾部,‘\0’
也会追加过去。返回值:成功:返回dest字符串的首地址;失败:NULL。
#include <stdio.h>
#include <string.h>
int main()
{
char str[20] = "123";
char src[] = "hello world";
strcat_s(str, src);
printf("%s\n", str);
return 0;
}
strncat_s
#include <string.h> char *strncat(char *dest, const char *src, size_t n);
将src字符串前n个字符连接到dest的尾部,‘\0’也会追加过去。返回值:成功:返回dest字符串的首地址;失败:NULL。
#include <stdio.h>
#include <string.h>
int main()
{
char str[20] = "123";
char src[] = "hello world";
strncat_s(str, src,5);
printf("%s\n", str);
return 0;
}
strcmp和strncmp
比较 s1 和 s2 的大小,比较的是字符ASCII码大小。返回值:相等:0; 大于:>0; 小于:<0。
#include <stdio.h>
#include <string.h>
int main()
{
char str1[] = "hello world";
char str2[] = "hello mike";
if (strcmp(str1, str2) == 0)
{
printf("str1==str2\n");
}
else if (strcmp(str1, str2) > 0)
{
printf("str1>str2\n");
}
else
{
printf("str1<str2\n");
}
return 0;
}
#include <stdio.h>
#include <string.h>
int main()
{
char str1[] = "hello world";
char str2[] = "hello mike";
if (strncmp(str1, str2, 5) == 0)
{
printf("str1==str2\n");
}
else if (strncmp(str1, str2, 5) > 0)
{
printf("str1>str2\n");
}
else
{
printf("str1<str2\n");
}
return 0;
}
sprintf_s
#include <stdio.h>
int main()
{
char dst[100] = { 0 };
int a = 10;
char src[] = "hello world";
printf("a = %d, src = %s", a, src);
printf("\n");
int len = sprintf_s(dst, "a = %d, src = %s", a, src);
printf("dst = \" %s\"\n", dst);// dst = " a = 10, src = hello world"
printf("len = %d\n", len);//25
return 0;
}
strchr
#include <string.h> char *strchr(const char *s, int c);
在字符串s中查找字母c出现的位置。返回值:成功:返回第一次出现的c地址;失败:NULL。
#include <stdio.h>
#include <string.h>
int main()
{
char src[] = "ddda123abcd";
char* p = strchr(src, 'a');
printf("p = %s\n", p);
return 0;
}
strstr
#include <string.h> char *strstr(const char *haystack, const char *needle);
在字符串haystack中查找字符串needle出现的位置。返回值:成功:返回第一次出现的needle地址;失败:NULL。
#include <stdio.h>
#include <string.h>
int main()
{
char src[] = "ddddabcd123abcd333abcd";
char* p = strstr(src, "abcd");
printf("p = %s\n", p);//p = abcd123abcd333abcd
return 0;
}
strstr
#include <stdlib.h> int atoi(const char *nptr);
atoi()会扫描nptr字符串,跳过前面的空格字符,直到遇到数字或正负号才开始做转换,而遇到非数字或字符串结束符(‘\0’)才结束转换,并将结果返回返回值。返回值:成功转换后整数
类似的函数有:atof():把一个小数形式的字符串转化为一个浮点数。atol():将一个字符串转化为long类型。
#include <stdio.h>
#include <stdlib.h>
int main()
{
char str1[] = "-10";
int num1 = atoi(str1);
printf("num1 = %d\n", num1);//num1 = -10
char str2[] = "0.123";
double num2 = atof(str2);
printf("num2 = %lf\n", num2);//num2 = 0.123000
return 0;
}
函数
函数的定义
函数定义的一般形式:
返回类型 函数名(形式参数列表)
{
数据定义部分;
执行语句部分;
}
如果没有形参,圆括号内容为空,或写一个void关键字。
函数的形参和实参
形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用。实参出现在主调函数中,进入被调函数后,实参也不能使用。单向传递,只由实参传给形参,而不能由形参传回来给实参。在调用函数时,编译系统临时给形参分配存储单元。调用结束后,形参单元被释放。实参单元与形参单元是不同的单元。调用结束后,形参单元被释放,函数调用结束返回主调函数后则不能再使用该形参变量。实参单元仍保留并维持原值。因此,在执行一个被调用函数时,形参的值如果发生改变,并不会改变主调函数中实参的值。
实参可以是常量、变量或表达式。
函数的声明
函数定义的位置在主调函数之后,则必须在调用此函数之前对被调用的函数作声明。
所谓函数声明,就是在函数尚在未定义的情况下,事先将该函数的有关信息通知编译系统,相当于告诉编译器,函数在后面定义,以便使编译能正常进行。注意:一个函数只能被定义一次,但可以声明多次。
#include <stdio.h>
int max(int x, int y); // 函数的声明,分号不能省略
// int max(int, int); // 另一种方式
int main()
{
int a = 10, b = 25, num_max = 0;
num_max = max(a, b); // 函数的调用
printf("num_max = %d\n", num_max);
return 0;
}
// 函数的定义
int max(int x, int y)
{
return x > y ? x : y;
}
exit
在main函数中调用exit和return结果是一样的,但在子函数中调用return只是代表子函数终止了,在子函数中调用exit,那么程序终止。
分文件编程
max.h文件
extern int max(int a, int b);
max.c文件
int max(int x, int y)
{
return x > y ? x : y;
}
main.c文件
#include <stdio.h>
#include "max.h"
int main()
{
int a = 10, b = 25, num_max = 0;
num_max = max(a, b); // 函数的调用
printf("num_max = %d\n", num_max);
return 0;
}
防止头文件重复包含
方法一:
#ifndef __SOMEFILE_H__
#define __SOMEFILE_H__
// 声明语句
#endif
方法二:
#pragma once
// 声明语句
指针
int i 定义整形变量
int *p 定义一个指向int的指针变量
int a[10] 定义一个有10个元素的数组,每个元素类型为int
int *p[10] 定义一个有10个元素的数组,每个元素类型为int*
int func() 定义一个函数,返回值为int型
int *func() 定义一个函数,返回值为int *型
int **p 定义一个指向int的指针的指针,二级指针
内存地址和指针
将内存抽象成一个很大的一维字符数组。编码就是对内存的每一个字节分配一个32位或64位的编号(与32位或者64位处理器相关)。这个内存编号我们称之为内存地址。
内存中的每一个数据都会分配相应的地址:char:占一个字节分配一个地址;int: 占四个字节分配四个地址。
内存区的每一个字节都有一个编号,这就是“地址”。
如果在程序中定义了一个变量,在对程序进行编译或运行时,系统就会给这个变量分配内存单元,并确定它的内存地址(编号)
指针的实质就是内存“地址”。指针就是地址,地址就是指针。指针是内存单元的编号,指针变量是存放地址的变量。
指针也是一种数据类型,指针变量也是一种变量。指针变量指向谁,就把谁的地址赋值给指针变量。“*”
操作符操作的是指针变量指向的内存空间。
#include <stdio.h>
int main()
{
int a = 0;
char b = 100;
printf("%p, %p\n", &a, &b); //打印a, b的地址
//int *代表是一种数据类型,int*指针类型,p才是变量名
//定义了一个指针类型的变量,可以指向一个int类型变量的地址
int* p;
p = &a;//将a的地址赋值给变量p,p也是一个变量,值是一个内存地址编号
printf("%d\n", *p);//p指向了a的地址,*p就是a的值
char* p1 = &b;
printf("%c\n", *p1);//*p1指向了b的地址,*p1就是b的值
return 0;
}
通过指针间接修改变量的值
#include <stdio.h>
int main()
{
int a = 0;
int b = 11;
int* p = &a;
*p = 100;
printf("a = %d, *p = %d\n", a, *p);//a = 100, *p = 100
p = &b;
*p = 22;
printf("b = %d, *p = %d\n", b, *p);//b = 22, *p = 22
return 0;
}
指针大小
使用sizeof()测量指针的大小,得到的总是:4或8。sizeof()测的是指针变量指向存储地址的大小。
在32位平台,所有的指针(地址)都是32位(4字节)。在64位平台,所有的指针(地址)都是64位(8字节)。
野指针和空指针
指针变量也是变量,是变量就可以任意赋值,不要越界即可(32位为4字节,64位为8字节),但是,任意数值赋值给指针变量没有意义,因为这样的指针就成了野指针,此指针指向的区域是未知(操作系统不允许操作此指针指向的内存区域)。所以,野指针不会直接引发错误,操作野指针指向的内存区域才会出问题。
int a = 100;
int* p;
p = a; //把a的值赋值给指针变量p,p为野指针, ok,不会有问题,但没有意义
p = 0x12345678; //给指针变量p赋值,p为野指针, ok,不会有问题,但没有意义
*p = 1000; //操作野指针指向未知区域,内存出问题,err
但是,野指针和有效指针变量保存的都是数值,为了标志此指针变量没有指向任何变量(空闲可用),C语言中,可以把NULL赋值给此指针,这样就标志此指针为空指针,没有任何指针。NULL是一个值为0的宏常量:
int *p = NULL;
万能指针
void *
指针可以指向任意变量的内存空间:
void* p = NULL;
int a = 10;
p = (void*)&a; //指向变量时,最好转换为void *
//使用指针变量指向的内存时,转换为int *
*((int*)p) = 11;
printf("a = %d\n", a);//11
const修饰的指针变量
指针常量和常量的指针
#include <stdio.h>
int main()
{
int a = 100;
int b = 200;
//指向常量的指针
//修饰*,指针指向内存区域不能修改,指针指向可以变
const int* p1 = &a; //等价于int const *p1 = &a;
//*p1 = 111; //err
p1 = &b; //ok
//指针常量
//修饰p2,指针指向不能变,指针指向的内存可以修改
int* const p2 = &a;
//p2 = &b; //err
*p2 = 222; //ok
return 0;
}
指针和数组
数组名字是数组的首元素地址,但它是一个常量:
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
printf("a = %p\n", a);//a = 0000002A5F6FFB48
printf("&a[0] = %p\n", &a[0]);//&a[0] = 0000002A5F6FFB48
//a = 10; //err, 数组名只是常量,不能修改
指针操作数组元素
#include <stdio.h>
int main()
{
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int i = 0;
int n = sizeof(a) / sizeof(a[0]);
for (i = 0; i < n; i++)
{
//printf("%d, ", a[i]);
printf("%d, ", *(a + i));//1, 2, 3, 4, 5, 6, 7, 8, 9,
}
printf("\n");
int* p = a; //定义一个指针变量保存a的地址
for (i = 0; i < n; i++)
{
p[i] = 2 * i;
}
for (i = 0; i < n; i++)
{
printf("%d, ", *(p + i));//0, 2, 4, 6, 8, 10, 12, 14, 16,
}
printf("\n");
return 0;
}
指针加法运算:指针计算不是简单的整数相加,如果是一个int *
,+1的结果是增加一个int的大小;如果是一个char *
,+1的结果是增加一个char大小。
int a;
int* p = &a;
printf("%d\n", p);//896988804
p += 2;//移动了2个int
printf("%d\n", p);//896988812
char b = 0;
char* p1 = &b;
printf("%d\n", p1);//896988812
p1 += 2;//移动了2个char
printf("%d\n", p1);//896988812
return 0;
通过改变指针指向操作数组元素:
#include <stdio.h>
int main()
{
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int i = 0;
int n = sizeof(a) / sizeof(a[0]);
int *p = a;
for (i = 0; i < n; i++)
{
printf("%d, ", *p);
p++;
}
printf("\n");//1, 2, 3, 4, 5, 6, 7, 8, 9,
return 0;
}
指针减法运算
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int* p2 = &a[2]; //第2个元素地址
int* p1 = &a[1]; //第1个元素地址
printf("p1 = %p, p2 = %p\n", p1, p2);
int n1 = p2 - p1; //n1 = 1
int n2 = (int)p2 - (int)p1; //n2 = 4
printf("n1 = %d, n2 = %d\n", n1, n2);
指针数组,它是数组,数组的每个元素都是指针类型。
//指针数组
int* p[3];
int a = 1;
int b = 2;
int c = 3;
int i = 0;
p[0] = &a;
p[1] = &b;
p[2] = &c;
for (i = 0; i < sizeof(p) / sizeof(p[0]); i++)
{
printf("%d, ", *(p[i]));//1, 2, 3,
}
printf("\n");
多级指针
C语言允许有多级指针存在,在实际的程序中一级指针最常用,其次是二级指针。二级指针就是指向一个一级指针变量地址的指针。
int a = 10;
int* p = &a; //一级指针
*p = 100; //*p就是a
int** q = &p;
//*q就是p
//**q就是a
int*** t = &q;
//*t就是q
//**t就是p
//***t就是a
指针和函数
函数形参改变实参的值
#include <stdio.h>
void swap1(int x, int y)
{
int tmp;
tmp = x;
x = y;
y = tmp;
printf("x = %d, y = %d\n", x, y);//x = 5, y = 3
}
void swap2(int* x, int* y)
{
int tmp;
tmp = *x;
*x = *y;
*y = tmp;
}
int main()
{
int a = 3;
int b = 5;
swap1(a, b); //值传递
printf("a = %d, b = %d\n", a, b);//a = 3, b = 5
a = 3;
b = 5;
swap2(&a, &b); //地址传递
printf("a2 = %d, b2 = %d\n", a, b);//a2 = 5, b2 = 3
return 0;
}
数组名做函数参数
数组名做函数参数,函数的形参会退化为指针。
//void printArrary(int a[10], int n)
//void printArrary(int a[], int n)
void printArrary(int* a, int n)
{
int i = 0;
for (i = 0; i < n; i++)
{
printf("%d, ", a[i]);//1, 2, 3, 4, 5, 6, 7, 8, 9,
}
printf("\n");
}
int main()
{
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int n = sizeof(a) / sizeof(a[0]);
//数组名做函数参数
printArrary(a, n);
return 0;
}
指针做为函数的返回值
#include <stdio.h>
int a = 10;
int* getA()
{
return &a;
}
int main()
{
*(getA()) = 111;
printf("a = %d\n", a);//a = 111
return 0;
}
指针和字符串
char str[] = "hello world";
char* p = str;
*p = 'm';
p++;
*p = 'i';
printf("%s\n", str);//millo world
p = "mike jiang";
printf("%s\n", p);//mike jiang
char* q = "test";
printf("%s\n", q);//test
字符指针做函数参数
#include <stdio.h>
void mystrcat(char* dest, const char* src)
{
int len1 = 0;
int len2 = 0;
while (dest[len1])
{
len1++;
}
while (src[len2])
{
len2++;
}
int i;
for (i = 0; i < len2; i++)
{
dest[len1 + i] = src[i];
}
}
int main()
{
char dst[100] = "hello mike";
char src[] = "123456";
mystrcat(dst, src);
printf("dst = %s\n", dst);//dst = hello mike123456
return 0;
}
const修饰的指针,变量从左往右看,跳过类型,看修饰哪个字符,如果是*
, 说明指针指向的内存不能改变,如果是指针变量,说明指针的指向不能改变,指针的值不能修改。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
//const修饰一个变量为只读
const int a = 10;
//a = 100; //err
//指针变量, 指针指向的内存, 2个不同概念
char buf[] = "aklgjdlsgjlkds";
//从左往右看,跳过类型,看修饰哪个字符
//如果是*, 说明指针指向的内存不能改变
//如果是指针变量,说明指针的指向不能改变,指针的值不能修改
const char* p = buf;
// 等价于上面 char const *p1 = buf;
//p[1] = '2'; //err
p = "agdlsjaglkdsajgl"; //ok
char* const p2 = buf;
p2[1] = '3';
//p2 = "salkjgldsjaglk"; //err
//p3为只读,指向不能变,指向的内存也不能变
const char* const p3 = buf;
return 0;
}
查找”abcd”个数-while
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char* p = "11abcd111122abcd333abcd3322abcd3333322qqq";
int n = 0;
while ((p = strstr(p, "abcd")) != NULL)
{
//能进来,肯定有匹配的子串
//重新设置起点位置
p = p + strlen("abcd");
n++;
if (*p == 0) //如果到结束符
{
break;
}
}
printf("n = %d\n", n);
return 0;
}
查找”abcd”个数-do-while
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char* p = "11abcd111122abcd333abcd3322abcd3333322qqq";
int n = 0;
do
{
p = strstr(p, "abcd");
if (p != NULL)
{
n++; //累计个数
//重新设置查找的起点
p = p + strlen("abcd");
}
else //如果没有匹配的字符串,跳出循环
{
break;
}
} while (*p != 0); //如果没有到结尾
printf("n = %d\n", n);
return 0;
}
求非空字符串元素的个数:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int fun(char* p, int* n)
{
if (p == NULL || n == NULL)
{
return -1;
}
int begin = 0;
int end = strlen(p) - 1;
//从左边开始
//如果当前字符为空,而且没有结束
while (p[begin] == ' ' && p[begin] != 0)
{
begin++; //位置从右移动一位
}
//从右往左移动
while (p[end] == ' ' && end > 0)
{
end--; //往左移动
}
if (end == 0)
{
return -2;
}
//非空元素个数
*n = end - begin + 1;
return 0;
}
int main(void)
{
char* p = " abcddsgadsgefg ";
int ret = 0;
int n = 0;
ret = fun(p, &n);
if (ret != 0)
{
return ret;
}
printf("非空字符串元素个数:%d\n", n);//非空字符串元素个数:14
return 0;
}
字符串反转模型(逆置):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int inverse(char* p)
{
if (p == NULL)
{
return -1;
}
char* str = p;
int begin = 0;
int end = strlen(str) - 1;
char tmp;
while (begin < end)
{
//交换元素
tmp = str[begin];
str[begin] = str[end];
str[end] = tmp;
begin++; //往右移动位置
end--; //往左移动位置
}
return 0;
}
int main(void)
{
//char *str = "abcdefg"; //文件常量区,内容不允许修改
char str[] = "abcdef";
int ret = inverse(str);
if (ret != 0)
{
return ret;
}
printf("str ========== %s\n", str);//str ========== fedcba
return 0;
}
内存管理
类型 作用域 生命周期 存储位置
auto变量 一对{}内 当前函数 栈区
static局部变量 一对{}内 整个程序运行期 初始化在data段,未初始化在BSS段
extern变量 整个程序 整个程序运行期 初始化在data段,未初始化在BSS段
static全局变量 当前文件 整个程序运行期 初始化在data段,未初始化在BSS段
extern函数 整个程序 整个程序运行期 代码区
static函数 当前文件 整个程序运行期 代码区
register变量 一对{}内 当前函数 运行时存储在CPU寄存器
字符串常量 当前文件 整个程序运行期 data段
C代码经过预处理、编译、汇编、链接4步后生成一个可执行程序。
只有c语言将数组放在栈区。
malloc()
#include <stdlib.h>
void *malloc(size_t size);
功能:在内存的动态存储区(堆区)中分配一块长度为size字节的连续区域,用来存放类型说明符指定的类型。分配的内存空间内容不确定,一般使用memset初始化。参数:size:需要分配内存大小(单位:字节)。返回值:成功:分配空间的起始地址,失败:NULL。
free
#include <stdlib.h>
void free(void *ptr);
功能:释放ptr所指向的一块内存空间,ptr是一个任意类型的指针变量,指向被释放区域的首地址。对同一内存空间多次释放会出错。
参数:ptr:需要释放空间的首地址,被释放区应是由malloc函数所分配的区域。返回值:无。
结构体
定义结构体变量的方式:先声明结构体类型再定义变量名;在声明类型的同时定义变量;直接定义结构体类型变量(无类型名)。
结构体类型:指定了一个结构体类型,它相当于一个模型,但其中并无具体数据,系统对之也不分配实际内存单元。
结构体变量:系统根据结构体类型(内部成员状况)为之分配空间。
//结构体类型的定义
struct stu
{
char name[50];
int age;
};
//先定义类型,再定义变量(常用)
struct stu s1 = { "mike", 18 };
//定义类型同时定义变量
struct stu2
{
char name[50];
int age;
}s2 = { "lily", 22 };
struct
{
char name[50];
int age;
}s3 = { "yuri", 25 };
结构体成员的使用
#include<stdio.h>
#include<string.h>
//结构体类型的定义
struct stu
{
char name[50];
int age;
};
int main()
{
struct stu s1;
//如果是普通变量,通过点运算符操作结构体成员
strcpy(s1.name, "abc");
s1.age = 18;
printf("s1.name = %s, s1.age = %d\n", s1.name, s1.age);
//如果是指针变量,通过->操作结构体成员
strcpy((&s1)->name, "test");
(&s1)->age = 22;
printf("(&s1)->name = %s, (&s1)->age = %d\n", (&s1)->name, (&s1)->age);
return 0;
}
结构体数组
#include <stdio.h>
//统计学生成绩
struct stu
{
int num;
char name[20];
char sex;
float score;
};
int main()
{
//定义一个含有5个元素的结构体数组并将其初始化
struct stu boy[5] = {
{ 101, "Li ping", 'M', 45 },
{ 102, "Zhang ping", 'M', 62.5 },
{ 103, "He fang", 'F', 92.5 },
{ 104, "Cheng ling", 'F', 87 },
{ 105, "Wang ming", 'M', 58 } };
int i = 0;
int c = 0;
float ave, s = 0;
for (i = 0; i < 5; i++)
{
s += boy[i].score; //计算总分
if (boy[i].score < 60)
{
c += 1; //统计不及格人的分数
}
}
printf("s=%f\n", s);//打印总分数 s=345.000000
ave = s / 5; //计算平均分数
printf("average=%f\ncount=%d\n\n", ave, c); //打印平均分与不及格人数 average=69.000000 count=2
for (i = 0; i < 5; i++)
{
printf(" name=%s, score=%f\n", boy[i].name, boy[i].score);
// printf(" name=%s, score=%f\n", (boy+i)->name, (boy+i)->score);
}
return 0;
}
结构体套结构体
#include <stdio.h>
struct person
{
char name[20];
char sex;
};
struct stu
{
int id;
struct person info;
};
int main()
{
struct stu s[2] = { 1, "lily", 'F', 2, "yuri", 'M' };
int i = 0;
for (i = 0; i < 2; i++)
{
printf("id = %d\tinfo.name=%s\tinfo.sex=%c\n", s[i].id, s[i].info.name, s[i].info.sex);
}
return 0;
}
结构体赋值
#include<stdio.h>
#include<string.h>
//结构体类型的定义
struct stu
{
char name[50];
int age;
};
int main()
{
struct stu s1;
//如果是普通变量,通过点运算符操作结构体成员
strcpy(s1.name, "abc");
s1.age = 18;
printf("s1.name = %s, s1.age = %d\n", s1.name, s1.age);
//相同类型的两个结构体变量,可以相互赋值
//把s1成员变量的值拷贝给s2成员变量的内存
//s1和s2只是成员变量的值一样而已,它们还是没有关系的两个变量
struct stu s2 = s1;
//memcpy(&s2, &s1, sizeof(s1));
printf("s2.name = %s, s2.age = %d\n", s2.name, s2.age);
return 0;
}
指向普通结构体变量的指针
#include<stdio.h>
//结构体类型的定义
struct stu
{
char name[50];
int age;
};
int main()
{
struct stu s1 = { "lily", 18 };
//如果是指针变量,通过->操作结构体成员
struct stu* p = &s1;
printf("p->name = %s, p->age=%d\n", p->name, p->age);//p->name = lily, p->age=18
printf("(*p).name = %s, (*p).age=%d\n", (*p).name, (*p).age);//(*p).name = lily, (*p).age=18
return 0;
}
堆区结构体变量
#include<stdio.h>
#include <string.h>
#include <stdlib.h>
//结构体类型的定义
struct stu
{
char name[50];
int age;
};
int main()
{
struct stu* p = NULL;
p = (struct stu*)malloc(sizeof(struct stu));
//如果是指针变量,通过->操作结构体成员
strcpy(p->name, "test");
p->age = 22;
printf("p->name = %s, p->age=%d\n", p->name, p->age);
printf("(*p).name = %s, (*p).age=%d\n", (*p).name, (*p).age);
free(p);
p = NULL;
return 0;
}
结构体套一级指针
#include<stdio.h>
#include <string.h>
#include <stdlib.h>
//结构体类型的定义
struct stu
{
char* name; //一级指针
int age;
};
int main()
{
struct stu* p = NULL;
p = (struct stu*)malloc(sizeof(struct stu));
p->name = malloc(strlen("test") + 1);
strcpy(p->name, "test");
p->age = 22;
printf("p->name = %s, p->age=%d\n", p->name, p->age);
printf("(*p).name = %s, (*p).age=%d\n", (*p).name, (*p).age);
if (p->name != NULL)
{
free(p->name);
p->name = NULL;
}
if (p != NULL)
{
free(p);
p = NULL;
}
return 0;
}
结构体普通变量做函数参数
#include<stdio.h>
#include <string.h>
//结构体类型的定义
struct stu
{
char name[50];
int age;
};
//函数参数为结构体普通变量
void set_stu(struct stu tmp)
{
strcpy(tmp.name, "mike");
tmp.age = 18;
printf("tmp.name = %s, tmp.age = %d\n", tmp.name, tmp.age);
}
int main()
{
struct stu s = { 0 };
set_stu(s); //值传递
printf("s.name = %s, s.age = %d\n", s.name, s.age);
return 0;
}
结构体指针变量做函数参数
#include<stdio.h>
#include <string.h>
//结构体类型的定义
struct stu
{
char name[50];
int age;
};
//函数参数为结构体指针变量
void set_stu_pro(struct stu *tmp)
{
strcpy(tmp->name, "mike");
tmp->age = 18;
}
int main()
{
struct stu s = { 0 };
set_stu_pro(&s); //地址传递
printf("s.name = %s, s.age = %d\n", s.name, s.age);
return 0;
}
结构体数组名做函数参数
#include<stdio.h>
//结构体类型的定义
struct stu
{
char name[50];
int age;
};
//void set_stu_pro(struct stu tmp[100], int n)
//void set_stu_pro(struct stu tmp[], int n)
void set_stu_pro(struct stu *tmp, int n)
{
int i = 0;
for (i = 0; i < n; i++)
{
sprintf(tmp->name, "name%d%d%d", i, i, i);
tmp->age = 20 + i;
tmp++;
}
}
int main()
{
struct stu s[3] = { 0 };
int i = 0;
int n = sizeof(s) / sizeof(s[0]);
set_stu_pro(s, n); //数组名传递
for (i = 0; i < n; i++)
{
printf("%s, %d\n", s[i].name, s[i].age);
}
return 0;
}
const修饰结构体指针形参变量
//结构体类型的定义
struct stu
{
char name[50];
int age;
};
void fun1(struct stu* const p)
{
//p = NULL; //err
p->age = 10; //ok
}
//void fun2(struct stu const* p)
void fun2(const struct stu* p)
{
p = NULL; //ok
//p->age = 10; //err
}
void fun3(const struct stu* const p)
{
//p = NULL; //err
//p->age = 10; //err
}
共用体(联合体)
联合union是一个能在同一个存储空间存储不同类型数据的类型;联合体所占的内存长度等于其最长成员的长度,也有叫做共用体;
同一内存段可以用来存放几种不同类型的成员,但每一瞬时只有一种起作用;
共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员的值会被覆盖;
共用体变量的地址和它的各成员的地址都是同一地址。
#include <stdio.h>
//共用体也叫联合体
union Test
{
unsigned char a;
unsigned int b;
unsigned short c;
};
int main()
{
//定义共用体变量
union Test tmp;
//1、所有成员的首地址是一样的
printf("%p, %p, %p\n", &(tmp.a), &(tmp.b), &(tmp.c));//0000003825CFF6B4, 0000003825CFF6B4, 0000003825CFF6B4
//2、共用体大小为最大成员类型的大小
printf("%lu\n", sizeof(union Test));//4
//3、一个成员赋值,会影响另外的成员
//左边是高位,右边是低位
//低位放低地址,高位放高地址
tmp.b = 0x44332211;
printf("%x\n", tmp.a); //11
printf("%x\n", tmp.c); //2211
tmp.a = 0x00;
printf("short: %x\n", tmp.c); //2200
printf("int: %x\n", tmp.b); //44332200
return 0;
}
枚举
枚举:将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。
enum 枚举名
{
枚举值表
};
在枚举值表中应列出所有可用值,也称为枚举元素。枚举值是常量,不能在程序中用赋值语句再对它赋值。枚举元素本身由系统定义了一个表示序号的数值从0开始顺序定义为0,1,2 …。
#include <stdio.h>
enum weekday
{
sun = 2, mon, tue, wed, thu, fri, sat
};
enum bool
{
flase, true
};
int main()
{
enum weekday a, b, c;
a = sun;
b = mon;
c = tue;
printf("%d,%d,%d\n", a, b, c);//2,3,4
enum bool flag;
flag = true;
if (flag == 1)
{
printf("flag为真\n");//flag为真
}
return 0;
}
typedef
为一种数据类型(基本类型或自定义数据类型)定义一个新名字,不能创建新类型。与#define
不同,typedef仅限于数据类型,而不是能是表达式或具体的值。#define
发生在预处理,typedef发生在编译阶段。
#include <stdio.h>
typedef int INT;
typedef char BYTE;
typedef BYTE T_BYTE;
typedef unsigned char UBYTE;
typedef struct type
{
UBYTE a;
INT b;
T_BYTE c;
}TYPE, * PTYPE;
int main()
{
TYPE t;
t.a = 254;
t.b = 10;
t.c = 'c';
PTYPE p = &t;
printf("%u, %d, %c\n", p->a, p->b, p->c);//254, 10, c
return 0;
}