C语言
初识C语言
大纲
1-初识c语言
2-分支和循环语句
3-函数
4-数组
5-操作符详解
6-指针
7-结构体
8-实用调用技巧
第一节
第一个程序
#include <stdio.h>
int main() //主函数-程序的入口,有且只能有1个main函数
{
printf("hello world\n"); //print function-打印函数
//这里完成任务
return 0; //返回 0
}
//int是整型的意思,main前面的int表示main函数调用返回一个整型值
//printf是库函数-C语言本身提供给我们使用的函数
//别人的要打招呼,用#include,包含一个叫stdio.h的文件,std-标准,standard input output
ctrl+F5执行
数据类型
char //字符数据类型 short //短整型 int //整型 long //长整型 long long //更长的整型 float //单精度浮点数 double //双精度浮点数
打印字符a
#include <stdio.h>
int main()
{
char ch = 'a'; //申请内存,ch=change(变量)
printf("%c\n",ch); //%c,--打印(字符格式的数据)
return 0;
}
打印整型20
#include <stdio.h>
int main()
{
int age = 20;
printf("%d\n",age); //%d,--打印整型十进制数据
return 0;
}
//%f,--打印浮点数字-打小数
//%p,--以地址的形式打印
//%x,--打印16进制数字
//%s, --输出内存中的字符串,内存中存的是字符串所在的地址
打印双精度浮点型
#include <stdio.h>
int main()
{
double d = 3.14;
printf("%lf\n",d); //也可以用f,但是lf最准确,表示打印双精度浮点数
return 0;
}
不同类型向内存申请的空间
例
#include <stdio.h>
int main()
{
printf("%d\n", sizeof(long long));
return 0;
}
//注意sizeof是操作符,不是函数
申请的大小如下图所示
![](https://img-blog.csdnimg.cn/img_convert/b814bb0515953dfbde2e0a8586cb23cc.png)
上面的1是一个字节
什么是字节?
计算机中的单位
bit 比特位 //计算机是硬件--通电 1-正电,0-负电,比特位用来存放一个二进制位,只能存1或0
byte 字节 //一个字节是8个比特位
kb //1kb=1024byte
mb
gb
tb
pb
比如上面那个short,代表两个字节,就是16的二进制比特位0000000000000000——1111111111111111
三个比特位,有8种能放的可能,8=2的三次方,排列组合
二进制举个例子:010=0x2的二次方+1x2的一次方+0×2的0次方
例子
float weight = 95.6f;
或者
double weight = 95.6; //向内存申请四个字节,存放小数
c语言规定:sizeof(long)>=sizeof(int)
变量
定义变量的方法
类型+变量名+赋一个值
int age = 150;
float weight = 45.5f;
char ch = ‘w';
分类——局部变量和全局变量
#include <stdio.h>
int num2 = 20; //全局变量——定义在代码块({})之外的变量
int main()
{
int num1 = 10; //局部变量——定义在代码块({})内部
return 0;
}
//全局变量和局部变量可以同时存在,名字相同时输出局部变量的值
//建议全局和局部的名字不要相同,容易误会,产生bug
//局部变量只能在它自己的{}中被使用,放到全局里就不行了
变量使用:相加程序
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
//计算两个数的和
int num1 = 0;
int num2 = 0;
int sum = 0;
//输入数据,使用输入函数scanf;
scanf_s("%d%d", &num1, &num2); //&——取地址符号,把第一个值放到第一个地址处,这里sc -anf不行,把一会要输入的两个值放在地址处
//c语言语法规定,变量要定义在当前代码块的最前面
sum = num1 + num2;
printf("sun = %d\n", sum);
return 0;
}
//讲一下scanf,scanf是C语言提供的。scanf_s不是C语言提供的,VS编译器提供的,不具有跨平台性和可移植性
//要是想输入scanf不报错,第一行加上#define _CRT_SECURE_NO_WARNINGS 1
变量的作用域
作用域:这个变量哪里可以用,哪里就是作用域,比如num,作用域就是包含它的大括号(局部代码块内部)
全局变量作用域是整个工程
局部变量的作用域是变量所在的局部范围
#include <stdio.h>
int global = 2020;
int main()
{
printf("%d\n",global);
return 0;
}
变量的生命周期
定义:变量从创建到变量销毁的时间段
局部变量的生命周期:进入作用域——离开作用域({})
全局变量的生命周期:整个程序的生命周期
第二节
常量
分类
字面常量
const修饰的常变量
#define定义的标识符常量
枚举常量
字面常量
定义:直观写出
举例:3, 100, 3.14……
const修饰的常变量
定义:const——常属性
举例
不加const
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int num = 4;
printf("%d\n", num);
num = 8;
printf("%d\n", num);
return 0;
}
//程序可以正常运行,输出4和8
加了const
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
const int num = 4;
printf("%d\n", num);
num = 8;
printf("%d\n", num);
return 0;
}
//num不能改了,此时num就是const修饰的常变量(常变量:类似中国人去了美国,但他本质上还是一个中国人
//num虽然具有const属性,但它本质上还是一个变量
//n是变量,但是又有常属性,所以我们说n是常变量
#define定义的标识符常量
#define MAX 10
int main()
{
int arr[MAX] = {0};
printf("%d\n",MAX);
return 0;
}
枚举常量
枚举关键:enum
例
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
enum Sex
{
MALE,
FEMALE,
SECRET
};
int main()
{
printf("%d\n", MALE); //默认012
printf("%d\n", FEMALE);
printf("%d\n", SECRET);
return 0;
}
什么能改,什么不能改
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
enum Color
{
RED,
YELLOW,
BLUE
};
int main()
{
enum Color color = BLUE;
color = YELLOW; //本来这样运行没问题
//BLUE = 6; //但是这个就不行
return 0;
}
//枚举常量是不能改的(大括号里面给定的),但是通过枚举类型创造出来的变量是可以改的,颜色本身不能改
字符串
概念:由双引号引起来的一串字符叫做字符串(字符串结束标志是一个\0的转义字符,在计算字符串长度的时候\0是结束标志,不算做字符串的内容。"hello bit")
求字符串长度的小函数:strlen,只认识\0,遇到\0才会停止
\0体现,转义字符——转变原来的意思
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
char arr1[] = "abc"; //里面除了abc,还在末尾隐藏了\0,值本来就是0
char arr2[] = { 'a','b','c' ,'\0'};//0至关重要,要是没有0,2就会出现烫烫哈哈哈也可0
printf("%s\n", arr1);
printf("%s\n", arr2);
return 0;
}
//因此字符串的最后有结束标志,1中就停了,2中继续打印
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
char arr1[] = "abc";
char arr2[] = { 'a','b','c' };
printf("%d\n", strlen(arr1));
printf("%d\n", strlen(arr2));
return 0;
}
//输出结果,3和随机值
//若在2那里输入'\0',结果就会变成两个3,\n也是一个转义字符,换行
// \t——制表符
//??) -->三字母词会变成]
转义字符
\? 在书写连续多个问号时使用,防止被解析为三字母词
\n 换行
\ \还可以转义斜杠,让斜杠就是斜杠,用魔法打败魔法
\\ 用于表示一个反斜杠,防止被解释为一个转义序列符【printf("%s\n","\"");】
\ddd ddd表示1-3个八进制数字。如:\130 X
\xdd dd表示2个十六进制数字。如:\30 0 ,比如遇见\61,是一个字符,叫转义字符
数数字符串的长度
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
printf("%d\n", strlen("c:\test\32\test.c")); //没错,就是13个,\t算一个,\32也算一个
return 0;
}
/* \32是2个八进制数字,32作为八进制代表的那个十进制数字,作为ASCII码值,对应的字符*/
/* 32 --> 10进制26 ——>作为ASCII码值代表的字符*/
red_book两数取个最大值小程序
不创建函数写法
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main()
{
int num1 = 10;
int num2 = 20;
if (num1 > num2)
printf("较大值是:%d\n",num1);
else
printf("%d\n", num2);
return 0;
}
创建函数写法
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int max(int x, int y);
int a,b,c;
scanf("%d,%d", &a,&b);
c = max(a,b);
printf("max=%d\n", c);
return 0;
}
int max(int x, int y)
{
int z;
if (x>y)z= x;
else z = y;
return(z);
}
//注意输出时要输5,8之类的,中间用,隔开,不然系统默输出第一个
注释
C语言风格的注释
/*kkk*/
缺点:不能嵌套
C++风格的注释
//kkk//
注释快捷键
ctrl+k+c //注释 ctrl+k+u //取消注释
用处
对难代码的注释,方便自己,便利他人哈哈哈
选择语句
选择小例子
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int input = 0;
printf("加入比特\n");
printf("你要好好学习吗?(1/0)>: ");
scanf("%d", &input);
if (input == 1) //两个等号是判断是否相等
printf("好offer\n");
else
printf("卖红薯\n");
return 0;
}
循环语句
循环小例子
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main()
{
int line = 0;
printf("加入比特\n");
while (line < 20000) //笑死了while不用加;
{
printf("敲一行代码\n");
line++;
}
printf("好offer\n");
return 0;
}
升级一下
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main()
{
int line = 0;
printf("加入比特\n");
while (line < 20000)
{
printf("敲一行代码,%d\n",line);
line++;
}
if(line>=20000)
printf("好offer\n");
return 0;
}
相加小函数
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int Add(int x, int y) //Add是函数名,小括号内是参数,int是返回类型,自定义函数
{ //大括号内是函数体,是在完成给定的任务
int z = x + y;
return z; //z是一个整形,对应上述int
}
int main()
{
int num1 = 10;
int num2 = 20;
int sum = 0;
int a = 100;
int b = 200;
//sum = num1+num2;
sum = Add(num1, num2);
//sum = a+b;
sum = Add(a, b);
printf("sum = %d\n", sum);
return 0;
}
函数小类型:自定义函数and库函数
数组
数组定义:一组相同类型元素的集合
数组有下标,从0开始,依次递增,最大的下标是n-1
数组的大小是常量,不能用n表示 int arr[n]={0},表述就是错误的,[里面是大小]
int arr[10] ={1,2,3,4,5,6,7,8,9,10}; //定义一个存放10个整数数字的数组 //数字
char ch[20]; //字符
float arr2[5];
打印数组里全部内容
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
while (i < 10)
{
printf("%d\n", arr[i]);
i++;
}
//printf("%d\n", arr[4]);
return 0;
}
操作符
算数操作符
+ - * / % %的意思是取模,也就是取余,5%2=1
移位操作符
移的是二进制位
<< 左移操作符
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main()
{
int a = 1;
int b = a << 1;
printf("%d\n",b);
return 0;
}
//整型1占4个字节——32bit位
//000000000000000000000000000000001,a占这么多,如果往左移1个位,000000000000000000000000000000010,1乘2的一次方
//左移两个就是2的两次方,移完a是不变的
位操作符
& 按位与
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main()
{
int a = 3; 转化为二进制是011
int b = 5; 转化为二进制是101
int c = a & b;
printf(" % d\n", c);
return 0;
}
// 0为假,1为真,按位与并起来就是001,输出结果就是1 ,非0就是真
//与: 一假既假,全真才真
| 按位或
对应二进制里面只要有个1就可以了
//或:一真既真,全假才假
^ 按位异或
^:不是次方,是异或
计算规律:对应的二进制位相同,则为0
对应的二进制位相异,则为1
011
101
算出:110
输出:6
赋值操作符
= += -= *= /= &= ^= |= >>= <<=
int main
{
int a = 10;
a = 20;
a = a+10;
//a += 10; 和上面二者完全等价
return 0;
}
a = a&2;
a &=2; //复合赋值符
判断是否相等操作符
!= 用于测试不相等
== 用于测试相等
逻辑操作符
&& 逻辑与(数学且)
#include <stdio.h>
int main()
{
int a =0;
int b =5;
int c =a&&b;
printf("%d\n",c);
return 0;
}
//输出0
//真-非0
//假-0
//全是真才为真
//有一个假就是假
|| 逻辑或
#include <stdio.h>
int main()
{
int a =0;
int b =5;
int c =a||b;
printf("%d\n",c);
return 0;
}
//有一个为真就输出真
条件操作符
exp1?exp2:exp3;
exp表达式意思,表达式1的结果如果为真,表达式2要执行,表达式2的结果是整个表达式的结果,如果表达式1结果为假,表达式3要执行,表达式3的结果是整个表达式的结果
关系操作符
> > =
!= 用于测试"不相等"
== 用于测试"相等",单个=用来赋值
单目操作符/双目操作符/
单目操作符
例子
a+b //+有两个操作对象,是双目操作符
单目操作符
! 逻辑反操作(把真变成假,把假变成真)
C语言中我们表示真假,0-假,非0-真
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main()
{
int a = 0;
printf("%d\n", a);
printf("%d\n", !a);
return 0;
}
-
int a= -
同理+
~ 对一个数的二进制按位取反
++
后置++,先使用,再++
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main()
{
int a = 10;
int b = a++;
printf("a = %d b=%d\n", a,b);
return 0;
}
//先把a赋给b,a再++
//输出a=11,b=10
前置++,先++,再使用
输出a=11,b=11
-- 同上
(类型) 强制类型转换
int a =(int)3.14;
sizeof
sizeof 计算的是变量/类型所占空间的大小,单位是字节
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main()
{
int arr[10] = { 0 };
printf("%d\n", sizeof(arr));
return 0;
}
//计算数组大小
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main()
{
int arr[10] = { 0 };
int sz = 0;
printf("%d\n", sizeof(arr));
sz = sizeof(arr) / sizeof(arr[0]);
printf("sz = %d\n", sz);
return 0;
}
//计算数组的元素个数
//个数=数组总大小/每个元素的大小
EOF - end of file --文件结束标志,本质上值是-1
第三节
原码,反码,补码
~按位取反 :按二进制位进行取反 0 <--> 1
原码按二进制位,符号位不变,其他位进行按位取反得到反码,反码加一得到补码
000000000000000000000000
111111111111111111111111
111111111111111111111111 //补码
111111111111111111111110 //反码
100000000000000000000001 //原码 --> -1
//补码减一得到反码,反码符号位不变,其他位按位取反得到原码
负数在内存中存储的时候,存储的是二进制的补码
只要是整数,内存中存储的都是二进制补码
正数--原码,反码,补码相同
有符号整形的最高位是符号位,为1代表负数,0代表正数
使用的,打印的是这个数的原码
操作符
++
后置++
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main()
{
int a = 10;
int b = a++; //后置++,先使用,再++,先把a的值赋给b,a再++
printf("a = %d b=%d\n", a, b);
return 0;
}
结果:a=11,b=10
前置++
先让a++,再把a的值赋给b
--
与++同理
(类型)
强制类型转换
int a =(int)3.14;
逗号表达式
exp1,exp2,exp3,...expN
下标引用,函数调用和结构成员
下标操作符
#include <stdio.h>
#include<string.h>
int main()
{
int arr[10] = { 0 };
arr[4]; //[]下标引用操作符
return 0;
}
函数调用操作符()
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int Add(int x, int y)
{
int z = 0;
z = x + y;
return z;
}
int main()
{
int a = 10;
int b = 20;
int sum = Add(a, b); // ()函数调用操作符
return 0;
}
. -->,这个在下一部分会讲到
常见关键字
关键字typedef
顾名思义就是类型定义,这里应该理解为类型重命名
类型
auto:自动
int main()
{
(auto) int a = 10;//局部变量自动变量,a自动创建,自动销毁
return 0;
}
break:停止循环
case
char:字符类型
const:修饰常变量
default:默认
enum:枚举
extern:引入外部符号
float:单精度浮点数
for:for循环
goto:goto语句
register:寄存器
register
register int a = 10; //建议把a定义成寄存器变量
signed:
int 定义的变量是有符号的
signed int
unsigned int num = 0 ;放什么都是正数
static:静态的
修饰局部变量,局部变量的生命周期变长
修饰全局变量,改变了变量的作用域,让静态的全局变量只能在自己所在的源文件内部使用,出了源文件就没法使用了
static还能修饰函数,改变了函数的链接属性,外部链接属性->内部链接属性
extern修饰外部变量
#include <stdio.h>
#include<string.h>
void test()
{
static int a = 1;
a++;
printf("a= %d\n", a);
}
int main()
{
int i = 0;
while (i < 5)
{
test();
i++;
}
return 0;
}
//输出:23456,去掉static,输出5个2
struct:结构体关键字
switch
typedef:类型定义— 类型重定义
typedef unsigned int u_int;
unsigned int num = 20;
u_int num2 = 20;
union:联合体,共用体
void:空
volatile
自己定义符号名不能和关键字冲突
#define 定义常量和宏
#define定义标识符常量
#define _CRT_SECURE_NO_WARNINGS
#define MAX 100
#include <stdio.h>
#include<string.h>
int main()
{
int a = MAX;
printf("%d\n",a);
return 0;
}
def MAX 100,下面每次遇到MAX都是100
#define定义宏—带参数
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
//函数定义
int Max(int x, int y)
{
if (x > y)
return x;
else
return y;
}
//宏的定义
#define MAX(X,Y) (X>Y?X:Y) //前面被后面替换
int main()
{
int a = 10;
int b = 20;
//函数
int max = Max(a, b);
printf("max = %d\n", max);
//宏
max = MAX(a, b);
//max = (a>b?a:b);
printf("max = %d\n", max);
return 0;
}
//宏实现起来更加简洁
指针
指针变量
指针名字是p,类型是int*
指针是个变量,是用来存放地址的
#include <stdio.h>
#include<string.h>
int main()
{
int a = 10; //4个字节
int* p = &a;
printf("%p\n", &a);
printf("%p\n", p);
//有一种变量是用来存放地址的指针变量
return 0;
}
//*p 解引用操作符,对p进行解引用操作,找到它所指向的对象a,加个*p = 20,输出后a=20
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main()
{
char ch = 'w';
char* pc = &ch;
*pc = 'a';
printf("%c\n", ch);
return 0;
}
//输出a
指针大小
32位平台上,一个指针变量大小是32bit,四个字节,64位八个字节
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main()
{
char ch = 'w';
char* pc = &ch;
printf("%d\n", sizeof(pc));
return 0;
}
//输出4
对*理解
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main()
{
int a = 10; // 申请了4个字节的空间
//printf("%p\n,&a)
int* p = &a; //p是一个变量-指针变量,*的意思是告诉p是一个指针变量,int说明p指向的对象(a)类型是int
//printf("%p\n,p)
*p = 20; //* - 解引用操作符/间接访问操作符,此处*和上述不一样,此处是操作符
printf("a = %d\n",a);
return 0;
}
地址大小
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main()
{
double d = 3.14;
double* pd = &d; //32-4 64-8
printf("%d\n", sizeof(pd));
//*pd = 5.5;
//printf("%lf\n", d);
//printf("%lf\n", *pd);
return 0;
}
指针大小都是四(32位)
结构体
要想描述人,书等,这些都是复杂对象,该如何描述复杂对象呢,c语言说用一种结构体来描述,是我们自己创造出来的一种类型
struct结构体关键字
加一句,一定要注意标点
结构体变量小程序
注意下面用到了新的操作符,'.',用于结构体变量找成员
-> ,结构体指针->成员
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
struct Book //创建的是书的类型,创建一个结构体类型
{
char name[20];//C语言程序设计
short price; //55
}; //;用来结束类型定义
int main()
{
//利用结构体类型创建一个该类型的结构体变量
struct Book b1 = { "C语言程序设计",55 };
printf("书名:%s\n", b1.name);
printf("价格:%d\n", b1.price);
b1.price = 15; //这里price可以修改,因为它是变量,书名不能改,它是数组,数组名本质上是个地址
//如果实在要改,用到strcpy,字符串拷贝,只有两个参数,是库函数,要用头文件-string.h
//strcpy(b1.name,"C++") 参数一:目的地(放到哪里去),参数二:你要拷贝谁
printf("修改后的价格:%d\n", b1.price);
return 0;
}
//用指针打印
int main()
{
//利用结构体类型创建一个该类型的结构体变量
struct Book b1 = { "c语言程序设计",55 };
struct Book *pb = &b1;
//strcpy(b1.name, "C++");
printf("%s\n", (*pb).name);
printf("%d\n", (*pb).price);
/*printf("书名:%s\n", b1.name);
printf("价格:%d\n", b1.price);
b1.price = 15;
printf("修改后的价格:%d\n", b1.price);*/
return 0;
}
对上述进行简化
printf("%s\n",pb->name); //->表示指针指向的对象的name
printf("%d\n",pb->price);
总结
上面是对C语言大致知识的一些描述,也是我学习C语言的第一步,接下来会具体对C语言进行更深入的学习,有很多地方还做的不足,希望各位师傅多多斧正!