C语言基础
学语言:逻辑,基本算法,基本数据结构
学c基础不是目的,就个开端
没有最好的语言,只有最合适的
C语言简介
- 计算机:(电脑)
- 电脑执行需要运行程序,执行程序都是由程序员进行编写。
- 人与计算机交互:机器码:
- 二进制数:计算机识别的最基础的语言。0 1码
- 纸带:交互能力太差
- 利用计算机语言:B语言–》unix(操作系统)
- 一定的编程语法
- 缺点B语言:可读性,可维护性太差 - C语言之父(unix):
- 肯.汤普逊和丹尼斯.里奇
- 自己写了C语言–
程序结构
- 基本结构
- 预处理指令,函数,变量,语句&表达式,注释
- 注释:
- 单行注释://注释内容
- 多行注释:/*注释内容*/
- 注释的用途:1.表明函数或者代码用意 2.版本说名等有用信息
- 打印函数:结果的输出
- 库/包
- #include <stdio.h> 面粉
- 提供基础的接口(基础应用)
- 主函数(main函数)
- 注意;每一个C语言工程中有且只能有一个main()函数
- main函数是我们程序的入口
- C语言中有严格的大小写区分
- int数据类型
#include <stdio.h> //预处理,帮助你加载已有包/库
#include <stdlib.h>
int main()
{
// 注释:注释在程序执行是不参加工作 帮你标注你的代码
//第一个c语言程序
/*
多行注释
q
w
e
r
d
f
*/
printf("Hello world!\n");//打印函数。
return 0;
}
- c语言各个令牌的组成,令牌可以是关键字,标识符,常量,变量。字符串或者一个符号
- 分号的意义:
- 意义重大。每一行代码的结束,都是由分号结果,如果每一行代码末尾没有分号,程序会报错
#代码规范
- 意义重大。每一行代码的结束,都是由分号结果,如果每一行代码末尾没有分号,程序会报错
- 错落有致
- 函数体内定义变量时,要将定义过程函数体中最顶端。
C语言标识符
- 概念:
- 标识符是用来标识变量,函数,或者其他的自定义项目名称。一个标识符以字符A-Z或者a-z或下划线开始,然后跟零个或者多个字母,下划线数字(0-9)
- 注意标识符不能以除字符下划线以外的的字符作为开头,不能以数字开头,否则程序会把他认为是一个数据,不是一个标识符。
- 注意:在进行函数命名或者变量命名或文件命名时不要以数字作为开头
数据类型
序号 | 数据类型 | 描述 |
---|---|---|
1 | 基本数据类型 | 算术数据类型(整数类型和浮点类型) |
2 | 枚举数据类型 | 常用来被定义程序中只能赋予其一定的离散整数型的数值 |
3 | void数据类型 | 缺省型 |
4 | 派生数据类型 | 指针 |
整数类型:
整形(关键字) | 字节数(bytes) | 范围值 |
---|---|---|
short | 2字节 | -3万~3万 |
long | 4字节 | -215次方-215 |
int | 2字节(32位操作系统)/4字(64位操作系统) | 。。 |
char(带符号) | 1字节 | -128~127/ 0~255 |
unsigned char(无符号类型) | 1 | 0-255 |
unsigned int(无符号类型) | 2字节/4字节 | |
unsigned long(无符号类型) | 4字节 | |
unsigned short(无符号类型) | 2字节 | 0~4294967295 |
浮点型
类型 | 存储大小 | 精度 | 整数位个数 | 小数位个数 |
---|---|---|---|---|
float(单精度浮点) | 4字节 | 小数据点后6位 | 8位 | 23位 |
double(双精度浮点) | 8字节 | 小数点后15位 | 11位 | 52位 |
long double | 16字节 | 小数点后19位 |
#include <stdio.h>//预处理 加入库/包
#include <float.h>
int main()
{
//主函数,程序运行的入口,花括号中的内容为函数体
//声明变量——变量的声明/定义要放在函数体的最顶端
float i;
printf("float max size = %d\n",sizeof(float));//输出float类型的最大字节数
printf("float max value = %E\n",FLT_MAX);//%E 以指数形式输出单,双精度实数。
printf("float min value = %E\n",FLT_MIN);
printf("float 精度:%d\n",FLT_DIG);
//输出float数据类型 %f
printf("float %f",i);
}
-
注意:
- float:
- 数据类型当小数点后第七位有数据值时符合四舍五入的原则讲数据整合到第六位进行输出。- 如果float后只是一个整数时,输出结果会讲其精度进行补全
缺省型void
-
概念:void是指没有确定的或者可指向的值
-
一般有以下三种情况
1. 函数返回为空。C语言中各个函数都拥有返回值,如果说不具有返回回值时,函数名使用void进行修饰。 2. 函数的参数为空,c语言当中各函数接收任何参数,你就可以在函数的参数列表中写入void 3. 指针指向void:执行的类型为void* 表达的时对象的地址,而不是类型。***内存管理
二进制数据
二进制数据:
-
概念:
-
最基本的机器语言是二进制码。—》机器是不是由一堆电路和电子元器件。
-
二进制码机器是如何识别的?机器对于输入输出(信号):电信号(逻辑电平)—》有电/没电 0 1
-
二进制对比十进制:(短除法)
二进制 十进制 0 0 1 1 10 2 100 4 1000 8 1100 12 1 0010 18 二进制到十进制:
二进制数 十进制数 10000 16 11100 1x4+1x23+1x22+0x21+0x2^0 28 计算机都是按位运算存储的。
-
变量
- 变量其实就是程序员在编码过程中器起的一个名字,名字的作用就是帮助程序员进行识别和使用。
- 定义内存,并且给内存进行命名
- 变量:
- 1.数据类型
- 2.变量名
- 注意:变量名的命名规则
- 1.符合标识符的规则:变量不能以数据开头和除下划线,字母这样的
- 2.不能使用已有关键字。错误例子:char int;//会报错
- 3.尽量不要和已有函数名重复。
- 注意:变量名的命名规则
- char i; i = 10;
- 变量的使用:
- 1.变量的声明-注意变量在不声明是无法使用,也就说变量想要使用必须进行声明。
- 2.变量的定义,也可以叫变量的初始化。
- C语言是一种编译型语言,面向过程开发的,编译型就是指程序只有全部的代码都正确才会输出结果,
- 在变量声明时,其实就是将变量和某一个内存相关连,而没有经过初始化的变量也就是说你这个变量表示的内存没有经过初始化,然后会将内存中原有的指直接输出,这个输出得结果时不一定的。
//引入头文件/包
#include <stdio.h>
int main() //主函数
{
//1.变量的声明 数据类型(空格)变量名;(最后以分号结尾)
int i;//整数数据类类型 i;
short a;//
char b;//整数类型中的字符型数据 b;
float c;//单精度浮点型数据
int d;//做一个定义
int j;//j只做声明不做定义直接将其输出
//我们的 i ,a ,b ,c其实在计算眼中就是在给内存起名字,方便于直观进行内存的数据存放和管理
//变量在声明时就可给它一个初始值,将其定义
/*
多行注释
注意大家在编码时要以分号结尾
*/
//2.变量的定义,实际实在给变量进行赋值
i = 10;
a = 233;
b = 'L';//字符的写法都是由char 类型定义 字符的表示方法就是英文状态下单引号中写。切记char 只是单字符
c = 80.233;
//变量在使用前必须声明。可以不进行定义但是必须进行声明
d = 100;
printf("i = %d\n",i);//%d针对整型数据输出的
printf("a = %d\n",a);//
printf("b = %c\n",b);//%c是单个字符输出使用使用的
printf("c = %f\n",c);//%f是输出浮点数时使用
printf("j = %d\n",j);//j直接输出没有经过定义
}
赋值操作
i = 10;//正确的读法为:将10赋给变量i
//注意在赋值操作中一般分为左值和右值。切记左值不能为 常量
常量
- 概念:常量就是指固定值,在程序的执行期间这个值时不会改边的,又称为字面量
- 常量可以时10进制,可以是八进制,可以是16进制, 0x开头的就代表时16进制,0开头的代表为8进制,不带前缀的就是默认的10进制数
- 整数常量
212 //十进制数
215U //U代表无法号整数-unsigned
21L //代表的长整数
0x001// 16进制数
020// 8进制数
- 浮点数常量
10.2 //浮点数产量
-
字符常量
转义字符 \ 含义 ’ ’ " " \t 制表符:多个空格 \n 换行符 \r 回车 \v 垂直制表符 -
字符串
- 概念:在C语言中由字符数组组成的称为字符串
- ‘a’ —> 字符a
- “hello world” —>就是由多个字符构成的。
- 注意:字符串使用双引号包含的。
如何定义常量
#define 常量名 常量值
- 注意:经过#define操作之后 变量名 就代表了一个常量,在之后的程序中不可以将这个变量名作为左值进行赋值操作。 不能#define的末尾添加分号
- 左值就是在赋值操作时(a=b)中的a的位置就是左值
//常量举例
#include <stdio.h>
//常量的定义方法
#define value 20 //注意没有分号 value 现在是一个常量
//赋值时常量不能为左值
int main()
{
int a;
a = value;
printf("a = %d \n",a);
}
运算符
算术运算符
a = 10 ,b = 2
运算符 | 描述 | 实例 |
---|---|---|
+ | 加法 | a+b 12 |
- | 减法 | a-b 8 |
* | 乘法 | a*b 20 |
/ | 取整除法 | a/b 5 |
% | 取余/取模除法 | a%b 0 |
++ | 自增 | ++b 前加 b++后加 |
– | 自减 | –b 前减b-- 后减 |
a+=2 运行过程为a = a+2;
关系运算符
//放到将条件语句的时候给大家讲
运算符 | 描述 | 实例 |
---|---|---|
== | 是否相等:判断左值与右值的数值是否相同 | |
> | 是否大于 | |
< | 是否小于 | |
>= | 是否大于等于 | |
<= | 是否小于等于 | |
!= | 是否不等于 |
逻辑运算符
运算符 | 描述 | 实例 |
---|---|---|
&& | 逻辑与:A条件&&B条件,当两个都为真是结果为真,有一个条件为假时即为假AB都为真,A&&B 结果为1 ,否则A&&B,有一个假的或者都是假的结果为0 | A&&B |
|| | 逻辑或:A || B,只有一个为真即为真,都为假才为假 | A||B |
!(英文状态下的!) | 逻辑非:!(A&&B(假)) 就变成真的了,非真条件为假,非假条件为真 | !A |
#include <stdio.h>
#define value 100
int main()
{
//主函数
int i;
int j;
i = 10;
if(i==value && i < value)//逻辑与都为真才为真
//if的条件判断就两种真或者假, 布尔值(bool)0 / 1
{
//执行内容
printf("条件满足\n");
}
j = (i==value && i<value);
printf("逻辑与结果为:%d\n",j);
}
#include <stdio.h>
#define value 100
int main()
{
int i = 10;
if(i>value||i<value)//这个条件中有一个为真
{
printf("条件满足\n");
}
printf("程序结束\n");
}
位运算符
运算符 | 描述 | 例子 |
---|---|---|
& | 与 | |
| | 或 | |
^ | 异或 | |
>> | 右移 | |
<< | 左移 |
赋值运算符
判断
-
概念:判断结构要求程序指定一个或者多个测试条件,以及通过条件之后要执行的内容(内容是必须要有的,不可为空)
-
if(条件)中的条件结果为0 和非0。结果为0时代表条件为假,否则条件为真
-
if(条件) { 满足条件的执行内容 } #include <stdio.h> //基础头文件的引入 #define Value 18 //这是的作用是什吗? ----》常量的定义 int main() { //主函数 int i;//变量的声明 i = 18;//变量的定义,赋值操作 if(i == Value)// i是否和value相等 { //条件通过之后执行的内容 printf("1. i和value值相等\n"); } //判断体之外的语句。不受判断体的影响c printf("2. 程序结束\n"); }
-
规则:如果条件满足时的执行语句只有一行代码时,可以不需要加大括号将执行内容包裹起来。如果执行内容时多行时,必须使用花括号将其包裹起来
-
#include <stdio.h> #define value 100 int main() { int i; i = 10; //代码格式 if(i == value) printf("1.i和value 相等\n"); if(i >= value) printf("2.i大于等于value\n"); printf("这是插入的语句\n"); if(i<=value) printf("3.i小于等于value\n"); if(i != value) printf("4.i不等于value\n"); printf("2.程序结束\n"); }
-
语句 | 描述 |
---|---|
if 语句 | if(条件) |
if … else语句 | if(条件1)else(除了条件1不满足其他的都满足) |
if的嵌套式语句 | if(条件1) else if(条件2) |
switch语句 | switch(条件) case…break…default…break |
A?B:C | 三元运算符,B,C都是执行语句。A是条件语句,A满住时执行B,不满足执行C |
#include <stdio.h>
int main()
{
int age;
age = 40;
if(age<18)//if 。。else 条件只有两个
{
printf("1.年纪为%d岁不可以谈恋爱,要多学习\n",age);
}
else if(age>=18 && age<=25)//如何实现 10<a<20
{
printf("2.年纪为%d岁,正是大好年华\n",age);
}
else if(age>25 && age<35)
{
printf("3.年纪为%d岁,爱情事业双丰收\n",age);
}
}
#include <stdio.h>
int main()
{
int money;
money = 30;
printf("我有%d块钱,能吃:\n",money);
switch(money)//money是结果 //条件
{
case 10://case value 注意只有条件和value 相等时才会执行
printf("吃一碗面条\n");
//切记需要在每一个case的执行内容中加入一个break;
break;//帮助你跳出执行体 打破
case 30:
printf("面条加啤酒\n");
break;
case 40:
printf("面条加啤酒加一盘小菜\n");
break;
case 50:
printf("面条加啤酒加一盘小菜加两鸡蛋\n");
break;
default: //以上条件都不满足时。执行 else
printf("以上都不满足\n");
break;
}
printf("程序结束\n");
}
- 注意1:switch(条件) { case 结果1 break … default …break} 只有当条件和结果相等时才执行内容。
- 注意2:break;跳出当前内容也就是直接到最近的一个花括号尾部。打破。。
三元运算符
#include <stdio.h>
int main()
{
int number;
number = 11;
number%2==0?printf("偶数"):printf("奇数");
}
课堂小练习:
eg:用三元运算符和if…else 。写出两个数值比较大小,
循环
-
概念:比如我们要执行一个语句多次,一般情况下都会使用循环来实现。
-
循环类型 描述 for 给定的条件为真的时候就执行循环语句,他在循环前先判断条件是否符合 while 多次执行语句代码。简化循环变量 do while 循环语句至少会执行一次,然后根据while()括号中的条件来判断是否继续执行循环语句 循环嵌套 循环套循环,列子见day03_07 -
for(a;b;c)
-
a代表的结果值,
-
b代表的条件
-
c代表的步进值。
-
注意:在for循环中a,c可以不写在for语句中,b必须在
-
#include <stdio.h> int main() { int i; i = 0; for(;条件;)//for循环中失去了结束条件,这个for循环会一直执行下去,形成死循环 { i+=2; printf("进入循环1\n"); printf("进入循环2\n"); } printf("i = %d\n",i); }
-
-
-
while():
-
括号中为循环条件,满足条件进行循环
-
在括号中写入非0的常量是构成死循环。
-
#include <stdio.h> int main() { int i; i = 0; while(i==0)//括号中就是循环条件,条件为真进入循环,假跳出循环 { printf("进入循环-----1\n"); printf("进入循环--2\n"); i = 1; } }
-
-
do…while…
-
#include <stdio.h> int main() { int i; i = 3; do{ printf("执行\n");//至少会执行一次 i--;// }while(i>1);//括号中就是循环条件 printf("结束\n"); }
-
-
循环的控制语句
-
控制语句 描述 break 语句 终止循环。直接结束循环 continue 语句 结束本次循环,进行下一次循环 goto 语句 将控制转移到被标记的语句, -
#include <stdio.h> int main() { int i; for(i=0;i<10;i++) { if(i%2==0)//i为偶数时 { continue; } printf("i = %d\n",i); } }
-
#include <stdio.h> int main() { int i; for(i=0;i<10;i++) { printf("i = %d\n",i); // break; } }
-
#include <stdio.h> int main () { int i; for(i = 0;i<10;i++) { if(i == 5) { goto end;//跳转点 } printf("i=%d\n",i); } end://标记点 printf("end i = %d\n",i); }
-
#include <stdio.h> int main () { int i,j; end: printf("结束\n"); for(i = 0;i<3;i++) { for(j = 0;j<10;j++) { if(j == 5) { goto end; } printf("j = %d ",j);//%d只是表示输出一个整型数据。\n换行 } printf("\n"); } }
- 注意:break,continue只能打破一层循环而goto语句可以打破多次循环
- 构建无限循环(死循环的方法)
- for(;😉
- while(1)
-
-
总结
- 逻辑运算符,
- 关系运算符
- 判断
- 循环
作业:
#include <stdio.h>
int main()
{
int i,j,k;//变量的声明
i = 0;
j = 0;//变量的定义
k = 0;
for(i=1;i<10;i++)
{
for(k=0;k<(10-i);k++)
{
printf(" ");
}
for(j=1;j<=i;j++)
{
printf("* ");
}
printf("\n");
}
}
- 有codeblock且能用的先不用动
- vscode
- 安装方法:1.mingw配置环境变量 2. vscode 运用商城下载 C/C++和Code Runner
函数
-
概念:函数是一组一起执行一个任务的语句。每一个c语言至少要有一个函数,也就是主函数。所有的简单代码都可以拥有额外的函数内容
-
函数的特性:高聚合,低耦合
-
示例
#include <stdio.h> //定义函数 /* 1. int 指的函数运行结束时返回值的数据类型 2. Add指函数名称 3. ()括号中的内容称为参数列表 4. int a,int b 称为形式参数也就是形参 5.花括号包含的内容为函数主体,也就是说函数的执行内容 */ /* 规则:一般会使用注释的方式对函数功能,返回值,以及参数进行说明 例如: function:加法函数 a:整数 b:整数 返回指为 整数类型 */ int Add(int a,int b)// { int c;//实参 c = a+b; return c;//返回值类型是由函数返回类型决定的 } int main() { //必须要要有的主函数 //函数的调用——》如果说函数想要执行,就需要主函输进行调用 int i,j,k; i = 10; j = 20; k = Add(i,j); printf("k = %d\n",k); }
-
注意:在同一个c文件中,函数如果定义在被调用之前,则不需要写函数声明,否则,也就是函数写在被调用之后必须书写函数声明,且在c文件的头部进行声明
-
C语言时编译型语言,也就是代码从main函数开始,自上而下执行,如果执行时发现未定义内容则报错
-
#include <stdio.h> //声明-注册 int MaxUnmber(int ,int);//声明时参数名称不是必要的,而参数类型是必要的 int main() { int c; c = MaxUnmber(100,80); printf("max = %d\n",c); } /* 输出两个数中的最大值 a 为整数 b 为整数 返回值为a,b中的最大值 */ //定义 int MaxUnmber(int a,int b) { if(a>b) return a; else return b; }
-
作用域规则
- 概念:任何一种编程里头,作用域就是程序中变量活动的范围,超过这个范围,这个变量就不能被访问和使用,
- 在单个函数范围内的变量——局部变量
- 在所有函数范围内的变量——全局变量
- 在形式参数范围中的变量——形式参数
- 注意:
- 1.局部变量和全局变量的变量名重复时,局部变量对于全局变量有屏蔽作用。
- 2.全局变量的生命周期是整个程序运行的时间,只要在运行过程中对全局变量发生了更改,那么其他地方再访问时这个全局变量的值就是发生过改边之后的值
- 3.形式参数对全局变量有屏蔽作用
- 4.形式和局部变量在同一个函数中时如果变量名相同,则会报错:变量的重复定义
数组
-
概念:数组是一种数据结构,它可以存储固定大小的相同类型的数据的顺序集合。
-
int array[10]:(一维数组)声明————type name [size]
- int :数组中存放的数据的类型,每一个数据数据称为元素,——》每一个元素都是int类型
- array:数组的名称 ,名称只要符格命名规则都可可以,例如 a,b,c 错误命名规则:以数字开头等。。(具体查看标识符的命名规则)
- /[10]:代表数组中元素的个数是10个
- 定义时
- eg: int array[10] = { }; //花括号中时相同数据类型的数据
-
访问方式:
-
通过 数组名[下标]的方式进行访问。下标的目标值的在数组中顺序位置从0计数开始的位置。
-
以循环的方式将数组中所有的值进行输出
-
通过对数组名[下标] = 数值的方式对其中的元素进行更改
-
#include <stdio.h> #include <stdlib.h> //需求:写10个数,从10-19 int main() { int a,b,c,d,e,f,g,h,i,j; //array 整数的数组 int array[10] = {10,11,12,13,14,15,16,17,18,19};//数组的初始化 //数组进行访问 //利用数组中元素的下标也就是位置,位置的计数是从0开始的 //列子访问 13拿出来 array[3] = 99; for(i=0;i<10;i++) { printf("array[%d] = %d\n",i,array[i]); } }
-
#include <stdio.h> int main() { char a[4];//数组的声明,数组中没有数值。 int i; a[0] = 'A'; a[1] = 'W'; a[2] = 'S'; a[3] = 'L'; for (i = 0;i<4;i++) { printf("%c",a[i]); } printf("\n"); }
-
-
多维数组
-
二维数组:多维中最简单的一种,本质上就是在一位数组的基础上加了列的概念,也就是说有x,y两个维度
- 定义/初始化
- type name [行数][列数] = { 元素}
- 注意:在定义/初始化时必须指定列数,行数可不写
- type name [行数][列数] = { 元素}
- 定义/初始化
-
练习—自己写一个三维和四维数组,然后利用循环将其输出
-
#include <stdio.h> int main() { //主函数 int array0[3] = {1,2,3};//一维数组 int array1[2][3] = {1,2,3,6,7,8};//二维数组1 int array2[2][3] = {//2*3 = 6个元素 {3,4,5}, {7,8,9} }//另一种写法:有两个1行3列数组 int array3[2][2][3] = {2,3,4,5,6,7,8,9,10,11,12,13};//元素个数就是数量的乘积2*2*3 = 12个元素 /* 2层拥有2个3列的数组 */ int array4[2][2][3] = { { {1,2,3}, {4,5,6} }, { {7,8,9}, {10,11,12} } } }
-
枚举 enum
-
概念:C语言中一种基本的数据类型,它可以让数据变得更加的简单,易读
-
语法格式为:
-
enum 枚举名 {元素1,元素2,};
-
#include <stdio.h> int main() { enum Day { MON, TUE, WED, THU, FRI, SAT, SUN, };//枚举的声明 enum Day day;//定义 day = SUN; printf("%d\n",day); }
-
#include <stdio.h> int main() { enum color {red=1,green,blue};//枚举的声明 enum color fav_color;//枚举的定义 while(1) { printf("输出你喜欢的颜色(1.red 2.green 3.blue):"); scanf("%d",&fav_color);//输出函数---****作用就是从控制台获取你得收入值 switch(fav_color) { case red://1 printf("你喜欢的是红色\n"); break; case green://2 printf("你喜欢的是绿色\n"); break; case blue://3 printf("你喜欢的是蓝色\n"); break; default: break; } } }
注意:enum 中默认是从0开始的,可以通过赋值方式对其进行更改
-
指针
-
概念:指针作为C当中的灵魂,如果进行内存和地址的访问,就需要使用指针,注意,指针不是一种变量,指针是指向地址的类型。
-
查看变量的地址
#include <stdio.h> int main() { int a;//整型a; char b;//字符b; float c;//浮点c //查看a , b ,c的存储地址, //存储地址就是指:a,b,c定义时计算机给分配的内存地址 //查看是利用指针指向他们所在的地址 //声明指针 /* 指向类型 * 指针变量名; */ int *p0;//指针p0指向一个整型数据的地址 char *p1; float *p2; p0 = &a;// &--->在位操作中是与操作,放在变量之前为取地址符 p1 = &b; p2 = &c; //%d->整数的打印占位 %f->浮点数 %c->字符 %p->地址的打印 //地址输出为16进制数 printf("a的地址为%p\n",p0); printf("b的地址为%p\n",p1); printf("c的地址为%p\n",p2); }
-
指针:数据类型 * 指针变量 ————》指向某种数据类型的地址的指针变量
-
不论这个数据类型是什吗样子的,不论是这个整型,浮点型,字符型,等等,对于指针来说其类型都是一样的,都是代表着一个16进制数的内存地址
-
因为和这个数据类型没有关系所以指针在内存存放时的大小始终是4/8(长度和编译环境有关系)个字节长度
-
#include <stdio.h> int main() { printf(" int占%d|char占%d|float%d|\n",sizeof(int),sizeof(char),sizeof(float)); printf(" int指针占%d|char指针占%d|float指针%d|\n",sizeof(int*),sizeof(char*),sizeof(float*)); }
-
指针的使用
-
使用指针是会有有以下操作:定义指针,把变量地址赋值给指针,访问指针变量种可用地址的指。这些都是通过元运算符*号来返回位于操作数所指定原来的地址的变量的值。
-
以下为案例
#include <stdio.h> int main() { int a; int*p;//定义一个指向整型的指针 a = 666; p = &a;//通过取地址符&将变量a的地址赋予指针p; //然后就可以通过指针p访问到地址a中的数值 printf("a = %d\n",a); printf("p指向的地址中的数值是多少%d\n",*p);//*p读作 对p取值 printf("变量A的地址是%p\n",&a); printf("变量p的地址是%p\n",&p); printf("变量p指向的地址是%p\n",p); //可以通过指针修改指针指向内存中的数据 *p = 30;//通过指针p改边了a变量内存中的数据 printf("a = %d\n",a); } 指针访问数组
指针访问数组
-
数组在内存中存储形式:连续的存储的每一个元素之前的地址间隔取决于元素的数据类型
-
数组的数组名代表了数组的存储地址的首地址,存放的是第一个数组元素
-
#include <stdio.h> int main() { int buffer[4] = {1,2,3,4};//4个int类型的数据 char buffer1[4] = {'c','b','d','!'}; int i; for(i=0;i<4;i++) { //利用循环将数组中每个元素的地址进行输出 printf("buffer[%d]的地址为:0x%p\n",i,&buffer[i]); } printf("buffer的首地址是0x%p\n",buffer);//数组名就代表了这个首地址 printf("--------------------------------------------\n"); for(i=0;i<4;i++) { //利用循环将数组中每个元素的地址进行输出 printf("buffer1[%d]的地址为:0x%p\n",i,&buffer1[i]); } printf("buffer1的首地址是0x%p\n",buffer1);//数组名就代表了这个首地址 }
-
-
通过指针进行数组的访问
-
注意:指针指向类型要与数组中的元素类型相同,否则在偏移时就会和数组中每个元素存放的地址不相同,无法正确访问。
-
#include <stdio.h> int main() { int buffer[4] = {1,2,3,4};//4个int类型的数据 char buffer1[4] = {'c','b','d','!'}; int i; //定义一个指针 int *p;//地址 for(i=0;i<4;i++) { //利用循环将数组中每个元素的地址进行输出 printf("buffer[%d]的地址为:0x%p\n",i,&buffer[i]); } printf("buffer的首地址是0x%p\n",buffer);//数组名就代表了这个首地址 printf("--------------------------------------------\n"); for(i=0;i<4;i++) { //利用循环将数组中每个元素的地址进行输出 printf("buffer1[%d]的地址为:0x%p\n",i,&buffer1[i]); } printf("buffer1的首地址是0x%p\n",buffer1);//数组名就代表了这个首地址 printf("------------------------------------------------\n"); //地址是可以通过指针进行访问的 p = buffer;//buffer代表首地址,也是数组第一个元素的地址 //p现在指向了数组第一个元素的地址,也就是数组的首地址 //通过指针p获取数组中的第一个元素,对地址进行取值操作 printf("数组buffer的第一个值为%d\n",*p);//p本就代表地址通过*号对地址进行取值 //地址+1,地址+1的步进值取决于p指向的数据类型 //p+1实际在内存中p向后/前移动了4个字节,刚到就到达了buffer[2]的地址 for(i=0;i<4;i++) { //利用循环,进行地址偏移 printf("p指向的地址为:%p,地址中存放的数值为:%d\n",p,*p); p += 1; } }
-
注意:
-
指针是指向地址的一种数据类型
-
指针通过别人的地址来进行访问其数据
-
数组的数组名代表了数组的首地址也就是第一个元素的地址
-
指针偏移的步进值取决于指针指向的数据类型
-
指向类型和数组类型不同时,注意步进值
-
#include <stdio.h> int main() { int buffer[5] = {7,8,9,10,99}; char* p;//指向字符类型的的地址的指针. int i; for(i = 0;i<5;i++) { printf("buffer[%d] = %d \t buffer[%d]的地址为:%p\n",i,buffer[i],i,buffer+i); } //p接收数组buffer p = buffer;//数组的首地址——>数组元素的第一个值得地址 //p每一次偏移1个字节,buffer的每一个元素的地址间隔是4个字节 //通过指针p输出uffer中的所有数据 printf("打印第一个元素:%d 地址:%p\n",*p,p);// printf("打印第二个元素:%d 地址:%p\n",*(p+4),p+4);// }
-
指针操作多维度数组
-
多维数组:所有的元素在内存中都是顺序存储的
-
#include <stdio.h> int main() { int a[2][2] = { 4,5, 6,7 }; int b[2][2] = { {14,5},//b[0] {77,88}//b[1] }; int c[2][3][2] = { { //c[0] {11,111},//c[0][0]-->这一个维度的首地址 {22,222}, {33,333} }, {//c[1] {44,444},//c[1][0]--->这个维度的首地址 {55,555}, {66,666} } } int *p; int i,j; for(i=0;i<2;i++) { for(j=0;j<2;j++) { printf("a[%d][%d] = %d,地址为:%p \t",i,j,a[i][j],&a[i][j]); printf("b[%d][%d] = %d,地址为:%p \n",i,j,b[i][j],&b[i][j]); } } p = a;//获取数组a的首地址 for(i=0;i<4;i++) { printf("p-a = %d\n",*(p+i)); } p = b;//获取数组b的首地址 for(i=0;i<4;i++) { printf("p-b = %d\n",*(p+i)); } printf("______________________________\n"); p = a[1];//--->数组a的第二行的首地址--也就是说a[1]代表了第二行的数组的首地址 printf("p获取的数据%d\n",*p); }
数组最为参数的传递
#include <stdio.h>
//声明
int Sub(void);
int main()
{
int result;
int main_array[3] = {0};
//result = Sub();//
//printf("result = %d\n",result);
printf("请输入3个数值:");
scanf("%d,%d,%d",&main_array[0],&main_array[1],&main_array[2]);
result = Sub2(main_array);
printf("result = %d\n",result);
}
int Sub(void)//函数的定义
{
int array[3] = {0};
int i;
printf("请输入3个数值:");
scanf("%d,%d,%d",&array[0],&array[1],&array[2]);
i = array[0]+array[1]+array[2];
return i;
}
int Sub2(int *array)
{
int i;
i = array[0]+array[1]+array[2];
return i;
}
指针作为参数传递
-
1.指针的实质意义是访问到内存中的数据,可以对内存中的数据直接操作
-
#include <stdio.h> #include <stdlib.h> //函数声明 void my(int a,int b); void her(int *a,int *b); int main() { int a; int b; a = 10; b = 20; my(a,b); printf("main a %d \n",a);//10 printf("main b %d \n",b);//20 printf("--------------------------\n"); her(&a,&b);// printf("main a %d \n",a);//11 printf("main b %d \n",b);//21 return 0; } void my(int a,int b)//变量有屏蔽作用 { a = a+1; b = b+1; printf("my a : %d\n",a);//11 printf("my b : %d\n",b);//21 } void her(int *a,int *b) { *a = *a + 1; *b = *b +1; printf("her a : %d\n",*a);//11 printf("her b : %d\n",*b);//21 }
-
函数指针
-
概念:
-
函数指针指向函数的指针变量
-
通常指针变量指向一个整型,字符型或数组等变量,而函数指针是指向函数的
-
函数指针可以像一般函数一样,用于调用和传递参数
-
示例:
-
type (*指针名称/函数名称)(参数1,参数2,…);
-
#include <stdio.h> //函数声明 //int max(int,int) int max(int a,int b); int main() { //定义一个函数指针 int (*p)(int,int) = &max;//&取地址符可以省略,max也就代表了函数地址 int a,b,c,d; while(1) { printf("请输入两个数值:"); scanf("%d,%d",&a,&b); d = p(a,b);//等价于 d=max(a,b); printf("较大的值为%d\n",d); } } /* 求最大值函数 int指函数的返回指为整型 max是函数名 a,b是形式参数,用来进行值的传递 */ //int max...函数的定义 int max(int a,int b) { //a>b?a:b b /* if(a>b) return a; else return b;*/ return a>b?a:b; }
-
-
回调函数
-
概念:
-
函数指针作为某个函数的参数来使用,简单来说就是由别人的函数执行时调用你得函数
-
/*在函数MyArray中定义了三个参数。其中第三个参数是一个 函数指针,在函数MyRound函数中返回一个随机值,将来要传入MyArray MyArray调用8次回调函数,并将其返回值复制给数组 */ #include <stdio.h> #include <stdlib.h> //函数声明 void MyArray(int *array,int Size,int (*p)(void)); int MyRound(void); int main() { int array[20] = {0}; int i; MyArray(array,20,MyRound); for(i = 0;i<20;i++) { printf("array[%d] = %d\n",i,array[i]); } } /* array:指向整型数据的指针 Size:整数 p:指向返回值为int类型且参数为void的函数的指针 功能就是将p指向的函数的返回值,放到数组里 */ void MyArray(int *array,int Size,int (*p)(void)) { int i; for(i=0;i<Size;i++)//循环次数 { array[i] = p(); } } //产生随机值 int MyRound(void) { return rand(); //随机值 }
-
形参列表/可变参数
-
我们有时候希望自己的函数的参数的个数是个动态的,而不是一开始就指定好参数的类型和个数的
-
#include <stdio.h> //函数声明 int sub(int number,...); int main() { sub(2,2,3); sub(3,2,3,4); } //求和函数 int sub(int number,...) { }
-
注意:
- sub函数的最后一个参数写成省略号也就是***…***,省略号之前的那个int代表了传递的参数的总和.
- 定义一个函数,最后一个参数为省略号,前面的可以设置自定义参数
- 在函数定义中创建一个va_list类型的变量,读取参数列表,这个变量在头文件 stdarg.h中声明
- 使用int参数和va_start宏来初始化va_list变量为一个参数列表 宏va_start在stdarg.h中声明的
- 使用va_arg宏和va_list变量来访问参数列表中的每个值
- 使用va_end清理赋予va_list的变量内存,记住每使用完一次就要进行清理
-
例子
-
#include <stdio.h> #include <stdarg.h> //函数声明 void my(int num,...); int main() { my(5,12,13,14,15,20); } //函数的定义 void my(int num,...) { va_list valist;//定义参数列表 int sum = 0; int i; /*为num个参数进行初始化*/ va_start(valist,num);// //访问赋值给valist中的所有参数 for(i=0;i<num;i++) { sum = va_arg(valist,int);//读取一次数据,返回为整数 printf("你传入的数据数值为:%d\n",sum); } //清理这个valist,准备下次使用时没有留存的垃圾值c va_end(valist); }
-
-
-
字符串
-
概念:字符串实际上是由null字符也就是***‘\0’结束一堆字符数组***,也就是说字符串是包含了以‘\0’结尾的多个字符的集合,集合也就是数组,这个数组被叫做字符串
-
#include <stdio.h> #include <stdlib.h> int main() { char start[5] = {'H','E','L','L','O'}; char start1[] = {"HELLO"};//字符数组+'\0' int i; printf("start="); for(i=0;i<5;i++) { printf("%c",start[i]); } printf("\n"); printf("start1=%s\n",start1); printf("start size %d\n",sizeof(start)); printf("start1 size %d\n",sizeof(start1)); }
-
-
字符串的定义:
-
1.字符串是一个由字符构成的数组,所以在定义字符串时完全符合数组的方法
-
#include <stdio.h> #include <stdlib.h> int main() { //定义字符串 //在定义字符串是不需要指定数组长度,计算会根据你写的内容计算长度存放起来 char buffer[] = {"Hello world!"};//12字符+‘\0’ 13 int i; //1。字符串长度是多少?————解:13个 printf("buffer的长度为:%d\n",sizeof(buffer)); //2。如何将字符串中的字符挨个取出 for(i=0;i<sizeof(buffer);i++) { printf("buffer[%d] = %c\n",i,*(buffer+i)); } printf("--------------------------------------\n"); for(i=0;i<sizeof(buffer);i++) { printf("buffer[%d] = %c\n",i,buffer[i]); } //3。如何整体输出这个字符串 printf("buffer = %s\n",buffer); return 0; }
-
-
字符串操作函数(API:接口函数)
-
使用前需要引入头文件 #include <string.h>
-
函数 描述 strcpy(s1,s2) 复制把字符串S2复制到字符串S1 strcat(s1,s2) 连接字符串,将S2字符串拼接到S1的末尾 strlen(s1) 计算字符串的长度 strcmp(s1,s2) 比较s1和s2的内容是否相同,如果相同返回0,如果不相同 s1>s2 返回值大于0 s1<s2返回值小于0,大于比较时时利用字符的ascall码进行比较的。 strchr(s1,ch) ch代表一个字符,s1是一个字符串。ch第一次在s1中出现的位置,返回的是一个指针 如果匹配不到返回指针 NULL strstr(s1,s2) s2字符串第一次出现在字符串s1种的位置,返回值是一个指针类型,如果匹配不到返回指针 NULL -
ascall码:计算机存储数据都是二进制值,于是就是把对应的字符转换成具体的数值进行存储
-
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { char s2[] = "xuao"; char s1[20] = {0};//定义空字符串 char s3[] = "tong"; char s4[] = "8个月,比他大";//内存中占12个 char s5[] = "MLXG"; char s6[] = "MLXG"; char s7[] = "8个月"; char ch = 'L'; char *p; int result; printf("s1被填充之前%s\n",s1); //复制操作,将S2的字符串内容复制到S1 /* 注意点, s1的长度要大于等于s2否则无法拷贝完整 */ strcpy(s1,s2); printf("s1复制了S2之后的内容为%s\n",s1); // //s1 = "xuao" //字符串拼接操作 /* 注意:s1的长度原来为5, 拼接后sizeof还是计数原始长度 */ printf("s2拼接前的内容:%s\n",s2);//xuao printf("s2的原始长度%d\n",sizeof(s2));//5 strcat(s2,s3);//xuao tong ->xuaotong printf("s2拼接后的内容:%s\n",s2); printf("s2的拼接后长度%d\n",sizeof(s2)); //计算字符串长度 /* 注意1.sizeof计算出的是占用的内存的字节数 strlen计算出的是字符串的字符长度 */ printf("sizeof计算出的长度%d\n",sizeof(s4)); printf("strlen计算出的长度%d\n",strlen(s4)); printf("-------------------------------------\n"); //字符串的比较 result = strcmp(s5,s2); if(result == 0) { printf("两个字符串完全相同\n"); }else if( result > 0 ) { printf("%s > %s\n",s5,s2); }else{ printf("%s < %s\n",s5,s2); } //单个字符在字符串中第一次出现的位置 printf("---------------------\n"); p = strchr(s5,'X');//MLXG L printf("%s \n",p); //一个字符串是否存在于另一个字符串当中 printf("---------------------\n"); p = strstr(s4,s7); printf("结果为:%s\n",p); }
-
-
typedef
-
它是一个关键字,你可以利用它给一个类型起一个新的名字,公式:typedef 数据类型 new_name;
-
#include <stdio.h> int main() { int a;//定义一个整型变量a typedef int iinntt; //将int 取别名为iinntt iinntt b;//定义一个整型变量b a = 10; b = 20; printf("a = %d b = %d\n",a,b); }
输入输出
-
概念:
- 输入要向程序填充一些数据,输入可以是文件形式或者命令行的形式。C提供了一些内置的输入函数
- 输出将数据输出到屏幕上,打印机或者文件进行显示一些数据,C提供了一些内置的输出函数
-
输出
-
#include <stdio.h> /* 所有的C都包含主函数main printf()函数就是将内容格式化输出到屏幕上 stdio.h中声明了printf()函数 #include 预处理命令,引入头文集过程 %d:整型用来匹配整型变量并将其输出到大屏幕 %f:浮点型(小数)用来匹配浮点型变量然后将其输出到屏幕 %c:字符型,用来匹配单个字符的变量然后输出到屏幕 %s:字符串的输出 %p:指针地址的输出 */ int main() { int a; float b; char ch; char str[] = "打雷了,要下雨"; int *c; a = 10; b = 100.1; ch = 'L'; c = &ch; printf("Hello world!\n"); printf("a = %d\n",a); printf("b = %0.2f\n",b);//0.2代表精确到小数点后两位 printf("ch = %c\n",ch); printf("str = %s\n",str); printf("c指向的地址为:0x%p\n",c); }
-
-
getchar()和putchar() api
-
int getchar(void)函数从屏幕读取一个字符,并把它返回成一个整数(这个字符对应的ascall码值)。这个函数在同一时间只会读取一个字符,也就是说每次只能从屏幕上获取输入内容中的一个字符
-
int putchar(int c)函数能把一个字符输出到屏幕上,并且返回一个相同的字符对应的ascall码值。每次执行只能输出一个字符,可以利用循环来让他输出多个字符
-
#include <stdio.h> int main() { int c; printf("please enter a value:"); c = getchar(); printf("get value ascall :%d\n",c); printf("putchar output value is:"); putchar(c); printf("\n"); printf("________________________________\n"); putchar(98);//b-->ascall }
-
-
gets()和puts() 函数
-
char* gets(char* s)函数从屏幕上读取一行字符到s所指向的内存中,直到一个终止符
-
int puts(const char* s)将字符串输出到屏幕上去,
-
#include <stdio.h> int main () { char str[100]; char str1[] = "啥阵型"; printf("你瞅啥?\n"); gets(str);//获取你在屏幕上输入的内容 puts(str1); gets(str);//获取你在屏幕上输入的内容 printf("别整了\n"); }
-
-
scanf()和printf()函数
-
int scanf(const char *format,…)
-
int printf(const char *format,…)
-
#include <stdio.h> #include <string.h> #define SIZE 100 int main() { int a; char str[SIZE]; char res1[] = "要"; while(1) { printf("许傲:彤彤啊你多大了?\n"); scanf("%d",&a);//&a也是指针 printf("彤彤:我今年%d岁了\n",a); if(a > 20) { printf("彤彤:老许老婆要不要?\n"); scanf("%s",str);//str是数组指针 printf("许傲:%s\n"); if(strcmp(str,res1) == 0) { printf("彤彤:就是我,死鬼\n"); }else{ printf("彤彤:哦\n"); } }else if(a < 20) { printf("许傲:吃鸡不?"); scanf("%s",str); printf("彤彤:%s\n",str); } } }
- scanf(“%s_%d_%c_%f”,指针);
-
强制类型转换
-
概念
-
就是将变量从一种数据类型转换成另一种数据类型
-
#include <stdio.h> int main() { int a; float b; int c; a = 100; b = 100.99; c = (int) b; printf("c = %d\n",c); printf("a = %f\n",(float)a); }
-
-
数据的转换
-
#include <stdio.h> int main () { char a = 'a'; int b; int c; b = 3; c = b + (int)a; printf("c = %d\n",c); }
-
-
类型转换层级关系
- int -> unsigned int -> long -> unsigned long -> long long -> unsigned long long -> float -> double -> long double
-
结构体
-
概念:
- C数组允许同种数据类型的变量,结构体时c语言中用户自定义的可用数据类型,它允许你可以存放不同的数据类型
-
结构体的定义、
-
#include <stdio.h> int main() { //定义结构体 struct Student{ char name[10];//名称 int age;//年龄 int grade;//成绩 }; }
-
struct 关键字
-
Student 结构体标签
-
char name 标准的变量定义
-
定义公式:
-
struct 结构体标签名 {
member-1;//成员1,数据类型由程序猿自己指定
member-2;
member-3;
//成员个数也是由程序猿自己指定
};
-
-
-
结构体的使用
-
#include <stdio.h> #include <string.h> int main() { //定义结构体 struct Student{ char name[10];//名称 int age;//年龄 int grade;//成绩 }; //定义只能告诉你结构体中包含了那些内容或者说属性 //如果想要使用结构体,需要进行结构的初始化 //结构体的初始化 //方法1 struct Student WangKai;//结构体变量WangKai //方法2 struct Student ZhaoDIngDing = {"赵丁丁",20,100}; //使用变量加.的方式访问结构体中内容 strcpy(WangKai.name,&"王凯");//name -> 指针 字符串 strcpy() WangKai.age = 20; WangKai.grade = 90; printf("wangkai的info\nname %s\nage %d\ngrade %d\n", WangKai.name,WangKai.age,WangKai.grade); printf("ZhaoDIngDing的info\nname %s\nage %d\ngrade %d\n", ZhaoDIngDing.name,ZhaoDIngDing.age,ZhaoDIngDing.grade); }
-
1.结构体的定义
-
2.结构体的初始化方法
-
-
结构体指针
-
指向结构体的指针。可通过指针访问结构体或者初始化结构体,
-
#include <stdio.h> #include <string.h> //全局变量 struct BOOK{ char name[20]; char Author_name[10]; int price; }; //函数声明 void BookInfo(struct BOOK book); int main() { int i; struct BOOK book1 = {"厉害吧","许傲",5}; struct BOOK book2 = {"在摸鱼","王怀彤",10}; struct BOOK book3 = {"可不得了","李冲",15}; struct BOOK book4 = {"班长在游戏","陈钊",200}; while(1) { printf("--------------------------------------------\n"); printf("| 1.厉害吧,2.在摸鱼,3.可不得了,4.班长在游戏 |\n"); printf("--------------------------------------------\n"); printf("请输入你要查看的书的id:"); scanf("%d",&i); printf("您查询的信息为:\n"); switch(i) { case 1: BookInfo(book1); break; case 2: BookInfo(book2); break; case 3: BookInfo(book3); break; case 4: BookInfo(book4); break; default: break; } } } //打印书的基本信息 void BookInfo(struct BOOK book) { //定义一个结构体指针 struct BOOK *p;//结构体指针 p = &book;//将book的地址赋值给结构体指针p //打印信息 printf("书名为:%s\n",p->name); printf("作者为:%s\n",p->Author_name); printf("售价为:%d元\n",p->price); }
-
-
递归
-
概念
-
在函数的定义自己调用自己
-
语法格式如下
-
void mode1() { line1; line2; .... model();//自己调用自己 } int main() { model(); }
-
例子
#include <stdio.h> //阶乘 5! = 5*4*3*2*1 /* 3 -- > 3*model(2)---> 3*2*model(1) == >6 */ double model(unsigned int i) { if(i<=1) return 1; return i*model(i-1); } int main() { unsigned int i; double result; while(1) { printf("输入一个整数:"); scanf("%d",&i); result = model(i); printf("%d 的阶乘结果为:%0.0f\n",i,result); } }
-
斐波那契数列
-
//斐波那契数列 #include <stdio.h> // 0 1 1 // 0 1 1 2 // int fibonaci(int i) { if(i == 0) { return 0; } if(i == 1) { return 1; } return fibonaci(i-1)+fibonaci(i-2); } int main() { int i; for(i=0;i<30;i++) { printf("%d-->",fibonaci(i)); } }
-
-
-
内存管理
-
动态内存管理,可以对内存进行申请,释放,扩充操作
-
序号 函数 描述信息 1 void*calloc(int num,int size) 在内存中动态的分配num个长度为size的连续空间,并且将内存中的原始内容会被清除为0. 2 void free(void* address) 释放(将内存归还给系统进行管理)address所指向的内存空间 3 void* malloc(int num) 在堆区指定分配一块指定大小的内存空间,这块内存只会被分配不会被初始化(不会清除其中原有的数据) 4 void realloc(void * address,int newsize) 重新分配address执行的内存空间的大小为newsize -
注意使用前引入头文件 <stdlib.h>