初识c语言
第一个c语言程序
写C代码
C代码
.c文件-源文件
.h文件-头文件head
添加源文件
基本框架:#include<stdio.h>
int main()//main函数-主函数-程序入口(fn+f10程序依次跑起来)必须有且只有一个 //int是整形的意思表示main函数返回一个整数值
{
//这里完成任务
//在屏幕上输出hello world!
//打印函数-printf(function)
Printf(“打印的内容\n”)
return 0;main函数基本框架
}
库函数-c语言本身提供给我们的函数-需要引入
#include<stdio.h>
包含一个叫stdio.h的文件
Std-标准-standard i-input o-output(需要输入或者输出的时候都需要引入这个头文件)
将源代码转换为可执行代码(用计算机语言表示的代码,用数字码表示的指令组成)
编译器会检查C语言程序设计是否有效,如果错误,就不生成可执行文件并报错。
数据类型
- Char字符数据类型(1字节)
- Short短整型(2)
- Int整型 (4)
- Long长整型(4)
- Longlong更长的整型(8)
- Float单精度的浮点数(4)
- Double双精度浮点数(精度更高)(8)
- 不同变量类型占用内存空间不一样,可以起到节省内存的作用
- C语言标准规定:sizeof(long)>=sizeof(int) 所以long型可以是4也可以是8.
C语言里面用单引号引起一个字符------’a’,双引号引起字符串,当然单个字符也可以是字符串
数据类型用来向内存申请一个空间来存放数据 -----------创建变量
char ch=’a’; char表示存放字符数据
printf(“%c\n”,ch); %c表示打印字符格式的数据,此处被打印的为ch.括号里面必需是双引号)
Int ch =getchar();//getchar获取用户输入一个字符,gatchar是一个无参数函数
Putchar(变量名);//输出一个函数
图中的程序
用户输入123456并回车之后,scanf会读取123456到变量password中,然后输入缓冲区内就还会剩下一个‘\n’,就接下来直接被getchar读取走了,则没有允许用户输入,就直接输出放弃确认。
解决上述问题,可以在scanf之后直接加上一个getchar(),先把’\n‘读取走,则不会影响接下来的步骤。
定义变量时,变量类型前面必须有类型
int age=20; int是整型
printf(“%d\n”,age); %d表示打印十进制数据
short int短整型(与整型只是空间上的区别)
%d打印整型 %C打印字符 %f打印浮点型---小数 %p以地址形式打印 %s打印字符串 %1f用于打印double类型的
double b=3.14;
printf(“%lf\n”,b); 此处应该使用%lf用于打印双精度浮点数。
Sizeof()函数可用于验证上述不同类型的数据的内存
Printf(“%d\n”,sizeof(char))可打印出来char数据类型所占的内存
Printf(“%决定打印的类型+\n”,待打印的数据名称)使用printf一定要加头文件引入这个函数
字节
计算机中的单位:
最小的单位------bit------比特位 (8个比特位的数列有2的八次方种排列,最大值为2的八次方减一)
计算机是硬件----通电----分为正电(1)负电(0)-----计算机可以识别这种指令
然后存放一个(1)/(0)的空间就叫做一个比特位(表示的是二进制)
Byte------字节--------一个字节=8个比特位的空间
kb=1024byte
1024mb =gb 1024tb=pb
变量
Eg.想要存一个东西,就要像内存申请空间,这个时候就需要创建一个变量。
#include stdio
int main()
{
//年龄
//20
short age = 20;//像内存申请两个字节=16个比特位来存放数字二十
float weight = 95.6f;//向内存申请4个字节,存放小数。加f是因为系统会判定95.6为双精度函数------------一般float类型的都会在后面加一个f.
printf("hello world/n");
return 0;
}
定义变量的方法:类型+变量名+赋值;
Int age=20;
Float weight=45.5f;
Char ch=’w’;
变量又分为局部变量和全局变量。
#include stdio
int num1 = 1;//全局变量-定义在代码块({})之外的变量
int main()
{
int num2 = 2;//局部变量-定义在代码块({})之内的变量
int num1 = 30;//局部变量和全部变量的名字建议不要相同,容易产生bug,同时,局部变量优先。
printf("%d\n", num1);
return 0;
}
&取地址符号 编号/命名对应地址
Int age=20;//4个自己的空间
Scanf函数
#include<stdio.h>
int main()
{
//计算两个数的和
int num1 = 1;
int num2 = 2;
int sum = 0;
//输入数据-使用输入函数scanf类似于python的input函数
#define _CRT_SECURE_NO_WARNINGS 1这个头文件,就可以正常运行,这个头文件可以让c语言许多不安全的函数正常运行。经过设置,可使源文件自动给含有这个抬头(初识c语言第二讲有讲)
scanf_s("%d%d", &num1, &num2);//&为取地址符号,哪个值放在哪个地址处,一一对应,待输入的值,此处直接使用scanf会报错,因为scanf是c语言提出的,所以需要引用头文件。而此处的scanf_s是vs这个编译器的专有,这时候代码不具有跨平台性,可移值性
//int sum=0;(报错,c语言规定变量要定义在当前代码块的最前面)
sum = num1 + num2;
printf("sum=%d\n", sum);//引号内的sum=%d中%d会被替换,sum=保存,最终结果变为sum=30.
return 0;
}
变量的作用域和生命周期
变量哪里可用,哪里不可以用,局部变量的作用域是局部范围{},全局变量的作用域是全部范围
int main()
{
{
int num = 0; //此处num的作用域即为它所在的这个大括号,则下面那个printf找不着num,会报错。如果将该条命令移动到这个大括号里面,则任务可以正常进行。局部变量出了这个大括号就被销毁了。
}
printf("num=%d", num);
return 0;
}
int main()
{
int num = 0; //在其对应括号内都起作用,包括它包含的括号
{
printf("num=%d", num);
}
return 0;
}
int global = 2020;//全局变量在整个工程,任何地方都可以用
//函数
void test()
{
printf("test()--%d", global);
}
int main()
{
test();
printf("%d\n", global);
return 0;
}
全局变量在整个工程,任何地方都可以用(可以跨越源文件之间),因为作用域是整个工程项目。
全局变量即为不在任何一个大括号内的变量
跨域源文件时,直接引用变量名会报错(提示:未声明的标识符)
声明:extern外部符号的声明符号
Eg.extern int globa;(globa来自于同一项目中的其他文件)
生命周期:变量什么时候存在,什么时候不存在
局部变量的生命周期是:进入作用域生命周期开始,出作用域,生命周期结束。
即出了作用域,就不可再使用(生命周期与作用域相雷同)
全局变量的生命周期是:整个程序(main函数的生命周期)的生命周期。
点击视图里面的解决方案资源管理器,就可以召唤右侧边栏。
各个源文件之间是相通的,例如他们之中只能含有一个主函数
常量
不可变-------1.字面常量2.const修饰的常变量3.#define定义的标识符常量4.枚举常量
字面常量:
//常量与变量的区别:变量可以被再次赋值,而常量不可以
const修饰的常变量
//const-常属性
//const修饰的常变量
int main()
{
const int num = 5;
printf("%d\n", num);
//num = 8;报错,常量不能被赋值{此处num仍是个变量,但是具有常属性,不能被改变}
printf("%d\n", num);
return 0;
}
#define定义的标识符常量
#define max 10
const int num = 5;
//int arr[num] = { 0 };报错,因为num本质是变量。
int arr[max] = { 0 };//arr[]这个括号内只能用常量,因此可以用来验证一个数据是不是常量
printf("%d\n", max);//输出10
不难看出,const修饰的常变量是具有常数性质的变量,而#define定义的标识符常量其本质就是一个常量
枚举常量
//枚举-可被一一列举eg.性别,三原色,星期
枚举关键字-enum
enum Sex
{
MALE,//0
FEMALE,//1
SECRET//2
};//MALE,FEMALE,SECRET-枚举常量
int main()
{
//enum Sex s=FEMALE;
printf("%d\n", MALE);
printf("%d\n", FEMALE);
printf("%d\n", SECRET);
枚举常量含有默认值,放在枚举里面的常量
enum Color
{
RED,//0
YELLOW,//1
BLUE//2
};//MALE,FEMALE,SECRET-枚举常量
int main()
{
enum Color color1 = BLUE;//color1是变量,而枚举括号内的是常量,本身无法改变
printf("%d\n",color1);}
字符串
由双引号引起来的一串字符为字符串字面值(字符串的标志是以\0结尾,在计算字符长度时,\0是结束标志,不看做字符串的内容)
Eg.”abcde”;
\0的重要性
int main()
{
char arr1[] = "abc";//字符串放到一个字符数组里面了,双引号为字符串,单引号是单个字符
char arr2[] = { 'a','b','c' };
char arr3[] = { 'a','b','c',0 };
printf("%s\n", arr1);//输出结果为abc---------可直接打印数组,以字符串的形式。
printf("%s\n", arr2);//输出结果:abc烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫虜悪
printf("%s\n", arr3);//输出结果为abc
return 0;
}//1和3结果相同,因为“abc”这个字符串其实包含四个元素--'a','b','c','\0'.’\0’是字符串结束标志。2中没有结束标志,就打印了一些随机值。3则是主动放置了结束标志,可以是’\0’,也可以是0,故3和1相同。
\0 、0、‘0’的区别:‘\0’转义字符的ascii码值是0,’\0’与数字0相同,但不与‘0’相同,‘0’的ascii码值是48,‘a'字符的值是97(ASCII表)
EOF-end of file
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abc";
char arr2[] = { 'a','b','c' };
printf("%d\n",strlen(arr1));//strlen-string length-计算字符串长度的
printf("%d\n",strlen(arr2));
return 0;
}//输出结果分别是3和42,说明字符串里面'\0'不被计入长度,但是该字符串里面有这个字符。
char arr[] = { 'b','i','t' };
printf("%d\n", strlen(arr));//没有结束标志,所以长度为随机值
char字符类型
strlen函数:头文件为#include<string.h>
用于计算整个字符串的长度,不包含结束字符’\0’。
转义字符
改变字符原本的意思
\t
int main()
{
printf("c:\test\32\test.c");//输出结果为c: est est.c
//\t-水平制表符-相当于一个tab键
\\
printf("c:\\test\\32\\test.c");//用于转义反斜杠,输出单个反斜杠
return 0;
\?
printf("(are you ok ? ? )\n");类似于这种??+)为了防止被解析为三字母词,用\?保留多个?
\’,\”
int main()
{
printf("%c\n", 'a');//打印a
printf("%c\n", '\'');//打印',\用于转义
printf("%s\n", "a");//打印a--------字符串与字符的区别
printf("%s\n", "\"");//打印"(转义之后打印才不会报错)
return 0;
}
\xdd dd表示两个十六进制数字。如:\x20 0 //区分八进制与十六进制就是有无x
#include<stdio.h>
#include<string.h>
int main()
{
printf("%d\n", strlen("c:\test\32\test.c")); //13----\t为一个字符,\32也是一个字符,表示2个八进制数字
//32作为八进制代表的那个十进制数字-----26------作为ascii码值对应的那个字符
printf("%d\n",strlen("c:\\test\\32\\test.c"));//17----\\表示一个\
return 0;
}
printf("%c\n", '\32');//打印出来一个26对应的→
printf("%c\n", '\x61');//打印出来一个6*16+1=97对应的字符 -a
\后面直接加数字是八进制,加个x再加数字是十六进制
48-57对应数字0-9,65-90对应A-Z,97-122对应a-z.(同一字母的大写与小写之间相差32)
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
int input = 0;
printf("加入比特\n");
printf("你要好好学习吗?(1/0)>:");
scanf("%d", &input);//1/0
if(input == 1)
printf("好offer\n");
else
printf("卖红薯\n");
return 0;
}
-
循环语句
while语句,for语句,do while语句
While语句
int main()
{
int line = 0;
while (line < 20)
{
printf("敲一行代码:%d\n",line);//输出形式为------敲一行代码:16(行数)
line++;//循环一次,行数加一
}
printf("好offer\n");
return 0;
}
一种方法使人人都可以调用它
Eg.add()为一个函数使两数相加
Sum=add(num1+num2);-------sum=num1+num2
sum=add(a+b);--------sum=a+b
库函数
- Sleep(1000)//经过一次sleep就会休息1000ms=1s.单位是毫秒。
头文件 #include<windows.h>
- System()执行系统命令的一个函数
System(“cls”)----cls---清空屏幕的一个函数
头文件 #include<stdlib.h>
System(“pause”)-----用系统函数暂停程序执行,等待任意操作来继续执行程序
- strcmp用于判断两字符串是否相等,不能用==判断
Strcmp(字符串1,字符串2),如果两字符串相等,则该函数返回结果是0
Eg.If(strcmp(password,”hu8yg”)==0)
头文件为 #include<string.h>
- strlen函数:头文件为#include<string.h>
- Int rand(void)-----------生成一个随机整数-------头文件#include<stdlib.h>
在调用rand函数之前,使用srand来调用rand,可以保证按照不同的顺序生成随机数。
自定义函数:
//一定不能忘记对函数输出数据类型的定义
- Int(函数最终返回值的类型) Add(int x, int y)
{
int z = x + y;
return z;
}
- int Max(int x, int y)
{
if (x > y)
return x;
else
return y;
}
int main()
{
int a = 10;
int b = 15;
int c = 0;
printf("%d\n", c);
return 0;
}
一组相同类型元素的集合
数组如果初始化,可以不指定数组的大小。可以不指定数组大小,但是[]不可以少,同时,数组前面,数组类型的定义也不可以少。
Int arr[]={1,2,3,4,5,6,7,8,9,0}
数组的大小必须由常量指定。
Int arr[n] 报错
Char ch[10]=“hello bit”
int arr[10];//定义一个存放十个整数数字的数组
char arr2[5];//定义一个存放五个字符的数组
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };//数组的值放在{}里面,只有一个也要{0}
int i = 0;
while (i < 10)
{
printf("%d", arr[i]);//使用下标可以访问元素,下标是从0开始的
i++;
}
return 0;
}
算数操作符:
+、-、*、/、%取模(取余数)eg.5%2=1
移位操作符:
>>右移、<<左移、移(2进制位----存储)
int main()
{
int a = 1;
int b = 0;
//整形占4个字节-32个bit位
//0000000000000000000000000000000001
b=a << 1;
//0000000000000000000000000000000010
printf("%d\n", b);//b=2
printf("%d\n", a);//a=1不改变
return 0;
}
位操作符:
&按位与 ^按位异或 | 按位或 -----依然是二进制位
int main()
{
int a = 3;//11(二进制序列)
int b = 5;//101(二进制序列)
int c = a & b;//将a视为011,然后与b中的101按位依次,按照与(取交集)的规则,1为真,0为假,两个都为真才是真
//011
//101
int d = a | b;//按位或,有一个为一,则为真
int e = a ^ b;//异或的计算规律:对应的二进制位相同,则为0,对应的二进制位相异则为一。如果有位需要取反,则使之与1按位异或即可。如果本身是1,那么和一异或,就变为0,如果本身是0,就变为1
printf("%d\n", c);//输出c为001----1
printf("%d\n", d);//输出d为111----7
printf("%d\n", e);//输出e为110----6
return 0;
}
赋值操作符:
=赋值符(==判断相等) 复合赋值符:+=(增量赋值) -= *= /= &= ^= |= >>= <<=
单目操作符:
!逻辑反操作
int a = 10;
//在c语言中,0表示假,非0全为真
printf("%d\n", a);
printf("%d\n", !a);//!为逻辑反操作,逻辑即指是与非,则是把真变为假,假变为真。此处输出0
-负值 +正值(基本省略)
&取地址
sizeof操作数类型的长度(以字节为单位)-----变量/类型所占空间的大小
int a = 10;
printf("%d\n", sizeof a);//括号可以去掉
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(int));//这三种写法结果完全相同。----Int这种写法不可以去括号,报错。
数组:int arr[10] = {0};//十个整型元素的数组=10*sizeof(int)=40
int sz = 0;
printf("%d\n", sizeof arr);//40
//计算数组元素的个数=数组总大小/每个元素的大小
sz = sizeof(arr) / sizeof(int);//10
printf("%d\n", sz);
~对一个数的二进制(ascii码)按位取反
int a = 0;//4个字节,32个bit位
//00000000000000000000000000000000000000---源码
int b = ~a;//按位取反(二进制取反,则在0和1)
//11111111111111111111111111111111111111----补码
//11111111111111111111111111111111111110----反码
//100000000000000000000000000000000000001----源码-----所以得到的值是-1
printf("%d\n", b);//-1
二进制的最高位表示符号位,符号位是1,则为负数,是0,则为正数
整数内存中储存的都是二进制的补码
正数-源码,反码,补码相同
负数在内存中存储的时候存储的是二进制的补码,打印的是源码
源码求补码:源码符号位不变,其他位按位取反得到反码,反码加一得到补码。
补码求源码:补码先减一得到反码,反码再除符号位以外,按位取反,得到源码。
--前置、后置--、++前置、后置++
int a = 10;
int b = a++;//后置++,先把a的值赋值给b,再对a+1
int c = 10;
int d = ++c;//前置++,先对c+1,再把c的值赋值给d
printf("%d\n", a);//11
printf("%d\n", b);//10
printf("%d\n", c);//11
printf("%d\n", d);//11
*间接访问操作符(解引用操作符)
int* p=&a;
*p=20;(等同于将a赋值为20)
*解引用操作符,解开地址找到对象a,将其改变为20
(类型)强制类型转换
int a = 3.14;直接操作会报警告,3.14是double类型
int a = (int)3.14;强制转换,无警告
双目操作符:
有两个操作数eg.a+b
三目操作符(条件操作符):
有三个操作数----b?x:y先计算条件b,然后进行判断。如果b的值为true,计算x的值,运算结果为x的值;否则,计算y的值,运算结果为y的值。一个条件表达式绝不会既计算x,又计算y。条件运算符是右结合的,也就是说,从右向左分组计算。
:exp1?Exp2:exp3
int a = 10;
int b = 15;
int max = 0;
max=(a > b ? a : b);//如果1为真,则将2的值赋值给max,反之,则是3的值
printf("%d\n", max);
关系操作符:
比较大小
> < >= <= != ==
逻辑操作符:
&&与(同真) ||或(一真即可)
0表示假,非0就是真
int a = 3;
int b = 5;
int c = a && b;
printf("%d\n", c);//1
逗号表达式:exp1,exp2,exp3,……expn
下标引用[] Eg.arr[4]
函数调用() Eg.add(a,b)
. ->
常见关键字
不可以自己创建
define不是关键字
.局部变量前面都有auto,省略不写而已
.break跳出循环
.enum枚举
.extern引入外部符号
.register建议把变量放入寄存器(空间有限)
.int定义的变量是有符号的,可以为-2,int=signed int
.unsigned int定义无符号数,永远为正数。
.static修饰变量和函数的。修饰局部变量,可以使局部变量生命周期变长。修饰全局变量时,让静态的全局变量只能在自己所在的源文件内部使用,出了源文件就无法再次使用了,使全局变量作用域变小。extern可以用于引入外部符号,而用extern引入static修饰的变量就会报错。修饰函数时,与全局变量相类似,外部函数也需要用extern引入,
格式:extern int(函数输出格式) add(intx,inty).同样的,引入static修饰的函数也会报错。改变了函数的链接属性,正常函数是具有外部链接属性的。使用了static就变成了内部链接属性。
局部变量:
void test()
{
//int a = 1;这样整个程序输出结果为22222,局部变量在出{}时就被销毁了,所以每次调用test函数时,a都需要重新创建,变为1
static int a = 1;//这样输出结果为23456,局部变量寿命变长,不会被销毁,就不用重新创建 -----------static修饰的变量不是不可以被修改。
a++;
printf("%d", a);
}
int main()
{
int i = 0;
while (i < 5)
{
test();
i++;
}
return 0;
}
.void用于创建函数,表示没有返回值
.struct结构体关键字
.typedef类型重定义 eg.typedef unsigned int u_int-------------创建别名,化繁为简
.union联合体
定义名字不能与关键字名字重合
define定义常量和宏
.#define定义的标识符常量
#define max 10
.宏
#define MAX(X,Y) (X>Y?X:Y)
int main()
{
int a = 10;
int b = 20;
int max = MAX(a, b);//宏的方式(a>b?a:b)
printf("%d\n", max);
return 0;
}
指针
内存:分为多个小空间------一个个小的内存单元,每个空间都编了号---地址
如何产生地址-----32位:32根地址线/数据线(电信号用1正0负来表示)----总共有2的32次方个二进制序列,产生这么多个二进制编号,对应2的32次方个字节---4g内存空间
int a = 10;//4个字节
//&a,取地址符号
int* p = &a;//有一种变量是用来存放地址的,就叫指针变量,类型为int*
printf("%p\n", &a);//000000333C8FFC04地址,存好地址后解开可以用。
printf("%p\n", p);
*p=20;//*解引用操作符,解开地址找到对象a,将其改变为20
printf("%d\n", a);//20
指针的大小,32位平台上为32个比特位,四个字节
64位平台上是64个比特位,8个字节(地址大小是不改变的)
char ch = 'w';
char* pc = &ch;//这次取地址的类型为字符,所以要用char*
*pc = 'a';
printf("%c\n", ch);//a
printf("%d\n", sizeof(pc));//8个字节。地址命名与变量无关
double d = 3.14;
double* pd = &d;
*pd = 5.5;
printf("%f\n", d);//5.500000
printf("%f\n", *pd);//5.500000
printf("%d\n", pd);//- 19924344
d=*pd
pd=&d
结构体
复杂对象:我们自己创造出来的一种类型
创建结构类型:
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;//可对其进行修改
printf("修改后的价格:%d\n", b1.price);
//b1.name="c++",会报错,因为原本的name是字符串,不可改变。成员是字符串的赋值形式的 变量要改变,都需要使用strcpy-----改变字符串
strcpy(b1.name,"C++");//strcpy-string copy-字符串拷贝-库函数-头文件-string.h
printf("%s\n", b1.name);//结果变为c++
return 0;
}//书名:c语言程序设计//价格:55//修改后的价格:15
struct Book b1 = {"c语言程序设计",55};
struct Book* pb =&b1;//指针类型变为了struct Book
//利用指针打印书名
printf("%d\n", (*pb).price);//55,此处指针地址的解用,需要括号括起来
printf("%d\n", pb->price);//.操作符运用于结构体变量,找到结构体成员。->结构体指针指向成员
//有两层循环要直接跳出就要用return