C语言简介及开发环境配置
为什么要学习C语言
C语言的诞生
C语言诞生于美国的贝尔实验室,是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发。
创始时间——>于1972年
创始人——>Dennis M Ritchie(丹尼斯·里奇),C语言之父,UNIX之父。
C语言应用领域
- 系统软件
- 驱动程序
- 数据库
- 图像处理/办公软件
- 嵌入式软件开发
- 游戏软件开发
学好C语言的好处
- 物联网开发、嵌入式软件开发
- Linux系统内核开发
- Linux驱动与应用开发
- 研究算法、数据结构必学语言
- 学习C++/Java/Python等入门语言
第一个C语言程序
//Windows平台
#include<stdio.h>//C语言标准输入输出头文件
int main()//程序的入口函数
{
print("Hello,world!");//输出字符串
reutrn 0;
}
//Linux平台开发
/*打开中断terminal——在桌面创建文件夹(mkdir hellword)——进入文件夹(cd hellword)——通过gedit编辑器编写文件(gedit hw.c)*/
#include<stdio.h>
void main()
{
print("hellow,world!")
}
//GCC编译器运行hw.c文件(gcc hw.c -0 hw)——运行编译后的文件(./hw)
C语言基本语法及程序结构
简单的C程序结构
- 预处理命令
- 变量、语句
- 表达式
- 注释:(块注释/**/行注释//)
#include<stdio.h>//预处理命令
int main()//主函数,程序就是从这里开始执行
{
int x = 10;//定义x为整型变量,且赋值为10
printf("x = %d\n", x);//输出x变量的值
x = 89;
printf("x = %d\n", x);//输出x变量的值
//以分号结尾都称为语句;
x = x + 100;
printf("x = %d\n", x);//输出x变量的值
return 0;//返回值,终止main()函数标记
}
C语言标识符
C语言标识符命名规则:
C语言标识符是用来标识变量、函数,或任何其他用户自定义项目的名称。一个标识符只能以字母A-Z或a-z、数字和下划线组成,第一个字符必须字母或下划线开头。
C语言标识符内不许出现特设符号,比如@、#、!等。C语言区分大小写字母。在C中,Var和VAR是两个不同的标识符。
C语言关键字
C语言中的保留字共计32个,这些保留字不能作为常量名、变量名或其他标识符名称。C99新增5个,C11新增7个。
auto | break | case | char %c | const | continue | default | do |
---|---|---|---|---|---|---|---|
double %lf | else | enum | extern | float %f | for | goto | if |
int %d | long %ld | register | return | short | signed | sizeof | static |
struct | switch | typedef | unsigned | union | void | volatile | while |
C99新增关键字
_Bool | _Complex | _Imaginary | inline | restrict |
---|
C11新增关键字:
_Alignas | _Alignof | _Atomic | _Generic |
---|---|---|---|
_Noreturn | _Static_assert | _Thread_local |
C语言数据类型及输入输出函数
C语言基本数据类型
所谓类型,就是对数据分配存储单元的安排,包括存储单元的长度(占多少字节)以及数据的存储形式不同的类型分配不同的长度和存储形式。
C原因允许使用的数据类型:
- 基本类型:
-
整型类型
基本整型
短整型
长整型
双长整型
字符型
布尔型
-
浮点类型
单精度浮点型
双精度浮点型
复数浮点型
-
枚举类型
-
空类型
-
派生类型
指针类型
数组类型
结构体类型
共用体类型
函数类型
整型数据的分类
最基本的整型类型
- 基本类型(int型):占2或者4个字节
- 短整型(short int):VC++6.0中占2个字节
- 长整型(long int):VC++6.0中占4个字节
- 双长整型(long long int):C99新增
sizeof()函数,求所占的字节数函数
整型变量的符号属性:
整型变量的值的范围包括负数到正数
可以将变量定义为“无符号”类型
扩充的整型类型:
1. 有符号基本整型 [signed] int;
1. 无符号基本整型 unsigned int;
1. 有符号短整型 [signed] short [int];
1. 无符号短整型 unsigned short [int];
1. 有符号长整型 [signed] long [int];
1. 无符号长整型 unsigned long [int];
1. 有符号双长整型 [signed] long long [int];
1. 无符号双长整型 unsigned long long [int].
有符号正数类型
类型名称 | 字节数 | 取值范围 |
---|---|---|
signed char | 1 | -27(-128)~27-1(127) |
short int 或 short | 2 | -2^15(-32 768)~2^15-1(32767) |
int | 4 | -2^31(-2 147 483 648)~2^31-1(2 147 483 647) |
long int 或 long | 4 | -2^31(-2 147 483 648)~2^31-1(2 147 483 647) |
long long int 或 long long | 8 | -2^63(-9 2233720368548e+18)~2^63-1(9 2233720368548e+18) |
浮点类型
类型名称 | 字节数 | 取值范围 |
---|---|---|
float | 4 | _/+3.4e38(精确到6位小数) |
double | 8 | _/+1.7e308(精确到15位小数) |
long double | 12 | _/+1.19e4932(精确到18位小数) |
字符数据
字符是按其代码(整数)形式存储的
C99把字符型数据作为整数类型的一种
字符型数据在使用上有自己的特点
a.字符与字符代码
大多数系统采用ASCII字符集
字母:A-Z(65-90),a-z(97-122)
数字:0-9(48-57)
专门字符:29个:!“ # & ‘ ( )* 等
空格符:空格、水平制表符、换行等
不能显示的字符:空(null)字符(以'\0'表示)、警告(以'\a'表示)、退格(以'\b'表示)、回车(以'\r'表示)等
printf("%d\n",'A');、
b.字符’1‘和整数1是不同的概念
字符‘1’只是代表一个形状为'1'的符号,在需要时按原样输出,在内存中以ASCII码形式存储,占一个字节:00110001
整数1是以整数存储方式(二进制补码方式)存储的,占2个或4个字节:00000000 00000001
c.字符变量
用类型符char定义字符变量
char c = '?';
系统把“?”的ASCII代码63赋值给变量c
浮点型数据
浮点型数据是用来表示具有小数点的实数
float类型(单精度浮点型)
编译系统为flat型变量分配4个字节
数值以规范化的二进制指数形式存放
浮点型数据是用来表示具有小数点的实数
float型(单精度浮点型)
double型(双精度浮点型)
- 编译系统为double型变量分配8个字节
- 15位有效数字
long double(长双精度)型
怎样确定常量的类型
字符常量:由单撇号括起来的单个字符或转义字符
整数常量:不带小数点的数值
系统根据数值的大小确定是int型还是long型等
浮点数常量:凡以小数点形式或指数形式出现的实数
C编译系统把浮点型常量都按双精度处理分配8个字节
输入/输出函数
几乎每一个C程序都包含输入输出,输入输出是程序中最基本的操作之一
-
所谓输入输出是以计算机主机为主体而言的
从计算机向输出设备(如显示器、打印机等)输出数据称为输出
从输入设备(如键盘、磁盘、光盘、扫描仪等)向计算机输入数据称为输入
-
C语言本身不提供输入输出语句
输入和输出操作是由C标准函数库中的函数来实现的
printf和scanf不是C语言的关键字,而只是库函数的名字
putchar、getchar、puts、gets
-
在使用输入输出函数时,要在程序文件的开头用预编译指令
#include<stdio.h>或#include"stdio.h"
用printf函数输出数据scanf函数输入数据
在C程序中用来实现输出和输入的,主要是printf函数和scanf函数:
这两个函数时格式输入输出函数
用这两个函数时,必须指定格式
-
printf函数的一般格式
printf(格式控制,输出列表)
eg:printf("i = %d, c = %c \n", i, c);
-
常用格式字符
d格式符:用来输出一个有符号的十进制整数
可以在格式声明中指定输出数据的域宽
printf("%5d%5d\n",12,-345);
%d输出int型数据
%ld输出long型数据
c格式符:用来输出一个字符
char ch = 'a';
printf("%c",ch);或printf("%5c",ch);
s格式符:用来输出一个字符串
printf("%s","Chain");
f格式符:用来输出实数,以小数形式输出
-
不指定数据宽度和小数位数,用%f
eg:用%f输出实数,只能得到6位小数。
double a = 1.0;
printf("%f\n",a/3);
-
指定数据宽度和小数位数。用%m.nf
printf("%20.15f\n",1/3);
printf("%.0f\n",10000/3.0);
-
输出数据向左对齐,用%-m.nf
float型数据只能保证6位有效数字
double型数据只能保证15位有效数字
计算机输出的数字不都是绝对精确有效的
e格式符:指定以指数形式输出实数
%e,VC++给出小数位数为6位
指数部分占5列
小数点前必须有而且只有1位非零数字
printf("%e",123.456);
输出:1.234560 e+002
%m.ne
printf("%13.2e",123.456);
输出: 1.23e+002(前面有4个空格)
-
-
用scanf函数输入数据
scanf函数的一般格式
scanf(格式控制,地址列表) 格式控制含义同Printf函数/地址列表可以是变量的地址,或字符串的首地址
scanf函数中的格式声明:
与printf函数中的格式声明相似,以%开始,以一个格式字符结束,中间可以插入附加的字符
scanf("a = %f, b = %f, c = %f", &a, &b, &c);
使用scanf函数时应注意的问题
scanf(" %f%f%f",a,b,c);错
scanf(" %f%f%f", &a, &b, &c);对
对于:scanf("a = %f, b = %f, c = %f", &a, &b, &c);
1 3 2 错
a = 1, b = 3, c = 2 对
a = 1 b = 3 c =2 错
对于scanf(" %c%c%c", &c1, &c2, &c3);
abc 对
a b c错
对于scanf(" %d%c%f", &a, &b, &c);
若输入:1234a1230.26
-
字符数据的输入输出
用putchar函数输出一个字符
从计算机向显示器输出一个字符
putchar函数的一般形式为:putchar(c)
eg:先后输出BOY三个字符。
解题思路:
定义3个字符变量,分别赋以初值B、O、Y
用putchar函数输出这3个字符变量的值
/*int a,b,c
scanf_s("a=%d,b=%d,c=%d",&a,&b,&c);
printf("a = %d, b = %d, c = %d", a, b, c);*/
putchar("B")
putchar("O")
putchar("Y")
用getchar函数输入一个字符
向计算机输入一个字符
getchar函数的一般形式为:getchar()
eg:从键盘输入BOY三个字符,然后把他们输出到屏幕。
解题思路:
用3个getchar函数先后从键盘向计算机输入BOY三个字符
用putchar函数输出
C语言常量与变量
变量
在程序运行过程中,其值可以改变的量,称为变量。
C语言变量其实是程序可操作的存储区的名称。C语言中每个变量都有特定的类型,类型决定变量存储的大小和布局,该范围内的值都可以存储在内存中,运算符可应用于变量上。变量命名的规则:由字母、数字和下划线组成,必须以字母或下划线开头。大写字母和小写字母是不同的,因为C是大小写敏感的。
常量
在程序运行过程中,其值不能改变的量,称为常量。
常量可以是任何的基本数据类型,比如整数常量、浮点常量、字符常量,或字符串字面值,也有枚举常量。
整数常量
整数常量可以是十进制、八进制或十六进制的常量。前缀指定基数:0x或0X表示十六进制,0表示八进制,不带前缀则默认表示十进制。
整数常量可以带一个后缀,后缀是U和L的组合,U表示无符号整数(unsigned),L表示长整数(long)。后缀可以是大写,也可以是小写,U和L的顺序任意。
浮点常量
浮点常量由整数部分、小数点、小数部分和指数部分组成。您可以使用小数形式或者指数形式来表示浮点常量。
当使用小数形式表示时,必须包含整数部分、小数部分,或同时包含两者。当使用指数形式表示时,必须包含小数点、指数,或同时包含两者。带符号的指数是用e或E引入的。
字符常量
字符常量是括在单引号中,例如,‘X'可以存储在char类型的简单变量中。
字符常量可以是一个普通的字符(例如’X')、一个转义序列(例如‘\t')。
定义常量
-
#define预处理器
使用#define预处理器定义常量的形式:
#define identifier value
-
const关键字
使用const前缀声明指定类型的常量,如下所示:
const type variable = value;
运算符及存储类型
运算符
运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C语言内置了丰富的运算符,并提供了以下类型的运算符:
- 算术运算符
- 关系运算符
- 逻辑运算符
- 位运算符
- 赋值运算符
- 其它运算符
算术运算符
运算符 | 描述解释 |
---|---|
+ | 把两个操作数相加 |
- | 从第一个操作数中减去第二个操作数 |
* | 把两个操作数相乘 |
/ | 分子除以分母 |
% | 取模运算符,整数后的余数 |
++ | 自增运算符,整数值增加1 |
-- | 自减运算符,整数值减少1 |
++在变量前面先加1后运算,否则先运算后加1
--在变量前面先减1后运算,否则先运算后减1
int a = 10;
printf("\na=%d\n", a++)//先输出a的值为10,然后a这个变量自动加1——>a = 11
printf("a=%d\n", a++)//a这个变量先加1——>a = 12,再输出a的值12
printf("a=%d\n", a++)//先输出a的值为12,然后a这个变量自动加1——>a = 13
关系运算符
运算符 | 描述解释 |
---|---|
== | 检查两个操作数的值是否相等,如果相等则条件为真 |
!= | 检查两个操作数的值是否相等,如果不相等则条件为真 |
> | 检查左操作数的值是否大于右操作数的值,如果是则条件为真 |
< | 检查左操作数的值是否小于右操作数的值,如果是则条件为真 |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真 |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真 |
逻辑运算符
运算符 | 描述解释 |
---|---|
&& | 称为逻辑与运算符。如果两个操作数都非零,则条件为真 |
|| | 称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真 |
! | 称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假 |
位运算符 & | ^ ~ << >>
按位与操作,按二进制位进行“与”运算。运算规则:
0 & 0 = 0、0 & 1 = 0、 1 & 0 = 0、1 & 1 = 1
printf("result = %d\n",3 & 5)//1 3 : 0011 5:0101
按位或运算符,按二进制进行“或”运算。运算规则:
0 | 0 = 0、0 | 1 = 1、 1 | 0 = 1、 1 | 1 = 1
printf("result = %d\n",3 & 5)//7 3 : 0011 5:0101
按位异或运算符,按二进制位进行“异或”运算。运算规则:
0 ^ 0 = 0、0 ^ 1 = 1、 1 ^ 0 = 1、 1 ^ 1 = 0
printf("result = %d\n",3 & 5)//6 3 : 0011 5:0101
按位取反运算符,按二进制位进行“取反”运算。运算规则:
~1 = 0、 ~ 0 = 1
<<二进制左移运算符。将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)(*2)
>>二进制右移运算符。将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃 (/2)
赋值运算符
运算符 | 描述解释 |
---|---|
= | 简单的赋值运算符,把右边操作数的值赋给左边的操作数 |
+= | 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 |
-= | 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 |
*= | 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 |
/= | 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 |
%= | 求模且赋值运算符,求两个操作数的模赋值给左边操作数 |
<<= | 左移且赋值运算符 |
>>= | 右移且赋值运算符 |
&= | 按位与且赋值运算符 |
^= | 按位异或且赋值运算符 |
|= | 按位或且赋值运算符 |
其他运算符
sizeof()返回变量的大小
&返回变量的地址
*指向一个变量
?:条件表达式 如果条件为真?则值为X:否则值为Y
存储类型
存储类定义C语言程序中变量/函数的范围(可见性)和生命周期。这些说明符放置在它们所修饰的类型之前。下面列出C语言程序中可用的存储类:
auto
register
static
extern
auto存储类
auto存储类是所有局部变量默认的存储类。
{
int mount;
auto int month;
}
上边的实例定义了两个带有相同存储类的变量,auto只能用在函数内,即auto只能修饰局部变量。
register存储类
register存储类用于定义存储在寄存器中而不是RAM中的局部变量。这意味着变量的最大尺寸等于寄存器的大小(通常是一个词),且不能对它应用一元的'&'运算符(因为它没有内存位置)
{
register int miles;
}
寄存器只用于需要快速访问的变量,比如计数器。还应注意的是,定义'register'并不意味着变量将被存储在寄存器中,它意味着变量可能存储在寄存器中,这取决于硬件和实现的限制。
static存储类
static存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用static修饰局部变量可以在函数调用之间保持局部变量的值。
static修饰符也可以应用于全局变量。当static修饰全局变量时,会使变量的作用域限制在声明它的文件内。
全局声明的一个static变量或方法可以被任何函数或方法调用,只要这些方法出现在跟static变量或者方法同一个文件中。
#include<stdio.h>
void FuncText();
static int k = 10;//全局变量 static是默认的
void FuncText()
{
static int x = 5;
x++;
printf("x=%d,k=%d\n",x ,k);
}
int main()
{
while(k--)
{
FuncText();
}
return 0;
}
extern存储类
extern存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当您使用extern时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。
当您有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用extern来得到已定义的变量或函数的引用。可以这么理解,extern是用来在另一个文件中声明一个全局变量或函数。
#include<stdi.h>//remain.c
int count;
extern void func()
int main()
{
count = 10;
func();
return 0;
}
#include<stdio.h>//su.c
extern int count;
void func()
{
printf("count is : %d\n",count);
}
if语句与switch语句
if语句
-
if第一种形式
有时我们需要在满足某种条件时进行一些操作,而不满足条件时就不执行任何操作,这个时候我们可以只使用if语句。
语法如下形式为:
if(判断条件){
语句块
}
如果判断条件成立就执行语句块,否则直接跳过。
#include<stdio.h> int main() { int x; printf("\n请输入x的值:"); scanf_s("%d", &x); if(x >= 0) printf("x大于等于0.\n\n"); printf("main函数结束.\n"); return 0; }
-
if-else第二种形式
if和else是两个新的关键字,If意为"如果",else意为"否则",用来对条件进行判断,并根据判断结果执行不同的语句。总结起来,if else的结构为:
if(判断条件){
语句块1
}else{
语句块2
}
如果判断条件成立,那么执行语句块1,否则执行语句块2。
#include<stdio.h> int main() { int age; printf("\n请输入你的年龄:"); scanf_s("%d",&age); if(age >= 18) printf("恭喜,你已经成年。\n\n"); else printf("对不起,你还没有成年。\n\n"); return 0; }
-
多个if else语句
if else 语句也可以多个同时使用,构成多个分支,形式如下:
if(判断语句1){ 语句块1
}else if(判断语句2){ 语句块2
}else if(判断语句3){ 语句块3
}else if(判断语句m){ 语句块m
}else{ 语句块n
}
意思是,从上到下依次检测判断条件,当某个判断条件成立时,则执行其对应的语句块,然后跳到整个if else语句之外继续执行其他代码。如果所有判断条件都不成立,则执行语句块n,然后继续执行后续代码。
也就是说,一旦遇到能够成立的判断条件,则不再执行其他的语句块,所以最终只能有一个语句块被执行。
//编程实现:从键盘输入一个字符,然后判断这个字符是大写字母,还是小写字母,或者是数字。 #include<stdio.h> int main() { char c; printf("请输入C的值:"); scanf_s("%c",&c); if(c < 32) printf("这是一个控制符。\n"); else if(c >= '0' && c <= '9') printf("这是一个数字。\n\n"); else if(c >= 'a' && c <= 'z') printf("这是一个小写字母。\n\n"); else if(c >= 'A' && c <= 'Z') printf("这是一个大写字母。\n\n"); else printf("其它字符。\n\n"); return 0; }
-
C语言嵌套if语句
在C语言中,嵌套if-else语句是合法的,这意味着您可以在一个if或else if语句内使用另一个if或else if语句。
C语言中 嵌套if语句的语法:
if(boolean_expression 1)
{
if(boolean_expression 2)
{/*当布尔表达式2为真时执行*/}
}
您可以嵌套else if...else,方式与嵌套if语句相似。
#include<stdio.h> int main() { int x, y; printf("请输入x,y的值:"); scanf_s("%d,%d",&x,&y); if(x != y) { if(x > y) { printf("x>y.\n"); } else { printf("x<y.\n"); } } return 0; }
switch语句
C语言虽然没有限制if else能够处理的分支数量,但当分支过多时,用if else处理会不太方便,而且容易出现if else配对出错的情况。
switch是另一种选择结构的语句,用来代替简单的、拥有多个分支的if else语句,基本格式如下:
switch(表达式){
case 整型数值1:语句1;
case 整型数值2:语句2;
......
case 整型数值n:语句n;
default:语句n+1;
}
#include<stdio.h>
int main()
{
int x;
printf("请输入星期数字(1——7):");
scanf_s("%d",&x);
switch(x)
{
case 1:printf("Monday.\n");break;
case 2:printf("Tuesday.\n");break;
case 3:printf("Wdnesday.\n");break;
case 4:printf("Thursday.\n");break;
case 5:printf("Friday.\n");break;
case 6:printf("Saturday.\n");break;
case 7:printf("Sunday.\n");break;
default:
printf("输入错误.\n\n");
}
return 0;
}
while循环与for循环
while循环
-
while语句的一般形式如下:
while(表达式)语句
循环条件表达式
表达式计算结构:“真”时执行循环体语句,“假”时不执行。
while循环的特点是:
先判断条件表达式,后执行循环体语句。
#include<stdio.h> int main() { int i = 1, sum = 0; while(i <= 5) { sum = sum + i; i = i + 1; } printf("sum = %d\n\n", sum); reuturn 0; }
-
do---while语句的一般形式为:
do
{
语句块
}while(表达式);
do---while语句的特点:
先无条件地执行循环体,然后判断循环条件是否成立。
#include<stdio.h> int main() { int i = 1, sum = 0; do { sum = sum + i; i = i + 1; }while(i <= 5); printf("sum = %d\n\n",sum); return 0; }
-
while和do while循环比较
while语句第一条件不成立,则循环体语句一次都不执行。
do-while语句第一条件不成立,则循环语句至少会执行一次。
for循环
for语句不仅可以用于循环次数已经确定的情况,还可以用于循环次数不确定而只给出循环结束条件的情况。
for语句完全可以代替while语句。
for语句的一般形式为:
for(表达式1;表达式2;表达式3)
表达式1:设置初始条件,只执行一次。可以为零个、一个或多个变量设置初值执行;
表达式2:循环条件表达式,用来判断是否继续循环。在每次执行循环体前先执行此表达式,决定是否继续执行循环;
表达式3:作为循环的调整期,例如使循环变量增值,它是在执行完循环体后才进行的。
#include<stdio.h>
int main()
{
int i = 1, sum = 0;
for(; i < 100; i++)
sum = sum + i;
printf("sum = %d\n\n",sum);
return 0;
}
break语句和continue语句
- break语句:结束整个循环赛程,不再判断执行循环条件是否成立。
- continue语句:只结束本次循环,而不是终止整个循环的执行。
数组
数组是一组有序数据的集合。数组中各数据的排列是有一定规律的,下标代表数据在数组中的序号。用一个数组名和下标唯一确定数组中的元素,数组中的每一个元素都属于用一个数据类型。
一维数组
一维数组是数组中最简单的:
它的元素只需要用数组名加一个下标,就能唯一确定,要使用数组,必须在程序中先定义数组。
定义一维数组的一般形式为:
类型符 数组名[常量表达式];(数组名的命名规则和变量名相同)
如:int a[10]; int:每个元素的数据类型 a:数组名 10:数组长度
int[4 + 6];合法
int n = 10; int a[n];不合法
#include<stdio.h>
int main()
{
int a[5] = {10, 20, 30, 40, 50};//定义一个一维数组 int a[] = {10, 20, 30, 40, 50}
//int a[5] = {0} int a[5] = {0,0,0,0,0} int a[5] = {1,20}后三位默认赋值为0
//int a[5] = {10, 20, 0, 0, 0} int a[10]系统碎金赋值
printf("%d\n",a)//我们打印输出数组名,就是输出整个数组首地址
for(int i = 0; i < 5; i++)
{
printf("a[%d]的地址为:%p\n", i, &a[p]);
printf("a[%d]数据元素的值为:%d\n",i ,a[i]);
}
return 0;
}
在定义数组并对其各元素赋值后,就可以引用数组中的元素。
注意:只能引用数组元素而不能一次整体调用整个数组全部元素的值。
引用数组元素的表示形式为:
数组名 [下标];
如a[0] = a[5] + a[7] - a[2*3] 合法
int n = 5, a[10]; a[n] = 20 合法
//从键盘输入5个数字,求最大值
#include<stdio.n>
int main()
{
int a[5] = {0};
printf("请输入数组a的值:\n");
for(int i = 5; i < 5; i++)
scanf_s("%d", &a[i]);
printf("\n输出数组a元素的值为:\n");
for(int i = 0; i < 5; i++)
printf("%5d",a[i]);
printf("\n");
int x = a[0];//将数组第一个元素作为最大数跟最后面进行比较
for(int i = 1; i < 5; i++)
{
if(x <= a[i])
x = a[i];//将比较x这个数字大的,赋值给x(作为最大数继续跟后面进行比较)
}
printf("\n最大数字为:%d\n",x);
retrurn 0;
}
二维数组
队员1 | 队员2 | 队员3 | 队员4 | 队员5 | 队员6 | |
---|---|---|---|---|---|---|
1分队 | 2456 | 1847 | 1243 | 1600 | 2346 | 2757 |
2分队 | 3045 | 2018 | 1725 | 2020 | 2458 | 1436 |
3分队 | 1427 | 1175 | 1046 | 1976 | 1477 | 2018 |
float pay[3][6];
二维数组定义的一般形式为:
类型符 数组名[常量表达式][常量表达式]
数组名[下标][下标]
b[1][2] = a[2][3]/2 合法
for(i = 0; i < m; i++)
printf("%d,%d\n",a[i][0],a[0][i]); 合法
二维数组可被看作是一种特殊的一维数组:
它的元素又是一个一维数组。例如,把a[3][4]看作是一个一维数组,它有三个元素:a[0]、a[1]、a[2],每个 元素又是一个包含4个元素的一维数组。
逻辑存储和内存中的存储顺序:
a[0] | a[0][] | a[0][1] | a[0][2] | a[0][3] |
---|---|---|---|---|
a[1] | a[1][0] | a[1][1] | a[1][2] | a[1][3] |
a[2] | a[2][0] | a[2][1] | a[2][2] | a[2][3] |
#include<stdio.h>
int main()
{
int a[3][3];
printf("输出二维数组下标:\n");
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
printf("a[%d][%d]",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};
int a[3][4]={{1},{5},{9}};等价于int a[3][4]={{1,0,0,0},{5,0,0,0},{9,0,0,0}};
int a[3][4]={{1},{5,6}};等价于int a[3][4]={{1},{5,6},{0}};
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};等价于int a[][4]={1,2,3,4,5,6,7,8,9,10,11,12};
int a[][4]={{0,0,3},{},{0,10}};合法
将一个二维数组行和列的元素进行互换,存储到另一个二维数组。
解题思路:定义两个数组,数组a为2行3列,存放6个数字(10,20,30,40,50,60),数组b为3行2列,将a数组中的元素[i][j]存放到b数组b[j][i]
#include<stdio.h>
int main()
{
int a[2][3] = {10,20,30,40,50,60};
int b[3][2];
printf("输出二维数组a元素值:\n");
for(int i = 0; i < 3; i++)
{
for(int j = 0; j <2; j++)
{
printf("%5d",a[i][j]);
b[j][i] = a[i][j];
}
printf("\n");
}
return 0;
}
字符数组
用来存放字符数据的数组是字符数组,字符数组中的一个元素存放一个字符。定义字符数组的方法与定义数值型数组的方法类似。
char c[10];
c[0] = '1';c[1] = ' ';c[2] = 'a';c[3] = 'm';c[4] = ' ';c[5] = 'h';c[6] = 'a';c[7] = 'p';c[8] = 'p';c[9] = 'y';
#include<stdio.h>
int main()
{
char s[10] = {'I','','a','m','.'};
for(int i = 0; i < 10; i++)
printf("%c",s[i]);
printf("\n");
return 0;
}
-
字符数组的初始化
char c[10] = {'I',' ','a','m',' ','h','a','p','p','y'};
char c[10] = {'c',' ','p','r','o','g','r','a','m',};
-
字符串和字符串结束标志
在C语言中,是将字符串作为字符数组来处理的,关心的是字符串的有效长度而不是字符数组的长度,为了测定字符串的实际长度,C语言规定了字符串结束标志'\0','\0'代表ASCII码为0的字符。
从ASCII码表可以查到,ASCII码为0的字符不是一个可以显示的字符,而是一个“空操作符“,即它什么也不做,用它作为字符串结束标志不会产生附加的操作或增加有效字符,只起一个共辨别的标志。
-
字符数组的输入输出
字符数组的输入输出可以有两种方式:
逐个字符输入输出(%c)
整个字符串一次输入输出(%s)
输出的字符中不包括结束符'\0',用%s输出字符串时,Printf函数中的输出项是字符数组名,不是数组元素名,如果一个字符串中包含多个’\0‘,则遇到第一个'\0'时输出就结束。
可以用sacnf函数输入一个字符串,scanf函数中的输入项c是已定义的字符数组名,输入的字符串应短于已定义的字符数组的长度。
#include<stdio.h> #include<string.h> int main() { char s[50] = "I am Happy."; printf("请输出字符串s:\n"); scanf_s("%s",s,strlen(s)); printf("\n输出字符串s=%s\n",s); return 0; }
-
字符串处理函数
在C函数库中提供了一些用来专门处理字符串的函数,使用方便。
-
puts函数——输出字符串的函数
其一般形式为:
puts(字符数组)
作用是将一个字符串输出到终端
-
gets函数——输入字符串的函数
其一般形式为:
gets(字符数组)
作用是输入一个字符串到字符数组
-
strcat函数——字符串连接函数
其一般形式为:
stract(字符数组1,字符数组2)
其作用是把两个字符串连接起来,把字符串2接到字符串1的后面,结果放在字符数组1中。
使用字符串函数时,在程序开头用#include<string.h>
-
strcpy和strncpy函数-字符串复制
strcpy一般形式为:
strcpy(字符数组1,字符串2)
作用是将字符串2复制到字符数组1中去。
使用字符串函数时,在程序开头用#include<string.h>
-
strcmp函数——字符串比较函数(ASCII)
strcmp函数一般形式为:
strcmp(字符串1,字符串2)
作用是比较字符串1和字符串2。
字符串1 < 字符串2 -1
字符串1 > 字符串2 1
字符串1 = 字符串2 0
使用字符串函数时,在程序开头用#include<string.h>
-
strlen函数——测字符串长度的函数
strlen函数的一般形式为:
strlen(字符数组)
它是测试字符串长度的函数,函数的值为字符串中的实际长度。
使用字符串函数时,在程序开头用#include<string.h>
-
strlwr函数——转换为小写的函数
strlwr函数的一般形式为:
strlew(字符串)
函数的作用是将字符串中大写字母换成小写字母。
使用字符串函数时,在程序开头用#include<string.h>
-
strupr函数——转换为大写的函数
strupr函数的一般形式为:
strupr(字符串)
函数的作用是将字符串中的小写字母换成大写字母。
使用字符串函数时,在程序开头用#include<string.h>
-
函数(一)
用模块化程序设计的思路。
采用“组装”的方法简化程序设计的过程。
事先编好一批实现各种不同功能的函数。
把它们保存在函数库中,需要时直接用。
在设计一个较大的程序时,往往把它分为若干个程序模块,每一个模块包括一个或多个函数,每个函数实现一个特定的功能。
c程序可由一个主函数和若干个其他函数构成
主函数调用其他函数,其他函数可以互相调用
同一个函数可以被一个或多个函数调用任意多次
可以使用库函数,可以使用自己编写的函数。
函数定义与调用
C语言要求,在程序中用到的所有函数,必须“先定义,后使用”。
指定函数名字、函数返回值类型、函数实现的功能以及参加的个数和类型,将这些信息通知编译系统
指定函数的名字,以便以后按名调用。指定函数类型,即函数返回值类型。指定函数参数的名字和类型,以便在调用函数时向它们传递数据。指定函数的功能。这是最重要的,这是在函数体中解决的。
对于库函数,程序设计者只需要用#include指令把有关的头文件包含到本文件模块中即可程序设计者需要在程序中自己定义想用的而库函数并没有提供的函数。
-
定义无参函数
定义无参函数的一般形式:
类型名 函数名(){
函数体
}
类型名 函数名(void)
{
函数体
}
-
定义有参函数
定义有参函数的一般形式为:
类型名 函数名(形式参数表列)
{
函数体
}
-
定义空函数
定义空函数的一般形式:
类型名 函数名()
{
}
先用空函数占一个位置,以后逐步扩充。
好处:程序结构清楚,可读性好,以后扩充新功能方便,对程序结构影响不大。
-
函数调用
函数调用的一般形式为:
函数名(实参表列)
如果调用无参函数,则“实参表列”可以没有,但括号不能省略。如果实参表列包含多个实参,则各参数间用逗号隔开。
-
函数调用语句
把函数调用单独作为一个语句
如pritf_star();
这是不要求函数带回值,只要求函数完整一定的操作。
-
函数表达式
函数调用出现在另一个表达式
如c = max(a,b);
这是要求函数带回一个确定的值以参加表达式的运算。
-
函数参数
函数调用作为另一个函数调用时的实参
如m = max(a, max(b,c));
其中max(b,c)是一次函数调用,它的值作为max另一次调用的实参。
-
-
函数调用的过程
在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。在发生函数调用时,函数Max的形参被临时分配内存单元。
- 函数的返回值是通过函数中的return语句获得的。
- 函数值的类型。应当在定义函数时指定函数值的类型。
- 在定义函数时指定的函数类型一般应该和return语句中的表达式类型一致。
函数的嵌套调用
C原因的函数定义是互相平行、独立的,即函数不能嵌套定义,但可以嵌套调用函数,即调用一个函数的过程中,又可以调用另一个函数。
#include<stdio.h>
int maxx(int a, int b, int c, intd);
int maxy(int x, int y);
int main()
{
int a, b, c, d, max;
printf("\n请输入4个整数:\n");
scanf_S("%d%d%d%d",&a,&b,&c,&d);
max = maxx(a, b, c, d);
printf("最大数max=%d\n\n",max);
return 0;
}
int maxx(int a ,int b, int c, int d)
{
int m;
m = maxy(a, b);
m = maxy(m, c);
m = maxy(m ,d);
return m;
}
int maxy(int x, int y)
{
return(x > y ? x : y)
}
函数的递归调用
在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。C语言的特色之一就在于允许函数的递归调用。
#include<stdio.h>
int ageFunc(int n)
{
int age = 0;
if(n == 1)
age = 10;
else
age = ageFunc(n - 1) + 2;
return age;
}
int main()
{
int age = 0;
printf("\n第No.5人的年龄:%d\n\n",ageFunc(5));
return 0;
}
函数(二)
数组作为函数参数
- 除了可以用数组元素作为函数参数外,还可以用数组名作函数参数(包括实参和形参)。
- 用数组元素作实参时,向形参变量传递的是数组元素的值。
- 用数组名做函数实参时,向形参传递的是数组首元素的地址。
/*
编程实现:用户从键盘输入10个数字,要求输出其中最大数及该数在第几个位置?
解题思路:
定义数组用来存放10数字;
肯定要设计一个函数,用来求比较两个数当中的最大数;
在主函数中定义变量max,调用比较函数;
算法(依次将数组的元素a[i]——>a[9]跟max进行比较。
*/
#include<stdio.h>
int maxFunc(int x, int y)
{
return (x > y ? x : y);
}
int main()
{
int a[10], maxx, count;
printf("\n请输入10个整数:\n");
for(int i = 0; i < 10; i++)
scanf_s("%d",&a[i]);
printf("\n输出10个整数如下:\n");
for(int i = 0; i < 10; i++)
printf("%5d",a[i]);
printf("\n");
maxx = a[0];//把第一个元素作为最大数跟后边那个数字比较就可以,依次类推
for(int i = 1; i < 10; i++)
{
if(maxFunc(maxx, a[i]) > maxx)
{
maxx = maxFunc(mazz, a[i]);
count = i;
}
}
printf("最大数字为:%d\n",maxx);
printf("该数的位置在:%d位\n",count + 1);
return 0;
}
/*
题目:从键盘输入10个学生的数学成绩,求平均成绩?
思路:定义函数来求平均成员,用数组名作为函数的实参,形参接收也要用数组名;
求平均成绩之后,返回主函数进行输出;
*/
#include<stdio.h>
double averageFunce(double a[10])
{
double aver, sum = a[0];
for(int i = 1; i < 10; i++)
sum = sum + a[i];
aver = sum / 10;
return aver;
}
int main()
{
double score[10], aver = 0;
printf("请输入10个学生的数学成绩:\n");
for(int i = 0; i < 10; i++)
scanf_s("%lf",&score[i]);
printf("\n");
aver = averageFunc(score);
printf("学生的数学平均成绩为:%lf\n",aver);
return 0;
}
/*
题目:设计一个函数输出3*3矩阵,求所有元素中的最大值?
思路:。。。。。。
*/
#include<stdio.h>
int MaxValue_Print(int a[3][3])
{
printf("\n输出3*3矩阵:\n");
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
printf("%5d",a[i][j])
}
printf("\n");
}
printf("\n");
int max;
max = a[0][0];//把第一个数字给max跟后面比较
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
if(a[i][j] > max)
max = a[i][j];
}
}
return max;
}
int main()
{
int a[3][3] = {{43,54,67},{36,78,74},{98,76,79}};
printf("\n矩阵3*3最大元素值为:%d\n\n",MaxValue_Print(a))
}
局部变量与全局变量
定义变量可能有三种情况:
- 在函数的开头定义
- 在函数内的复合语句内定义
- 在函数的外部定义
在一个函数内部定义的变量只在本函数范围内有效
在复合语句内定义的变量只在本复合语句范围内有效
- 局部变量:在函数内部或复合语句内部定义的变量称为“局部变量”
- 全局变量:
- 在函数内定义的变量是局部变量,而在函数之外定义的变量称为外部变量
- 外部变量是全局变量(也称全程变量)
- 全局变量可以为本文件中其他函数所共有
- 有效范围为从定义变量的位置开始到本源文件结束
内部函数和外部函数
-
内部函数
如果一个函数只能别本文件中其他函数所调用,它称为内部函数。
在定义内部函数时,在函数名和函数类型前面加static,即:
static 类型名 函数名(形参表)
内部函数又称静态函数,因为它是static声明的;
通常把只能由本文件使用的函数和外部变量放在文件的开头,前面都冠以static使之局部化,其他文件不能引用;
提高程序的可靠性。
-
外部函数
如果在定义函数时,在函数首部的最左端加关键字extern,则此函数是外部函数,可供其他文件调用。
如函数首部可以为:
extern int fun(int a, int b)
如果在定义函数是省略extern,则默认为外部函数