前言
本文主要是对作者学到的知识进行的一个总结,方便以后遗忘时可以回来看看。如果帮助到大家,实属荣幸,如果有不足之处大家也可以在评论中提出来,互相学习互相增长,随时更新,谢谢大家。
提示:以下是本篇文章正文内容,下面案例可供参考
一、C代码的基础框架
.c 结尾的是C语言的源程序。
#include <stdio.h>
int main()
{
printf("hello world!!\n");
return 0;
}
.h 译为head,表示头文件。stdio.h表示standard input output是标准输入输出头文件。对于头文件与函数的关系,我们可以联想成工具箱与工具,方便记忆。
“< >”是Linux系统自带的头文件,而自己的写的头文件用 " “,比如"my.h” 。
“;”代表一句话的结束,其功能是在屏幕上打印输出字符串。
int是整型,一种C语言的数据类型,后面会详细说明。
main是函数函数体开始,函数的返回值类型是int,() 里面放的main函数的参数列表。需要注意的是一个程序只能有一个入口函数main。
“printf”是一个函数,格式化输出函数。
“\n”是一种换行符。
" "表达的是字符串, " "之间写什么,屏幕上就原封不动打印输出什么。
return是返回值的意思,返回值是0,是main函数体的结束。
二、变量与常量
1.数值类型
1.1-基本类型
1.1.1-整型int
(unsigned-无符号) (short int)/short:占用字节2,比特数16,取值范围:
-32768-32767,带unsigned:0-32767*2=65535。
(unsigned-无符号)int:占用字节4,比特数32,取值范围:
-2147483648-2147483647,带unsigned:0-2147483647*2=4294967295。
(unsigned-无符号)long int(long):占用字节8,比特数32,取值范围:
-2147483648-2147483628,带unsigned:0-2147483628*2=4294967295
以上类型,对应输出符号都为%d。
1.1.2-浮点型float
float:所占字节4,比特数32,有效数字6~7,对应输出符号为%f。
double:所占字节8,比特数64,有效数字15~16,对应输出符号为%lf。
long double:所占字节16,比特数64,有效数字18~19,对应输出符号%lf。
.2f:结果保留两位小数。
1.1.3-字符型char
(unsigned-无符号)char:所占字节1,比特数8,取值范围-128127,无符号0255,对应输出符号%c。
string:字符串类型,可理解成字符型数组,内部容量根据实际需求确定,对于输出符号%s。
字符串常量与静态变量类似,都是程序结束时才被释放。
同时,字符有其对应的ASCII码,
‘0’ -‘9’~48-57
‘A’-‘Z’~65-90
‘a’-‘z’~97-122
1.1.4-枚举型enum
enum:枚举变量只能被赋予枚举值。枚举值会被默认标号,从0开始,依次递增。
enum 枚举名
{
枚举值1,
枚举值2,
枚举值3,
…………
}枚举变量表列(a,b,c……);
1.1.5-指针型
*+any(例:int *a),指针类型包含很多,常见的有int型、char型、struct型等。指针常量只有唯一的一个空地址NULL。
1.2-构造类型
1.2.1-数组
一维数组:
最简单的数组,语法为“数组类型 数组名[数组内容个数]”由一个集合构成,标号从0开始。
例:int a[3],则调用数组内部成员分别通过a[0]、a[1]、a[2]调用。
二维数组:
多维数组中,最简单的数组,内部结构可理解成矩阵,语法为“数组类型 数组名[行数][列数]”,调用内部成员方式与一维数组类似,只不过多了描述行和列的位置。
例:int a[2][2],内部结构为两行两列的二维数组,调用第一行第二列的语法为a[0][1]。
1.2.2-结构体
用户自定义数据类型的一种,语法结构为:
struct 结构体名
{
数据类型 成员名1;
数据类型 成员名2;
…………
}结构体变量表列;(可写可不写,与普通变量一起定义也可以)
例:
struct Stu
{
int age;
char sex;
char* name;
}e1,e2;
或
struct Stu
{
int age;
char sex;
char* name;
};
struct Stu s1;
1.2.3-共用体
用户自定义类型的另一种,与语法结构为:
union Stu
{
int age;
char sex;
char *name;
};
创建变量的方法与结构体相同,唯一不同的是,共用体内存由其最大的成员决定。
2.常量
多指存在于代码中的内容不固定的一个类型的数值名。
例:int a;——定义了一个整型变量a。
char b=‘c’;——定义了一个字符型’’变量b,其值为‘c’。
3.变量
3.1-const
使用const定义的常量,之后不能被改变,做参数也是。
语法规则:int const a;
或:const int a;
对于指针
int * const a;与const int *a/int const *a;是不同的,前者是指针常量,不能改变a的值;后者是常量指针,可改变其指向,但不能改变其指向的变量的值。
3.2-define
一种进行符号替换的关键字,通常与头文件放在一起。
语法结构:
#define A 10 ——让代码中,所有的A的值都为10
。
3.3-typedef
用于给一种数据类型定义新名字的关键字。
例:typedef signed char s8——给有符号字符型取名为s8
之后便可使用新名字命名:s8 a;——定义了一个有符号字符型变量a。
当对结构体使用typedef时,需要注意。
typedef struct Stu
{
成员表列
……
}STU,*PSTU;
此时,在主函数中可以通过STU定义普通结构体变量,使用*PSTU定义指针结构体变量。
3.4-static
static关键字声明的静态变量存储在数据段(也称全局区)。未初始化时其值为0存储在数据段的未初始化区,初始化时存储在数据段的初始化区。
修饰局部变量,称静态变量,作用域不变,生命周期被延长,直至整个程序结束,如果被调用多次执行的是同一个变量,值初始化一次,未初始化默认值为0。
修饰全局变量,变量只能在本文件调用,不能被其他文件调用。
修饰函数,只能在本文件中使用,不能被其他文件调用。
若想在其他文件中调用,就需要使用extern进行外部声明。
静态变量在声明后,除非在外部文件中使用extern声明后可以调用,其余情况下只能在本文件中使用,并且在程序结束时才被销毁。
例:
static int a = 10;
或
static void add()
{
printf(“1+1=2”);
}
使用static声明后也可以看作将该块内容保护起来,不能被其他文件调用或修改。
4.作用域
4.1-局部变量
在主函数内部定义的变量都属于局部变量,仅在主函数内部有效。每个函数的参数也属于局部变量,作用域仅限于当前函数内。
4.2-全局变量
(extern可加可不加。)在任何函数外部定义的变量都是全局变量,在整个代码中都有效。
5.存储模型
5.1-自动
一般没有特别声明的变量,都属于自动型变量,auto可写可不写。同时具有动态存储期、代码块的作用域、空连接。
例:int a; auto int a; 二者是一样的。
5.2-寄存器
使用修饰符register声明的变量属于寄存器存储类。具有自动存储器、代码块作用域和空连接。
需要注意的是,不能对该类性的变量使用“&”,因为他存储在cpu的寄存器中。
5.3-静态、空连接
使用static修饰的变量属于静态空连接存储类,使用静态存储方式。所有全局变量都是静态变量,而局部变量只有定义时加上类型修饰符static,才为局部静态变量。
空连接指该变量的作用域是定义它的代码块。
使用static定义的全局变量属于静态全局变量。
使用static定义的局部变量属于静态局部变量,生存期与为整个程序执行期间,作用域与局部变量相同,只能在定义该变量的函数内使用该变量。
5.4-静态、外部链接
未使用static描述的的全局变量属于静态、外部链接存储类,具有静态存储时期、文件作用域和外部链接。在使用外部变量的函数中使用extern关键字来再次声明,若在其他文件中定义的,则必须使用extern。
外部链接:外部链接的变量可以在多个文件中使用。
5.5-静态、内部链接
使用static描述的全局变量属于静态、内部链接存储类,仅能被与他在同一文件的函数使用。
内部链接:内部链接的变量只能在一个文件中使用。
6.预处理
6.1-预定义
一些之前定义好的一些符号,用于表示各种信息。
例:
FILE 表示正在与编译的源文件名
LINE 表示文件当前行的行号
FUNCTION 表示当前所在的函数名
DATE 表示预编译文件的日期
TIME 表示预编译文件的时间
STDC 如果编译器遵循ANSIC,则值为1
6.2-宏定义
define的具体应用。
无参数宏定义:
例:#define M (y + 3),代码中的“(y+3)”都可由M代替。
有参数宏定义:
例:#define M(y) y+3,代码中的“y+3”都可由M(x)代替,使用时必须传参。
需要注意的是,宏定义无脑替换,定义的什么,表达式就是什么,没有需要自己加括号的情况。
#define X 2
#define Y X+1
printf("result is %d\n",Y*Y);
//结果为2+1*2+1 = 5
6.3-条件编译
语法结构为:
#if 条件
………
#endif
例:
#ifdef DEBUG
int i;
for ( i = 0 ; i < 5 ; i++ )
{
printf("%d\n",a[i]);
}
#endif
7.进制转换
简单方法:
八进制-%o、十进制-%d、十六进制-%x/%X,若在八进制与十六进制前加“#”,则在每个数前显示“0”。
复杂方法:
十进制转二进制——先跟2取余,再除2,直至除的结果为0
十进制转八进制——先跟8取余,再除8,直至除的结果为0
十进制转十六进制——先跟16取余,再除16,直至除的结果为0
二进制转八进制——三个一组,每组按421算值, 例:010001->010 001->021
二进制转十进制——从最右侧开始以0开始依次递增1到最左端结束,然后2取标号的幂相加,例:10001100->22+23+2^7
二进制转十六进制——四个一组,每组按8421算值,
例:10100010->1010 0010->0xA2
8.获取随机值
语法结构
头文件:#include<time.h> ——只为能使用time(NULL);
语句:srand(time(NULL));
int z=rand()%n;——对n取余表示随机获取n之前的值。
原理
time()是获取1970年至今的差数,srand()是获取一组随机数,srand(1)是一组,srand(2)又是一组。
而rand()从刚才获取的一组随机数。
三、运算符
1.算术运算符
“+”加法运算符 int a = 3 + 5; //a = 8;
“-”减法运算符 int b = 3 - 5; //b = -2;
“*”乘法运算符 int c = 3 * 5; //c = 15;
“/”除法运算符 int d = 5 / 3; //d = 1;
“%”模运算符(求余运算) int e = 5 % 3; //e = 2;
“,”逗号运算符
例:s=2; d=3; a=12+(s+2,d+4);先算括号内的值:s+2=4,d+4=7;括号内应为(4,7),括号内取值只取最后一个,如果没有括号则取第一个;a=12+7=19。
2.关系运算符
“<”小于
“<=”小于等于
“>”大于
“>=”大于等于 //(1)(2)(3)(4)优先级相同(高)
“==”等于
“!=”不等于 //(5)(6)优先级相同(低)
3.逻辑运算符
“&&”逻辑与 // (a>b)&&(x>y)
“||”逻辑或 // (a>b)||(x>y)
“! ”逻辑非 // ! (a > b) ###举例:if(!a)
对于“&&”,当第一个条件表达式成立时,需要看第二个,第二个也正确,结果为1否则为0;当第一个不成立时,不需要再看第二个,结果为0。
对于“||”,当第一个条件不成立时,需要看第二个,第二个也不成立,结果为0否则为1;当第一个条件成立时,不需要看第二个,结果为1。
4.sizeof()
作用:求变量或数据类型所占内存空间的大小,以字节为单位。
若为字符串测量,包含了‘\0’。
5.优先级
算数运算符>移位运算符>条件运算符>按位运算符>赋值
括号成员第一:()、[]、->、.、
全体单目(操作数只有一个)第二:!、~、++、–、-、(类型转换)、、&、sizeof()
乘除余三:、/、%
加减四:+、-
移位五:>>、<<
关系六:<、<=、>、>=
等于不等排第七:=、!=
位与、异或、和位或“三分天下”八九十:第八“&”、第九“^”、第十“|”
逻辑或跟与十二和十一:第十一“&&”、第十二“||”
条件高于赋值:十三“ ? : ”、十四“=、+=、-=、*=、/=、%=、>>=、<<=、&=、^=、|=”
逗号运算级最低。:“,”
四、程序结构与控制语句
1.输出语句
1.1-格式化输出
int printf( const char *fort mat,……);
在代码中,我们直接用
printf(“变量输出符 转义字符……杂七杂八……”,变量表列);
例:
printf(“%d , %f \n……”,a,b,……);
1.2-字符输出函数
int putchar(int c);
在标准输出上显示一个字符,putchar(……);
例:
putchar(a);putchar(‘\n’);
2.输入语句
2.1-格式化输入函数
按照自己设置的输出格式输出。
scanf(“变量输出符……”,&(取地址符)参数表列……);
例:
scanf(“%d %f……”,&a,&c……);或scanf(“%d:%f……”,&a,&c……);
在输入时需要按照引号内部的格式输入。
2.2-字符输入函数
int getchar(void);
在键盘上都一个字符,包括\n(enter)。
例:
getchar();
3.选择语句
3.1-if、else if、else
语法格式
if(判定条件)
{
}
else if(判定条件)
{
}
else if(判定调价){
}
……(等等else if)
else{
}
不写花括号,if只识别其下面第一条语句。
3.2-switch
语法格式
switch(整形表达式)
{
case 目标值1(变量):
操作语句;
break;
case 目标值2:
操作语句;
break;
…………
default:
操作语句;
break;
}
default是都不满足才执行。
当case没有break时,switch里的条件会从满足往后都会执行一遍,包括了default。
4.循环语句
4.1-while
先判断在操作。
while(条件语句)
{
}
只要满足条件就一直执行。
例:
while(a<5) 或 while(1)
{ {
a++; //死循环
} }
4.2-do-while
先操作,在判断。
do
{
}while(条件语句);
例:
do
{
}while(a<3);
4.3-for
语法结构
for(变量或直接赋初值;条件语句;执行后需要的操作)
{
}
例:
for(int a; a<5;a++)
{
printf(“ %d \n”,a);
}
for的无限循环——for( ; ; ){}。
5.转向语句
5.1-continue
用于跳过本次循环,进入下一次循环。
5.2-break
用于循环语句或switch中,用于结束循环或选择。
跳出循环还可以用return、goto等。当处于多层循环中,使用一次break只跳出最内层循环,以此类推。
五、数组
1.一维数组
1.1-语法结构
存储类型 数据类型 数组名[数组下标]
例:int a[10]、char c[10]、……
1.2-内存分配
占用连续空间,数组名是起始地址,对数组名使用sizeof可得出数组占用的总空间。
地址 数组
0XB8F00000 a[0]
0XB8F00004 a[1]
0XB8F00008 a[2]
0XB8F0000C a[3]
0XB8F00010 a[4]
………… ……
对于数组长度,可以通过“sizeof(数组名)/sizeof(数组类型)”或“sizeof(数组名)/sizeof(数组的第一个元素)”求得。在这里,sizeof(数组名)求得的是整个数组的大小。
1.3-初始化
1) 直接初始化:如int a[5]={1,2,3,4,5},当所有变量都被赋值“[]”内的数可以不写。
2) 部分初始化:int a[5]={1,2},其余值会被赋值为0
3) 库函数初始化:memset(a,0,sizeof(a));,将数组用0填充。
4) 循环初始化:for(int i;i<3;i++){ scanf(“%d”,&a);}。
1.4-引用
数组名 [下标]
例:a[5]=3;
1.5-应用
1.5.1-冒泡排序
第一轮先将第一个数与第二个数进行比较,若大于或小于则进行换位,否则不操作,接着将第二个数与第三个数进行比较,以此类推,第一轮结束,最大或最小的值会被放在最后。随后一直进行至最后一位开始即可。
//x指数组总大小。
for (int i = 0; i < x; i++)
{
for (int j = 0; j < x-(i+1); j++)
{
if(a[j]>a[j+1])
{
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}
1.5.2-选择
先将首位依次与其他位比较,如果大于或小于则进行换位,否则不操作,比较完成再将下一位依次与其他位比较。
//x指数组总大小。
for (int i = 0; i < x-1; i++)
{
for (int j = i+1; j < x; j++)
{
if(a[i]>a[j])
{
t=a[i];
a[i]=a[j];
a[j]=t;
}
}
}
2.多维数组
多维数组以二维数组为例,多维数组用法可由二维数组类推而得。
2.1-语法结构
存储类型 数据类型 数组名[数组行下标][数组列下标]
2.2-内存分配
二维数组由多个一维数组组成,在内中存放时:
以a[1][3]为例
地址 数组
0XBFF58A90 int a[0][0]
0XBFF58A94 int a[0][1]
0XBFF58A98 int a[0][2]
0XBFF58A9C int a[1][0]
0XBFF58AA0 int a[1][1]
0XBFF58AA4 int a[1][2]
而我们理解二维数组时,通常通过矩阵加深理解。
以a[3][3]为例。
A[0] A[0][0] A[0][1] A[0][2]
A[1] A[1][0] A[1][1] A[1][2]
A[2] A[2][0] A[2][1] A[2][2]
2.3-初始化
降维按行初始化
int a[2][3] = {{1,2,3},{4}};
//只初始化了部分数据,其余都是0
按线性存储初始化
int a[2][3] = {1,2,3,4};
//没有初始化的,都是0
可省行数初始化
int a[][3] = {{1,2,3},{4,5,6}};
3.字符数组
大多数情况下与一维数组、二维数组相同,但需要注意的是,字符数组未初始化的值会被赋为‘\0’,而且当使用“”来定义一个字符数组时,一个字符数组以‘\0’结尾。比如,“abcde”看似有五个字符,其实有6个。
当前字符数组长为6,则a[5]是‘\0’,如果初始化或赋值时,最后一位被覆盖会出现内存访问越界的错误。
4.字符串
是以‘\0’为结束字符的一组字符。
4.1-定义
定义
char name[]= “akai”;——长度为5,因为有结束字符\0,。
char name[] = {“apple”};
4.2-输入输出
除了基本的,通过循环输入输出,还可通过scanf和printf进行输入输出,使用“%s”作为标识符,使用字符串名字为数组首地址。
例:scanf(“%s”,&name);
printf(“%s”,name);
使用循环遍历时,可以把“a[i]!= ‘\0’”作为结束条件。
还可以通过“gets(name);/puts(name);”进行输入输出。直接对字符串进行输入输出。
4.3-字符串处理函数
4.3.1-strcpy-字符串拷贝函数
strcpy(dest,src);//将src拷贝至dest中,返回值是目标串的起始地址。
4.3.2-strcat-字符串连接
strcat(dest,src);//将src的内容加至dest末尾,
//要注意dest的空间需要足够大。
4.3.3-strcmp-字符串比较
strcmp(s1,s2);//比较s1和s2,二者相等返回值=0;
//s1大于s2返回值>0;s2大于s1返回值<0。
4.3.4-strlen-字符串长度
strlen(s1);//测s1字符串长度,不含结束标志。
4.3.5-strtok-字符串分解
strtok(s,delim);//以delim的字符串作为分隔符,分割s,
//返回值为分解出的字符串地址。
4.3.6-atoi-转换数字字符串
int num = atoi(a);//将数字字符串转换成数字。
总结
2022.08.12——本次更新了控制语句和数组,下一次会更新指针,敬请期待。