C语言基础知识
1.第一个C语言程序
C语言的编程框架
c
#include <stdio.h>
int main()
{
/* 我的第一个 C 程序 */
printf("Hello, World! \n");
return 0;
}
2.注释
c
单行注释: //第一种写法 /* 单行注释 */
多行注释:
/*
多行注释
多行注释
多行注释
*/
3.标识符
C 标识符是用来
标识
变量、函数,或任何其他用户自定义项目的名称
。规定:C语言的的标识符由
数字
,字母
,下划线
构成,但不能以数字开头
。
可以作为标识符的
mohd , zara , abc , move_name , a_123
myname50 , _temp , j , a23b9 , retVal
不可以作为标识符的
12mb , 23_m
4.关键字
具有特殊含义的标识符,C语言已经使用的了,
用户自定义标识符时不能再使用
。 后续的学习都会慢慢接触这些,现在只需要眼熟即可。
5.数据类型
数据类型就像一个盒子一样,盒子中存放数据,不同的数据要用不同的盒子装。
为了限制变量中所存储的数据(至少是可以兼容的)。
为了限制变量所占空间
先学习基本数据类型,其他的数据类型后续学习
char //字符数据类型
short //短整型
int //整形
long //长整型
long long //更长的整形
float //单精度浮点数
double //双精度浮点数
C语言本身并没有字符串类型
,我们在C语言程序中使用的字符串实际上是字符数组,即多个字符构成的就是字符串!
- 整型
- 浮点型
为了得到某个类型或某个变量在特定平台上的准确大小,可以使用 sizeof 运算符。表达式 sizeof(type)
得到对象或类型的存储字节大小。
c
#include<stdio.h>
int main(){
printf("int 存储大小 : %d \n", sizeof(int)) ;
return 0;
}
数据类型的转换
类型转换是将一个数据类型的值转换为另一种数据类型的值。
-
隐式类型转换:隐式类型转换是在表达式中
自动发生的
,无需进行任何明确的指令或函数调用。它通常是将一种较小的类型自动转换为较大的类型,例如,将int类型转换为long类型或float类型转换为double类型。隐式类型转换也可能会导致数据精度丢失或数据截断。
cint i = 10; float f = 3.14; double d = i + f; // 隐式将int类型转换为double类型
-
显式类型转换:显式类型转换需要使用强制类型转换运算符(type casting
operator),它可以将一个数据类型的值
强制转换
为另一种数据类型的值。强制类型转换可以使程序员在必要时对数据类型进行更精确的控制,但也可能会导致数据丢失或截断。
cdouble d = 3.14159; int i = (int)d; // 显式将double类型转换为int类型
6.变量
生活中有些值是可变的(比如:年龄,体重,薪资),需要用变量来表示 数据类型决定了
变量存储的大小和布局
,该范围内的值都可以存储在内存中
变量两部步骤(定义,初始化)
1.定义:
数据类型 variable_list;
数据类型,可以是整型、浮点型、字符型、指针等,也可以是用户自定义的对象。
variable_list 可以由一个或多个变量的名称组成
,多个变量之间用逗号,分隔
举例:
c
int age; //age 被定义为一个整型变量。
float salary; //salary 被定义为一个浮点型变量。
char grade; //grade 被定义为一个字符型变量。
int *ptr; //ptr 被定义为一个整型指针变量。
int i, j, k; //声明并定义了变量 i、j 和 k
2.初始化(赋值)
c
int x; // 整型变量x定义
x = 20; // 变量x初始化为20
float pi; // 浮点型变量pi定义
pi = 3.14159; // 变量pi初始化为3.14159
char ch; // 字符型变量ch定义
ch = 'B'; // 变量ch初始化为字符'B'
为了简化,可以定义的同时初始化
c
int x = 10; // 整型变量 x 初始化为 10
float pi = 3.14; // 浮点型变量 pi 初始化为 3.14
char ch = 'A'; // 字符型变量 ch 初始化为字符 'A'
extern int d = 3, f = 5; // d 和 f 的声明与初始化
int d = 3, f = 5; // 定义并初始化 d 和 f
byte z = 22; // 定义并初始化 z
如果变量不初始化
整型变量(int、short、long等):默认值为0。
浮点型变量(float、double等):默认值为0.0。
字符型变量(char):默认值为'\0',即空字符。
指针变量:默认值为NULL,表示指针不指向任何有效的内存地址。
7.常量
常量是
固定值
,在程序执行期间不会改变。这些固定的值,又叫做字面量。
-
整数常量
前缀:整数常量可以是
十进制、八进制或十六进制的常量
。前缀指定基数:0x 或 0X 表示十六进制
,0 表示八进制
,不带前缀则默认表示十进制
。后缀:后缀是 U 和 L 的组合
,U 表示无符号整数(unsigned)
,L 表示长整数(long)
。后缀可以是大写,也可以是小写
,U 和 L 的顺序任意。c212 /* 合法的 */ 215u /* 合法的 */ 0xFeeL /* 合法的 */ 十六进制数 FEE 078 /* 非法的:8 不是八进制的数字 */ 032UU /* 非法的:不能重复后缀 */ ============================================== 85 /* 十进制 */ 0213 /* 八进制 */ 0x4b /* 十六进制 */ 30 /* 整数 */ 30u /* 无符号整数 */ 30l /* 长整数 */ 30ul /* 无符号长整数 */
-
浮点常量
浮点常量由
整数部分
、小数点
、小数部分和指数部分
组成当使用
小数形式
表示时,必须包含小数点
。例如 0.123、.123、123.、0.0等都是合法的实型常量。
当使用
指数形式
表示时,字母e或E之前必须要有数字,且e或E后面的指数必须为整数
例如 +1.2E+5,1.5e-9,-5.0e10等都是合法的实型常量。
不带 f、F、l 或 L 后缀的浮点常量类型为 double。 如果后缀是字母 f 或 F,则常量的类型为 float。 如果后缀是字母 l 或 L,则常量的类型为 long double。
c10.0 /* Has type double */ 10.0F /* Has type float */ 10.0L /* Has type long double */
-
整数常量
字符常量是括在单引号中,例如,'x' 可以存储在 char 类型的简单变量中
字符常量可以是
一个普通的字符(例如 'x')
、一个转义序列(例如 '\t')
,或一个通用的字符(例如 '\u02C0')
。在 C 中,有一些特定的字符,当它们前面有反斜杠时,它们就具有特殊的含义,被用来表示如换行符(\n)或制表符(\t)等。下表列出了一些这样的转义序列码:
字符常量的 ASCII 值可以通过强制类型转换转换为整数值。
cchar myChar = 'a'; int myAsciiValue = (int) myChar; // 将 myChar 转换为 ASCII 值 97
常量的定义
在 C 中,有两种简单的定义常量的方式:
-
使用 #define 预处理器: #define 可以在程序中定义一个常量,它在编译时会被替换为其对应的值。
-
使用 const 关键字:const 关键字用于声明一个只读变量,即该变量的值不能在程序运行时修改。
#define 预处理器
#define 常量名 常量值
c
#define PI 3.14159
在程序中使用该常量时,编译器会将所有的 PI 替换为 3.14159
。
c
#include <stdio.h>
#define LENGTH 10
#define WIDTH 5
#define NEWLINE '\n'
int main()
{
int area;
area = LENGTH * WIDTH;
printf("value of area : %d", area);
printf("%c", NEWLINE);
return 0;
}
const 关键字
const 数据类型 常量名 = 常量值;
c
const int MAX_VALUE = 100;
在程序中使用该常量时,其值将始终为100,并且不能被修改。
c
#include <stdio.h>
int main()
{
const int LENGTH = 10;
const int WIDTH = 5;
const char NEWLINE = '\n';
int area;
area = LENGTH * WIDTH;
printf("value of area : %d", area);
printf("%c", NEWLINE);
return 0;
}
#define 与 const 区别(了解即可)
#define 与 const 这两种方式都可以用来定义常量,选择哪种方式取决于具体的需求和编程习惯。通常情况下,建议使用 const 关键字来定义常量,因为它具有类型检查和作用域的优势,而 #define 仅进行简单的文本替换,可能会导致一些意外的问题。
#define 预处理指令和 const 关键字在定义常量时有一些区别:
替换机制:#define 是进行简单的文本替换,而 const 是声明一个具有类型的常量。#define 定义的常量在编译时会被直接替换为其对应的值,而 const 定义的常量在程序运行时会分配内存,并且具有类型信息。
类型检查:#define 不进行类型检查,因为它只是进行简单的文本替换。而 const 定义的常量具有类型信息,编译器可以对其进行类型检查。这可以帮助捕获一些潜在的类型错误。
作用域:#define 定义的常量没有作用域限制,它在定义之后的整个代码中都有效。而 const 定义的常量具有块级作用域,只在其定义所在的作用域内有效。
调试和符号表:使用 #define 定义的常量在符号表中不会有相应的条目,因为它只是进行文本替换。而使用 const 定义的常量会在符号表中有相应的条目,有助于调试和可读性。
8.运算符
9.输入输出
输入
1.输入:scanf()
格式:scanf(控制串,&var1,&var2,...);
其中控制串由三部分组成:
- 格式说明符:前缀为%,用于告诉方法下次要读入何种数据类型的数据,并顺次放到方法后的变量中.
- 空白符:由
空格(" ")、制表符("\t")和新行符("\n")表示,
让方法在输入流中忽略一个或多个空白符(只要存在一个就可以忽略多个)。控制串中的空白符使 scanf() 在输入流中读,但不保存结果,直到发现非空白字符为止。 - 非空白符:除去格式说明符和空白符以外的其他字符,如逗号,分号,于空白符相同,scanf()在输入流中读,但不保存结果。
如果格式符之间添加了空格,那么按照规则,会忽略掉全部的空白符
直到遇到下一个不是空白符的字符
格式说明符 | 意义 |
---|---|
%d |
输入有符号的十进制数 |
%u |
输入无符号的十进制数 |
%o |
输入无符号的八进制数 |
%x/X |
输入无符号的十六进制数 |
%i |
输入八进制,十进制,十六进制数 (更通用) |
%c |
输入单个字符 |
%s |
输入字符串,将字符串送到一个字符组中,在输入时以非空白字符开始 ,以第一个空白字符结束 |
%f |
输入实数,可以用小数形式或指数形式输入 |
%e,E,g,G |
与f作用相同,e与f,g可以相互替换 |
附加格式符(也称修饰符)
字符 | 说明 |
---|---|
h |
输入短整型数据(可用到%hd,%ho,%hx) |
l |
输入长整型数据(可用到%ld,%1o,%lx.%lu)以及double型数据 (%lf ,%le) |
域宽 |
指定输入数据所占的宽度(列数),域宽应为正整数 |
* |
本输入项在读入后不赋给相应的变量 |
举例
读入整数
c
读入一个整数:
int a;
scanf("%d",&a);
读入多个整数 输入12 1 3
int a,b,c;
scanf("%d %d %d,&a,&b,&c);
读入以逗号分隔的多个整数: 输入1,2,3
int a,b,c;
scanf("%d,%d,%d",&a,&b,&c);
总之一句话,按照格式输入进行读取整数
读入其他类型的数字
参考读入整数,其他类型的数字使用方式相同,要注意的是
为了读取长整数
,可以将 l 放在格式说明符的前面
(如%ld,%lu
);
为了读取短整数
,可以将 h 放在格式说明符的前面
(如%hd
),
如果要强调。这些修饰符可以与 d、i、o、u 和 x 格式代码一起使用。
读入单个字符
在用%c格式声明输入字符时,空格
和"转义字符"中的字符
都会作为有效字符输入!所以如果要连续赋给变量
c
scanf("%c%c%c",&a,&b,&c),此时应该连续输入abc,而不是a b c。
int i;
char k;
scanf("%d %c",&i,&k);
/**
* 这个时候输入"1\na"和"1a"的效果是一样的,因为无论怎么换行,都属于空白符,会被忽略
*/
scanf("%d%c",&i,&k);
/**
* 这个时候输入"1\na",运行后k会接收到换行符,而不是"a",因为空白符没有被忽略,而%c对所有字符一视同仁。
*/
读入字符串
始终要注意的是读入字符串是scanf()方法的功能,而该方法是属于c的
,因此它不支持c++新增的string类型
c
char str[80];
scanf("%s",str);//注意这里不需要&,因为str是数组,传入的已经是指针了
要注意%s虽然是读入字符串,但它也会忽略空白符,下面例子中的两行scanf()方法是等价的,因为%s本身就有忽略空白符的功能。
c
char stra[80];
char strb[80];
scanf("%s %s",stra,strb);
scanf("%s%s",stra,strb);
以非空白字符开始,以第一个空白字符结束为第一个字符串
虽然会忽略空白符,但是会主动的在最后一个字符后添加"\0"表示字符串结束
(也因此,char数组不需要初始化就可以接受字符串,一般情况下不影响操作),因此在设置char数组长度时候,最好要比理论中的最大长度多预留一个长度
。
c
char str[5];//如果题目接受的最大字符串长度是4,那么设置的数组长度最好大于等于5
scanf("%s",str);
要注意的是,方法对空白符的忽略不是抛弃了空白符
,如果没有继续读下去的话,接受字符串后的空白符是会保留在缓冲区
的,这个时候使用%c接收是可以接收到,这个可能困扰了很多人,一定要注意。
c
char k;
char str[10];
scanf("%s%c",str,&k);
/**
* 如果输入"abcd",那么会直接运行结束,str="abcd",k='\n'
*/
2.输入:getchar()
字面意思,接收单个字符
,使用方法
c
char a;
a = getchar();
实际上效果等同于
char a;
scanf("%c",&a);
3.输入:gets()
字面意思,读取多个字符,实际上是读取一整行
,使用方法
c
char str[80];
gets(str);
由于gets()不检查字符串string的大小
,必须遇到换行符或文件结尾才会结束输入,因此容易造成缓存溢出的安全性问题,导致程序崩溃,可以使用fgets()代替。
区别:
scanf() 读取字符串时以空格为分隔,遇到空格就认为当前字符串结束了,所以无法读取含有空格的字符串。
gets() 认为空格也是字符串的一部分,只有遇到回车键时才认为字符串输入结束,所以,不管输入了多少个空格,只要不按下回车键,对 gets() 来说就是一个完整的字符串。
也就是说,gets() 能读取含有空格的字符串,而 scanf() 不能。
4.输入:fgets()
是对gets()方法的扩展,gets()是从标准输入流中读取,而fgets()是从文件输入流中读取,但是文件输入流并不局限于普通的文件,只要是流都可以用来输入,使用方法:
c
char str[80];
fgets(str,79,stdin);
fgets()函数的作用可以这么解释:从第三个参数
指定的流中读取最多第二个参数大小的字符到第一个参数指定的容器地址中
。在这个过程中,在还没读取够第二个参数指定大小的字符前,读取到换行符'\n'或者需要读取的流中已经没有数据了。则提前结束,并把已经读取到的字符存储进第一个参数指定的容器地址中。
注意事项
1.fgets()函数的注意事项1fgets()函数的
最大读取大小是其"第二个参数减1"
,这是由于字符串是以'\0'为结束符的,fgets()为了保证输入内容的字符串格式,当输入的数据大小超过了第二个参数指定的大小的时候,fgets()会仅仅读取前面的"第二个参数减1"个字符,而预留1个字符的空间来存储字符串结束符'\0'
。
2.fgets()函数的注意事项2在fgets()函数的眼里,换行符'\n'也是它要读取的一个普通字符而已。在读取键盘输入的时候会把最后输入的回车符也存进数组里面,即会把'\n'也存进数组里面,而又由于字符串本身会是以'\0'结尾的。所以在输入字符个数
没有超过第二个参数
指定大小之前,你输入n个字符按下回车输入,fgets()存储进第一个参数指定内存地址的是n+2个字节。最后面会多出一个'\n'和一个'\0',而且'\n'是在'\0'的前面一个(\n\0)。
输出
1.输出:printf()
printf函数一般格式:printf(格式控制,输出列表)
1)格式控制:格式声明:由"%"和格式字符组成,如%d,%f
(1)格式控制:格式声明:由"%"和格式字符组成,如%d,%f
普通字符:需要在输出时原样输出的字符。
(2)输出列表:是程序需要输出的一些数据,可以是常量,变量或表达式。
格式字符
格式附加字符
*号的用法
*在printf里可以代表一个泛整数,可以代表任何整数。它可以出现在位宽的位置,也可以出现在小数位数的位置。但在printf的双引号外面,必须要有*对应的数值
。
比如我的位宽不确定,想用整数a表示,则可以写成:
2.输出:putchar()