前言
提示:/*该文章作为个人学习且分享使用,若有侵权,请联系我删除*/
本文章起名为初识C语言,顾名思义,即简单地、浅显地知晓一下C语言,大概需要学到哪些知识,不做深层的解读,本文章适合初学者进行学习,有错误还请私信我纠正。
提示:以下是本篇文章正文内容,下面案例可供参考
一、什么是C语言?
语言我们大家都知道,像我们现实生活中交流都需要用汉语语言来沟通学习交流,那什么是C语言?C语言通俗来讲,就是人与计算机进行交流,是一门通用的计算机编程语言,广泛应用于底层的开发,像底层的软件开发,如操作系统、驱动层软件的开发。
计算机C语言的发展历史:最初的计算机语言是利用2进制(机器语言)来编写,用2进制来编写太复杂了,于是人们便采用了助记符来编写程序,以此发展到汇编语言,而后发展到B语言,最后发展成现在的C语言。
C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。
C语言是一门面向过程的计算机编程语言,与C++,Java等面向对象的编程语言有所不同。
其编译器主要有Clang(MacOS系统)、GCC(Linux系统)、WIN-TC、SUBLIME、MSVC(Microsoft Visual C++,用于Windows系统 )等
二、第一个C语言程序
#include <stdio.h> int main() { printf("hello world\n"); return 0; }
程序的运行从main函数开始,在整个工程中,main函数只存在一个。
三、基本数据类型
char //字符数据类型
short //短整型
int //整形
long //长整型
long long //更长的整形
float //单精度浮点数
double //双精度浮点数
基本的数据类型会被分为有符号(signed)和无符号(unsigned)两大类。一般写的数据类型没有在前面注明(unsigned char)的情况下,默认为有符号类型。
那么有符号的数据类型和无符号的数据类型有什么区别?
区别就是在内存的存储中,符号位是1还是0,具体的还请翻阅数据存储及内存相关的知识。在这个章节咱们先了解即可。
1. 有符号整型家族
咱们试着在编译器中用**sizeof()
**(sizeof()是一个关键字,它是一个编译时运算符,用于判断变量或数据类型的字节大小。)来打印各种基本数据类型的大小。
2. 无符号整型家族
3. 浮点类型家族
以上基本数据类型的单位都是字节(byte),数据存储中是以“字节”(Byte)为单位,数据传输大多是以比特(bit)为单位,一个位就代表一个0或1(即二进制),每8个位(bit,简写为b)组成一个字节(Byte,简写为B),是最小一级的信息单位。
4.C语言基本单位的换算
那么C语言中,有哪些单位,这些单位之间又是如何转换运算呢?
Byte -->1 Byte = 8 bit
KB --> 1KB = 1024Byte
MB --> 1MB = 1024KB
GB --> 1GB = 1024MB
TB --> 1TB = 1024GB
PB --> 1PB = 1024TB
……
四、变量和常量
1.变量
定义格式:数据类型+变量名 = 字面值(XXX) ;
int age = 50; float weight = 130.5f; char name = “张三”;
(局部)变量在创建时未初始化一般会给随机值,但是有的编译器会报错。为了避免这样的错误,我们一般会在创建时就给初始值。
int main() { int a = 0; // 在定义变量的同时,我们给上初始值,一般给上0 return 0 }
变量的命名规则
只能由字母(包括大写和小写)、数字和下划线( _ )组成。
不能以数字开头。
长度不能超过63个字符。
变量名中区分大小写的。
变量名不能使用关键字
注意:在起变量名时不能太随意,变量名最好见名知意。
变量的分类
全局变量
局部变量
局部变量:局部变量是在函数内部定义的变量,只能在函数内部或者局部变量所在的局部范围内使用。
全局变量:是在函数外部定义的变量(没有定义在某一个函数内),适用于整个工程,所有函数内部都可以使用这个变量。
当局部变量和全局变量同名的时候,则局部变量优先。
用代码说明如下:
#include <stdio.h> int gl_val = 123;//全局变量 int main() { int local = 234;//局部变量 //下面定义的global会不会有问题? int gl_val = 456;//局部变量 与全局变量不冲突 printf("gl_val = %d\n", gl_val); // gl_val = 456 return 0; }
变量的作用域和生命周期
作用域:
作用域(scope)是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效可用的而限定这个名字的可用性的代码范围就是这个名字的作用域。
局部变量的作用域是变量所在的局部范围。
全局变量的作用域是整个工程。
这里就出现报错,局部变量b,出了所在的局部范围再打印b,程序会报错,出现在44行。
生命周期:
变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段
- 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。
- 全局变量的生命周期是:整个程序的生命周期。
int main() { { int a = 10; printf("%d\n", a); //仅在局部范围内打印 } printf("%d\n", a);//出了局部范围,变量a生命周期结束。 return 0; }
2.常量
- 字面常量
const
修饰的常变量d(本质还是一个变量,相当于用const给上了一把锁,不能直接被修改)#define
定义的标识符常量- 枚举常量
int main() { //1.字面常量 //100;//整型字面值 //'w';//字符字面值 //3.14;//浮点型的字面值 //"abcdef";//字符串常量 //2. const 修饰的常变量 //const 是常属性的 const int num = 10;//num本质上是个变量,但是具有常属性,不能被修改 printf("%d\n", num);//10 num = 20;//这里会报错,不能直接被修改 //printf("%d\n", num);//20 /* //数组 //const int n = 10; //int arr[n] = {0};//n虽然被const修饰,具有了常属性,不能被修改, //但是本质上还是变量,所以不能用来指定数组的大小 //下面的代码在支持C99的编译器上可以编译的 //C99中,引入了:变长数组的概念,变长数组的大小是可以使用变量来指定的,但是数据不能初始化。 //VS2019是不支持C99中的变长数组的,所以没法验证 //int n = 10; //int arr[n]; */ //int main() //{ // int n = 10; // int arr[n];//变长数组 // int i = 0; // for (i = 0; i < n; i++) // { // arr[i] = i; //向arr数组放进i的值 // } // for (i = 0; i < n; i++) // { // printf("%d ", arr[i]); //打印arr数组的值 // } // // return 0; //} }
int main() { //3.define 定义的标识符常量 #define MAX 10000 ///可以写在源文件顶部,也可以写在函数内部 MAX = 20000;//这里也不能做修改 printf("MAX = %d\n",MAX); return 0; }
//4.枚举常量 enum RGB // 声明一个三原色的枚举常量red,green,blue { //red, //此时没给值的话,系统会自动分配为0 //green,//1 //blue //2 red = 10, green, blue }; int main() { enum RGB r = red; printf("%d\n",red); //10 printf("%d\n",green);//11 printf("%d\n",blue);//12 return 0; }
五、字符串+转义字符+注释
1.字.符串
“hello world”
这种由双引号(Double Quote)引起来的一串字符称为字符串字面值(String Literal),或者简称字符串。
'\0'
是字符串的结束标志
int main() { char arr1[] = "abcde";//用字符数组存一组字符串 char arr2[] = {'a','b','c','d','e'};//以另一种方式表达字符数组 printf("%s\n",arr1);//打印abcde printf("%s\n",arr2);//打印abcde+随机值 //为什么呢? //arr1里存的是字符串,而字符串末尾隐含一个‘\0’,这个‘\0’是字符串结束的标志,所以会直接打印abcde //arr2存放的是字符,它需要在内存中去寻找‘\0’,直到寻找到‘\0’才结束打印,所以在打印abcde之后会随机打印一些随机值,所以会出现乱码 }
如果我们在arr2数组的后面添加个‘\0’,这时在‘e’后面找到了\0,就会结束打印
\0
不占据字符串长度,但占据内存空间长度
int main() { //strlen 是一个库函数,专门用来求字符串长度的 char arr1[] = "abc"; char arr2[] = {'a', 'b', 'c'}; int len = strlen(arr1); printf("%d\n", len);//这里长度是3, 在计算字符串长度的时候 \0 是结束标志,不算作字符串长度 len = strlen(arr2); printf("%d\n", len);//长度不是15,而是一个随机值 //sizeof 是一个运算符,用来获取某个数据类型或者变量所占用空间的字节数 printf("arr1的长度是%d",sizeof(arr1));//arr1的长度是4个字节,'\0'占据一个字节的空间 return 0; }
转义字符
int main() { printf("abcd\0ef"); return 0; }
什么是转义字符,其实我们在上面就讲过,‘\0’
就是一个转义字符,在0的前面添加一个反斜杠,就会改变它原有的含义,此时它的含义就不是0这个单纯的值了,而是作为结束符来使用,此时的“abcd\0ef”
打印出来就是abcd
。
打印出单引号和双引号
#include<stdio.h> int main() { /*这样写就会报错 printf(""");\\前两个双引号成对,而后面那个引号则落单了 printf(''');\\前两个单引号成对,而后面那个引号则落单了 */ printf("\""); printf("\n"); //转义字符换行 printf("\'"); return 0; }
更多常见转义字符,详细见表格。
\ddd
和 \xhh
表示什么意思呢?
转换它为十进制,所对应的ASCII码表中的字符。
int main() { /* \ddd d是一个0~7的八进制数字(但不能超过ACII码表所表示的范围),ddd表示是三位八进制数字 比如说\130 算出它的十进制为88,88所对应的ACII码表的字符为X \xhh h是一个0~f的十六进制的数字,hh表示两个十六进制数字 比如说\x30 算出它的十进制为48,48所对应的ASCII码表的字符为0 */ printf("%c",'\130'); //x printf("%c",'\x30'); //0 return 0; }
注释
哪些情况下我们可以使用注释呢?
代码中有不需要的代码可以直接删除,也可以注释掉
代码中有些代码比较难懂,可以加一下注释文字来解释它
注释有两种风格:
C语言风格的注释 /xxxxxx/
缺陷:不能嵌套注释
C++风格的注释 //xxxxxxxx
可以注释一行也可以注释多行
六、选择语句
1.if语句和switch语句
if语句的语法格式为:
if(条件判断)
{
条件判断为真,就执行该大括号里的内容
}else
{
条件判断为假,执行此括号里的内容
}
#include<stdio.h> int main() { printf("好好努力敲代码吗?(1/0)\n"); int a; scanf("%d",&a); if(1 == a) { printf("未来拿到高薪offer"); }else { printf("未来吃土"); } return 0; }
if……else多分支语句
if(条件判断1)
{
条件判断1为真执行此大括号内的语句;
}else if(条件判断2)
{
条件判断2为真执行此大括号内的语句;
}else if(条件判断3)
{
条件判断3为真执行此大括号内的语句;
}else{
以上条件判断皆为假则执行此大括号内的语句
}
#include<stdio.h> int main() { printf("请输入你的成绩(0-100)\n"); int score; scanf("%d", &score); if (score == 100) { printf("恭喜你获得了满分,奖励你100人民币!"); } else if (score >= 80 && score < 100) { printf("成绩优异,奖励你50人民币!"); } else if (score >= 60 && score < 80) { printf("成绩合格,继续努力。"); } else if (score >= 0 && score < 60) { printf("成绩不合格,需要重修!"); } else { printf("输入有误,请重新输入!"); } return 0; }
2. switch语句
switch语句的语法格式如下
switch(变量表达式){
case 常量表达式1:语句1;
case 常量表达式2: 语句2;
case 常量表达式3: 语句3;
…
case 常量表达式n: 语句n;
default: 语句n+1;
}
当变量表达式所表达的量与其中一个case语句中的常量相符时,就执行此case语句后面的语句,并依次下去执行后面所有case语句中的语句,除非遇到break;语句跳出switch语句为止。如果变量表达式的量与所有case语句的常量都不相符,就执行default语句中的语句
int main () { char grade = 'B'; switch(grade) { case 'A' : printf("很棒!\n" ); break; case 'B' : case 'C' : printf("做得好\n" ); break; case 'D' : printf("您通过了\n" ); break; case 'F' : printf("最好再试一下\n" ); break; default : printf("无效的成绩\n" ); } printf("您的成绩是 %c\n", grade ); // 做得好 // 您的成绩是B return 0; }
七、循环控制语句
循环语句:
while语句
for语句
do……while语句
1.while语句
while循环的语法形式为
while (表达式)
{
执行内容(循环体);
}
当表达式为真,则执行下面的循环体;循环体执行完之后再判断表达式是否为真,如果为真,再次执行下面的循环体;然后再判断表达式是否为真……就这样一直循环下去,直到表达式为假,就跳出循环。
#include <stdio.h> int main() { /*假设你从今天开始,一直敲代码,直到总代码量达到5万行,你就可以拿到一个高薪offer 这里我们用while语句实现*/ printf("努力敲代码\n"); int line = 0; while (line <= 50000) { line++; printf("%d:继续努力敲代码\n",line); } if (line >= 50000) printf("拿到高薪offer\n"); return 0; }
2.for语句
for 循环的一般形式为:
for(表达式1; 表达式2; 表达式3)
{
执行内容(循环体);
}
它的运行过程为:
先执行“表达式1”。 再执行“表达式2”,如果它的值为真(非0),则执行循环体,否则结束循环。
执行完循环体后再执行“表达式3”。
重复执行步骤 2和 步骤3,直到“表达式2”的值为假,就结束循环
#include <stdio.h> int main(){ int i, sum=0; for(i = 1/*表达式①*/; i <= 100/*表达式②*/; i++/*表达式③*/){ sum += i; } printf("%d\n",sum); return 0; }
3. do……while语句
do……while
语句的语法格式为:
do
{
循环体;
}while(表达式);
do …… while
循环与 while
循环不同的是:先执行一次语句,再判断表达式是否为真,然后决定是否再执行一次语句或者表达式为假跳出循环。
#include <stdio.h> int main() { /* 局部变量定义 */ int a = 10; /* do 循环执行,在条件被测试之前至少执行一次 */ do { printf("a 的值: %d\n", a); a = a + 1; }while( a < 20 ); return 0; }
八、 控制语句
注:break不能用于除循环语句和switch语句之外的任何其他语句中
break 语句:终止循环或 switch 语句,程序会跳出循环体,将继续执行紧接着的语句或switch 的下一条语句。
continue 语句:结束本次循环,即跳过循环体中下面尚未执行的语句,接着进行下一次是否执行循环的判定。
goto 语句: 将控制转移到被标记的语句。但是不建议在程序中使用 goto 语句
九、函数
介绍两个常用的输入输出函数
1.scanf和printf函数
讲一讲scanf()函数和printf()函数,这两个函数是C语言中常用的函数,为输入输出函数,两个函数使用前均需要使用头文件#include <stdio.h>(standard input &output,意为标准输入输出)
printf函数:用于向标准输出设备按规定格式输出信息。
scanf函数:是格式输入函数,即按用户指定的格式从键盘上把数据输入到指定的变量之中
scanf函数
# include<stdio.h> int main() { int x = 0; int y = 0; //在scanf函数中""后的数据为待输入的数据,""里的内容,为待打印格式 //&为取地址符,表示变量存储的地址,即表示通过键盘输入的数据 //"%d"和"%f"为输入打印格式字符, //%d表示十进制整型数据 //%f表示浮点型数据 scanf("%d %f",&x,&y) //x的输入为整型数据 , y的输入为浮点型数据 return 0; }
有关scanf函数的返回值问题
#include<stido.h> int main() { int a = 0; int b = 0; //读取到几个值就返回多少 //这里读取到两个数据,返回值为2 scanf("%d %f",&x,&y) //x的输入为整型数据 , y的输入为浮点型数据 return 0; }
scanf读取数据,如果返回正常的话,返回的是读取到的数据的个数 。
如果读取失败,那么返回的是EOF
,全称为“End Of File”(文件的结束标志),
EOF
对应的值是多少?在编译器中输入EOF并点击转到定义,可以看出它的值为-1。
那么scanf的返回值有什么用呢?
可以适用于多次输入、多组输入的标准,如何编写?以以下题目为例
据说智商140以上者称为天才,KiKi想知道他自己是不是天才,请帮他编程判断。输入一个整数表示一个人的智商,如果大于等于140,则表明他是一个天才,输出“Genius”
输入描述要求:多组输入,每行输入包括一个整数表示的智商。
输出描述要求:针对每行输入,输出“Genius”
#include<stido.h> int main() { int iq = 0; /* while( scanf("%d",&iq) == 1) //每输入一次输入返回值为1 { if(iq >= 140) printf("Genius\n"); } */ /*多组输入*/ while( scanf("%d",&iq) != EOF) //每输入一次输入返回值为1 { if(iq >= 140) printf("Genius\n"); } return 0; }
printf函数
printf函数使用输出有两种格式,一种是直接引用字符串的形式输出,第二种类似于scanf函数,以格式化字符串的形式输出。
1.第一种,直接进行输出,不按需求格式化,引用格式为:printf(“输出数据\n”);
#include<stido.h> int main() { printf("Hello,World!")//这里字符串里的数据写的是什么屏幕就打印什么。 return 0; }
2.第二种格式化字符串进行输出,引用格式为:printf(" 格式化字符串 ", 待输出参数 )
#include<stido.h> int main() { /*以下printf中的%d和%f为输出打印格式字符,a和b为待打印的参数*/ int a = 1; printf("%d\n",a); //1 float b = 2; printf("%f\n",b);//2.000000 return 0; }
更多格式字符见以下表格
2. 自定义函数
/**仅先了解有返回值的函数&*/。
函数有什么用呢?
比如说:
求两个数的和,我们平常最直接的方法是按以下方法写
#include<stido.h> int main() { int m = 0; int n = 0; //输入 scanf("%d %d",&m,&n); //求两个数之和 int sum = m + n; //输出 printf("%d",sum); return 0; }
如果需要再写几个加法呢,我们需要再定义几个变量如以上方法去写吗?太过于麻烦了!
这时我们直接写一个函数,再需要几次,直接调用几次使用就行。
那么如何把加法的功能写成函数呢?
#include<stido.h> int Add(int a,int b) //创建函数 { int z = a + b; //计算 return z; } int main() { int m = 10; int n = 20; int sum = Add(m,n); //调用函数 printf("%d",sum); return 0; }
#include<stido.h> int Add(int a,int b) //创建函数 { int z = a + b; //计算 return z; } int main() { int m = 10; int n = 20; int sum = Add(m,n); //调用函数 printf("%d",sum); return 0; }
如何理解这个加法计算的函数的过程呢?
观察以下流程图,我们可以把函数类比成工厂,工厂中的原材料A和原材料B看成函数中的传进的参数m与n,工厂里的加工操作则可以看成是函数中的计算,再经过加工处理之后,也就生产出可以售卖给自己的产品,同样如此,函数经过在内部的计算之后,得到的结果就是通过return返回z值,调用函数,才能将得到的结果传到sum中,再通过sum打印出来。