IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C语言之初识C语言(点到为止,两万字文章详细解读!) -> 正文阅读

[C++知识库]C语言之初识C语言(点到为止,两万字文章详细解读!)


前言

提示:/*该文章作为个人学习且分享使用,若有侵权,请联系我删除*/

本文章起名为初识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. 有符号整型家族

类型名称大小(字节数)取值范围
signed char1-2^ 7(-128) ~ 2^7-1(127)
short int 或 short2-2^ 15(-32 768) ~ 2^15-1(32 767)
int4-2^ 31(-2 147 483 648) ~ 2^31-1(2 147 483 647)
long int 或 long4-2^ 31(-2 147 483 648) ~ 2^31-1(2 147 483 647)
long long int 或 long long8-2^ 63(-9.2233720368548e+18) ~ 2^63-1(9.2233720368548e+18)

咱们试着在编译器中用**sizeof()**(sizeof()是一个关键字,它是一个编译时运算符,用于判断变量或数据类型的字节大小。)来打印各种基本数据类型的大小。
在这里插入图片描述

2. 无符号整型家族

类型名称大小(字节)取值范围
unsigned char10 ~ 2^8-1(255)
unsigned short int 或 unsigned short20 ~ 2^16-1(65 535)
unsigned int40 ~ 2^32-1(4 294 967 295)
unsigned long int 或 unsigned long40 ~ 2^32-1(4 294 967 295)
unsigned long long int 或 unsigned long long80 ~ 2^64-1(1.844674407371e+19)

3. 浮点类型家族

类型名称大小(字节)取值范围
float4-/+3.4e38(精确到6位小数)
double8-/+1.7e308(精确到15位小数)
long double12-/+1.19e4932(精确到18位小数)

以上基本数据类型的单位都是字节(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)是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效可用的而限定这个名字的可用性的代码范围就是这个名字的作用域。

  1. 局部变量的作用域是变量所在的局部范围。
  2. 全局变量的作用域是整个工程。

这里就出现报错,局部变量b,出了所在的局部范围再打印b,程序会报错,出现在44行。

生命周期:

变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段

  1. 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。
  2. 全局变量的生命周期是:整个程序的生命周期。
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;
}

五、字符串+转义字符+注释

字符串

“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;
}

在这里插入图片描述
更多常见转义字符,详细见表格。

转义字符释义
?表示一个问号,在书写连续多个问号时使用,防止他们被解析成三字母词
\0常用作字符串的结束标志
\’表示输出一个单引号
\"表示输出一个双引号
\a警告字符,电脑会蜂鸣
\b退格符
\f进纸符
\n换行
\r回车
\t水平制表符
\v垂直制表符
\dddddd表示1~3个八进制数字。如 \130 X
\xhhhh表示两个十六进制数字。 如\x30 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;
}

注释

哪些情况下我们可以使用注释呢?

  1. 代码中有不需要的代码可以直接删除,也可以注释掉
  2. 代码中有些代码比较难懂,可以加一下注释文字来解释它
  3. 注释有两种风格:
    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. 先执行“表达式1”。 再执行“表达式2”,如果它的值为真(非0),则执行循环体,否则结束循环。

  2. 执行完循环体后再执行“表达式3”。

  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;
}

更多格式字符见以下表格

格式化字符释义
%d以十进制形式输出带符号整数(正数不输出符号)
%o以八进制形式输出无符号整数(不输出前缀0)
%x,%X以十六进制形式输出无符号整数(不输出前缀Ox)
%u以十进制形式输出无符号整数
%f以小数形式输出单、双精度实数
%c输出单个字符
%s输出字符串
%p输出指针地址

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;
}

如何理解这个加法计算的函数的过程呢?

观察以下流程图,我们可以把函数类比成工厂,工厂中的原材料A和原材料B看成函数中的传进的参数m与n,工厂里的加工操作则可以看成是函数中的计算,再经过加工处理之后,也就生产出可以售卖给自己的产品,同样如此,函数经过在内部的计算之后,得到的结果就是通过return返回z值,调用函数,才能将得到的结果传到sum中,再通过sum打印出来。
在这里插入图片描述

十、数组

/*这里只简单地概述一下一维数组的内容/
要存储1-10的数字,怎么存储?
C语言中给了数组的定义:一组相同类型元素的集合

1.数组的创建

# include<stdio.h>
int main()
{
	 //数组的创建
	 int arr[5]; //创建一个名为arr的整型数组,数组有5个元素, 每个元素为整型
	 char ch[15]; //创建一个名为ch的字符数组,数组有15个元素,每个元素为字符型
	return 0;
}

2.数组的初始化

# include<stdio.h>
int main()
{
		//数组的初始化
		
		//在初始化变量时,我们一般不知道给什么元素,会暂时都赋值为0
		int a = 0;
		
		//1.同样,当我们在初始化的时候不知道给数组什么元素,我们可以将整型数组赋值为		{0},数组里的每个元素会被初始化为0
		int arr1[5] = {0};
		
		//2.在给定数组一些值时,中括号内规定多少元素,则最多只能存储多少个元素。
		int arr[5] = {1,2,3,4,5};
		//字符数组以下两种方法皆可
		char ch1[3] = "abc";
		char ch2[3] = {'a','b','c'};
		
	return 0;
}

查看数组的元素 [按f10调试->监视窗口]
在这里插入图片描述

#include<stdio.h>
int main()
{
	//数组的不完全初始化
	//给定若干元素,在赋值元素时,没有讲给定的元素全部填充,剩下的元素则会默认被初始化为0
	int arr[10] = {1,2,3,4,5};
	return 0;
}

在这里插入图片描述

3.数组的下标

C语言规定:数组的每个元素都有一个下标,下标是从0开始的。
数组可以通过下标来访问的。

比如:int arr[10] = {1};
如果数组有十个元素,其下标的范围为0 ~ 9
在这里插入图片描述
数组的元素需要通过数组的下标来访问。

# include<stdio.h>
int main()
{
	 int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	 printf("%d",arr[4]);//访问数组的第五个元素,下标为4
	return 0;
}

遍历数组,将数组中的元素全部打印出来

#include <stdio.h>
int main()
{
 int i = 0;
 int arr[10] = {1,2,3,4,5,6,7,8,9,10};
 for(i = 0; i < 10; i++)
 {
       printf("%d ", arr[i]);
 }
 printf("\n");
    return 0;
}

十一、操作符(运算符)

简单地初步认识就行,不作深入了解。

算数操作符:+ ? ?- ? ? * ? ?/ ? ? %

# include<stdio.h>
int main()
{
	int a = 5,b = 10 ,c;
	 c = a + b; //15, +运算符作加法运算
	 c = b - a; //5, -运算符作减法运算
	 c = a * b; //50, *运算符作乘法运算
	 c = b / a; //2, /运算符作除法运算
	 c = b % 3; //1, %运算符作取模运算
	 
	return 0;
}

%操作符只能作用于整数

# include<stdio.h>
int main()
{
 	float m = 10.0f;
 	float n = 3.0f;
 	printf("%f\n",a / b); //3.333333  flaot类型默认打印小数点后六位
 	//printf("%f\n",a % b); //错误的写法,求余运算只能用于整数
	 
	float a = 10 / 3;//当/两边都为整数时,表达式执行的是整数除法,结果商为3余1,
	
	float b = 10.0f / 3;//如果要得到小数,必须保证/两边至少一个操作数是浮点数,结果才是3.3
	//10.0后加上f为float,不加f则默认为double类型
	printf("%f\n",a);//3.000000
	printf("%f\n",b);//3.333333
	return 0;
}

移位操作符:>> ? ? <<
移动的是内存中的二进制位

位操作符:& ? ? |? ? ^
按位与、按位或、按位异或

赋值操作符:= ? ? += ? ? -= ? ? *= ? ? /== ? ? &= ? ? ^= ? ? |= ? ? >>= ? ? <<=

# include<stdio.h>
int main()
{
 	 int a = 0; //初始化
     a = 10;// = 为赋值操作符
     a += 20 ; //可以看成 a = a + 20 ,即a+20得到的值再赋值给a,a的值为30
     //-=、/=、*=、%=同样可以这么理解
	return 0;
}

单目操作符:
? ! ? ? ? ? ? ? 逻辑反操作
? - ? ? ? ? ? ?负值
? + ? ? ? ? ? 正值
?& ? ? ? ? ? 取地址
?sizeof ? ? 操作数的类型长度(以字节为单位)
?~ ? ? ? ?? ? 对一个数的二进制按位取反
?– ? ? ? ? ? ?前置、后置–
?++ ? ? ? ? 前置、后置++
?* ? ? ? ? ? ? 间接访问操作符(解引用操作符)
?(类型) ? ? 强制类型转换

加上!逻辑反操作把真变为假,把假变为真。

#include<stdio.h>
int main()
{
	int flag = 0;
	//在C语言中,0表示为假,非0表示为真
	
	//flag为真打印hehe
	if(flag)
	{
		printf("hehe\n");
	}
	
	//flag为假,打印haha
	if(!flag)
	{
	printf("haha\n");
	}
	return 0;
}

sizeof用来计算变量或者类型的大小

#include<stdio.h>
 int main()
{
	 int a = 10;
	 printf("%d\n",sizeof(a));//4 单位是字节
	 printf("%d\n",sizeof(int));
	 int arr[10] = {0};
	 printf("%d\n",sizeof(arr));//计算的是数组的总大小,单位是字节
	 printf("%d\n",sizeof(arr[0]));//计算数组首元素的大小
	int sz = sizeof(arr)/sizeof(arr[0]);//计算元素的个数
	printf("%d\n",sz);
	return 0;
}

自增(++)和自减(--

#include <stdio.h>
int main()
{	
	//自增和自减用法一样
	//后置--
	int a = 10;
	int b = a--;//后置--,先试用再自减 即int b = a,a = a - 1;
	printf("a = %d b = %d",a,b);// a = 9 b = 10

	//前置--
	int a = 10;
	int b = --a;//前置--,先自减,后使用 即a = a - 1, int b = a;
	printf("a = %d b =%d\n",a,b);
	return 0;
}

()强制类型转换

#include <stdio.h>
int main()
{	
	//一下两种写法都会发生警告
	 int a = 3.14; //精度不够
	 float f = 3.14; //默认为double类型,精度太大
	
	//这里用()强制类型转换操作符
	int a = (int)3.14;
	float f = (float)3.14;
	 
	return 0;
}

关系操作符:
?>
?=
?<
?<=
?!= ????????用于测试“不相等”
?== ?????? 用于测试“相等”

逻辑操作符:
?&& ? ? ? 逻辑与
?|| ? ? ? ? ? 逻辑或

逻辑操作符的运用

#include <stdio.h>
int main()
{
	/*输入一个字母,判断其是否为字母*/
	char input = ' ';
	scanf("%c",&input);
	//这里的&&就是与、并且的意思,而||是或者的意思
	if('a' < input && input < 'z' || 'A' < input && input < 'Z' )
	{
	printf("是字母");
	}else  
	printf("不是字母");
	 
	return 0;
}

条件操作符(三目操作符):
exp1 ? exp2 : exp3
用法:当exp1为真就执行exp2的结果,为假则执行exp3的结果。

#include<stdio.h>
int main()
{
	/*输入两个值,求最大值*/
	 int a = 0;
	 int b = 0;
	 int max = 0;
	scanf("%d %d",a,b);
	//if(a > b)
	//max = a;
	//else
	//max = b;
	
	/*也可以使用条件操作符(三目操作符)来表示*/
	max = (a > b ? a : b);
	printf("%d",max);
	return 0;
}

逗号表达式:
exp1, exp2, exp3,……expN

逗号表表达式的特点是:表达式从左向右依次计算,但是整个表达式的结果为最后一个表达式的结果。

#include<stdio.h>
int main()
{
	 int a = 10;
	 int b = 20;
	 int c = 30;
	 int d = (a += 10,b -= 15,c = a + b);
	 printf("%d",d); //25
	return 0;
}

下标引用、函数调用和结构成员
[ ]??()??. ?? ->

十二、 常见关键字

C语言中提供了32个关键字,而这些关键字是C语言中已经预先设定好的,我们用户自己不能创造关键字。

auto ?break ? case ? char ? const ? continue ?default ?do ? double? else? enum ? extern? float ?for ? goto ? if ?int ? long ? register ? return ? short ?signed ?sizeof ? static ?struct ?switch typedef ? union unsigned ? void ?volatile ?while

循环语句中用到的关键字:

break、continue、do……while、while、for

分支语句关键字:

switch、case、if……else、goto

函数中的返回值:

return

变量中常用到的:

auto、register、static

关键字autoregister

#include<stdio.h>
int main()
{
	auto int a = 10;//局部变量(自动变量),自动变量,自动销毁
	register int num = 100;//建议把100放在寄存器中存储
	return 0;
}

关键字static

static是用来修饰变量和函数的

  1. 修饰局部变量-称为静态局部变量
  2. 修饰全局变量-称为静态全局变量
  3. 修饰函数-称为静态函数

1、修饰局部变量

 #include<stdio.h>
 
 void test()
 {
	int a = 1;
	a++;
	printf("%d ",a);   // 此处代码打印为(10个2)2 2 2 2 2 2 2 2 2 2	
}
 int main()
{
	 int i = 0;
	 while(i < 10)
	 {
		test();
		i++;
	}
	return 0;
}

在局部变量a的前面加上static结果就不一样了

 #include<stdio.h>
 
 void test()
 {
	static int a = 1; //静态变量
	a++;
	printf("%d ",a);   // 此处代码打印为(2到11)2 3 4 5 6 7 8 9 10 11	
}
 int main()
{
	 int i = 0;
	 while(i < 10)
	 {
		test();
		i++;
	}
	return 0;
}

为什么呢?
在内存中,主要分为三个区域,栈区、堆区和静态区域。栈区存放局部变量、形式参数,堆区主要用于动态内存分配,而静态区主要存放静态变量和全局变量。

在这里插入图片描述

一个普通的局部变量是存放在栈区的,而被static修饰的局部变量,是存放在内存的静态区的,本质上改变了在内存中的存储位置,使得局部变量出了作用域不会销毁,影响了变量的生命周期(作用域不受影响)。

2、修饰全局变量
再新建一个add.c的源文件,写入一个全局变量g_val
在这里插入图片描述
我们发现,直接使用会有报错显示“未声明的标识符”,此时在test.c文件中声明一下g_val,就可以运行了。
在这里插入图片描述
全局变量是具有外部链接属性的,在其他源文件内部,只要适当地申明就可以使用。
当我们用static去修饰这个全局变量的时候,它就会报错(无法解析的外部符号),这是因为static修饰的全局变量的外部链接属性消失了,而变成了内部链接属性,只能在自己的.c文件内部使用,其他.c文件内部无法使用。所以本质上是影响了变量的作用域范围
在这里插入图片描述

3.修饰函数
static 修饰函数与修饰全局变量类似
新建一个add源文件,在add源文件中写入一个简单的Add求和函数,函数和全局变量一样也是具有外部链接属性的。

//代码1
//add.c
int Add(int x, int y)
{
    return c+y;
}

//test.c
//声明外部符号 -函数
extern int Add(int , int);
int main()
{
    printf("%d\n", Add(2, 3));
    return 0;
}

static修饰函数后,函数的外部链接属性就变成了内部链接属性,被static修饰的函数只能在自己的.c文件内部使用,其他.c文件内部无法使用,本质上影响了作用域范围。

//代码2
//add.c
static int Add(int x, int y)
{
    return c+y;
}

//test.c
//声明外部符号 -函数
extern int Add(int , int);
int main()
{
    printf("%d\n", Add(2, 3));
    return 0;
}

类型:

union、enum、struct、char、short、int、float、long、double、const、void、sizeof、signed、unsigned、typedef

关键字typedef—类型重命名

#include<stdio.h>

//将unsigned int 重命名为uint, 所以uint也是一个类型名
typedef unsigned int uint;
 
 int main()
{
	 //观察num1和num2,这两个变量的类型是一样的
	unsigned int num1 = 100;
	unit num2 = 200; 
	return 0;
}

十三、define定义的常量和宏

1.定义常量

可以使用#define定义一个标识符来表示一个常量
注:由define定义的常量只能在定义的地方做修改,其他处无法被修改。

格式:#define 标识符 常量值

#include<stdio.h>
//因为不属于语句,所有后面不需要添加分号
#define MAX 10000  //定义整型常量MAX 其值为10000
#define char_str "Hello,world" //定义字符串常量char_str 其值为"Hello,world"
int main()
{
	printf("%d",MAX);//10000
	printf("%s",char_str);//Hello,world
return 0;
}

2.定义宏

也可以使用#define来定义宏

#include<stdio.h>
 //定义宏与定义常量的差异在哪里呢?
 //定义宏需要给予参数,而定义常量是没有参数的
 //宏类似于函数,但是没有参数的数据类型
 #define max(x,y) ((x)>(y)?(x):(y)) //这里的x,y为一个参数,可加可不加。
 									//但是若x或y为一个表达式时,括号就必须加上,保证其准确性。
int main()
{
	int a = 10;
	int b = 20;
	int m = max(a,b); //编译器会自动替换为 int m = (a>b?a:b);
	printf("%d",m);
	return 0;
}

十四、指针

在学习指针之前,我们首先得认识认识一下内存。

内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的 。
所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节
为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址

假设有一栋楼,该楼共有六层,共有三十层房间,在没有门牌号的情况下,如何精准地定位找到自己想去的房间?不好寻找。而在实际生活中,每个房间都有门牌号,这让我们直接就可以找到自己想去的房间,而不至于那么麻烦。
在这里插入图片描述

而在内存中,内存中的每一个内存单元相当于实际生活中的每一个房间,每一个内存单元也有对应的一个编号,而通过这个编号,我们也能快速找到这样一个个小的内存单元,这一个个内存单元的编号被称为地址,也叫做指针
所以我们有这样一概念( 编号 = 地址 = 指针)。
在这里插入图片描述
我们想一下,1个内存单元给多大比较合适呢?
1个字节
为什么要1个字节,而不是1bit、1KB……

如果用char类型来说,如果内存单元为1bit的话,需要8个bit的内存空间,而int类型则需要4*8=32个内存空间,显然,用bit多余了,1KB又太大,而1个字节恰恰合适。
基本的数据类型char类型占1个字节,int类型占4个字节。所以每个内存单元的单位以1个字节最合适。

那么内存单元的编号(地址)是怎么产生的呢?

在32位机器上,有32根地址线(物理电线),电线是通电的,通电之后就有高电平和低电平之分,电信号最终会转换成数字信号,而高电平转换成数字信号为数字“1”,低电平转换成数字信号为数字“0”,由此会产生32个0或者1的随机数字信号,就会组成232个二进制序列,这些组成不同的二进制序列就可以作为内存单元的编号,也就会产生232个地址。

那么232个地址就能管理232个字节的空间,即4294967296个byte,
4294967296byte/1024 = 4194304KB;
4194304KB/1024 = 4096MB;
4096MB/1024 = 4GB;
所以,232个地址最多也就占用4GB的大小内存。

int a = 10,本质就是在内存中申请4个字节大小的空间来存储10。

在这里插入图片描述
如何取到变量a的地址呢?
用&a(&为取地址操作符)表示变量a的地址。
注:a实际占用4个字节的空间,每个字节都有地址,但是&a拿到的是第一个字节的地址编号(也是最小的地址,如图中:0x0012ff40)

&a拿出的是地址,地址也是一个值,如何来存储&a呢,用int* pa = &a来存放地址,此时的pa是一个存放地址(指针)的变量,故pa被称为指针变量
在这里插入图片描述
那么pa仅仅是用来存储地址的吗?其实不然,我们可以通过pa来找到a,用*pa来表示。(此时的*为解引用操作符)

#include <stdio.h>
int main()
{
	int a = 10;
	int* pa = &a;
	printf("%p\n",&a);//%p为打印地址格式符
	printf("%d\n",a);//10
	*pa = 20;//此时a的值被覆盖为20
	printf("%d\n",a);//20
 return 0;
}

除了整型类型的指针之外,其他类型如字符类型的指针,例子如下:

#include <stdio.h>
int main()
{
	 char ch = 'A';
	 char* pc = &ch;
	 *pc = 'q';
	 printf("%c\n", ch);
 return 0;
}

指针变量的大小是多大呢?

指针变量是用来存放地址的,地址在32位机器上,是由32个0或1组成的二进制序列号,故需要32个比特位的空间存储,指针变量就需要四个字节,不论什么数据类型的指针变量,大小都是4个字节
在64位机器上,是由64个0或者1组成的二进制序列号,需要64个比特位的空间存储,指针变量的大小就是8个字节

结论:指针大小在32位平台是4个字节,64位平台是8个字节

我们也可以通过sizeof来计算指针变量的大小

#include <stdio.h>
int main()
{
	//x86(32)位平台上指针变量的大小为4个字节
	int* pa;
	char* ch;
	double* pd;
	printf("%d\n", sizeof(pa)); //4
	printf("%d\n", sizeof(ch)); //4
	printf("%d\n", sizeof(pd)); //4

	return 0;
}

十五、结构体

结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂类型。
比如描述学生,学生包含: 名字+年龄+性别+学号 这几项信息。
描述复杂对象,不能简单的使用单个的内置类型来描述了,这里只能使用结构体来描述。
例如:

struct Student
{
    char name[20];//名字
    int age;      //年龄
    char sex[5];  //性别
    char id[15]//学号
};

结构体的初始化:

 int main()
 {
	struct Student s1 = {"张三",18,"男","12345678"};
	//直接打印结构体成员
	printf("%s %d %s %s\n",s1.name,s1.age,s1.sex,s1.id); //结构体变量.成员
	
	struct Student * ps = &s1;//指针结构体
	printf("%s %d %s %s\n",(*ps).name,(*ps).age,(*ps).sex,(*ps).id);
	printf("%s %d %s %s\n",ps->name,ps->age,ps->sex,ps->id); //结构体指针->成员
	
	//struct Student s2 = {"李四",18,"女","14725836"};
	return 0;
	}

/*以上为初步学习C语言知识部分(点到为止不做深度解读),已完结 。*/

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-12-25 10:47:31  更:2022-12-25 10:50:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/22 19:42:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码