C语言基础
c语言是结构化 的程序设计----顺序结构,选择结构,循环结构
一、C语言入门
一、hello world
1 2 3 4 5 6 7 8 9 10 11 12 eg: #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> int main () { printf ("hello world\n" ); return 0 ; }
程序从main函数开始执行,且只有一个
return 返回0,int是整型,然后返回一个整型0
print f 打印函数 \n换行
include 包含一个名字叫stdio.h的文件
二、数据类型
char 字符 ’ ’ 打印字符 %c打印字符格式
1 2 3 4 5 6 int main () { char ch = 'A' ; printf ("%c\n" ,ch); return 0 ; }
int 整型 %d
1 2 3 4 5 6 int main () { int age = 20 ; printf ("%d" ,age); return 0 ; }
%f–浮点型 %lf–double型 %p—以地址打印 %x—打印16进制
%c在C语言中代表字符型格式符
%s在C语言中代表字符串型格式符
字符占用长度
字符
字节(8个比特位)
char
1
short
2
int
4
long
4
long long
8
float
4
double
8
三、键盘输入函数-----scanf()
1 2 3 4 5 6 7 8 9 10 11 12 int main () { int num = 0 ; int num1 = 0 ; int sum = 0 ; printf ("请输入两个数\n" ); scanf ("%d%d" ,&num,&num1 ); sum = num + num1; printf ("结果是%d" , sum); return 0 ; }
四、变量的作用域和生命周期
作用域(scope) ,程序设计概念,通常来说一段代码中所用到的名字并不是总是有效的,而限定这个名字的可用性的代码范围就是这个名字的作用域。
生命周期 ,变量的生命周期是指变量的创建到变量销毁的一个时间段
五、常量
1.字面常量
将变量转换为不可变的固定常量
相当于java的fianily
define定义的标识符常量
1 2 3 4 5 6 7 #define MAX 10 int main () { int arr[MAX] = { 0 }; printf ("结果是%d" , MAX); return 0 ; }
2.枚举常量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 enum Sex { MALE, FEMALA, SECRET }; int main () { printf ("结果是%d" , MALE); printf ("结果是%d" , FEMALA); printf ("结果是%d" , SECRET); return 0 ; }
3.字符串的打印
1 2 3 4 5 6 7 8 int main () { char arr1[] = "abc" ; char arr2[] = { 'a' ,'b' ,'c' ,0 }; printf ("%s\n" ,arr1); printf ("%s\n" , arr2); return 0 ; }
** \0 表示字符串的结束符
1.strlen()–字符串统计函数 string length–计算字符串长度
eg:arr2的abc后面放着一个随机值–直到0为止
二、循环语句
1、if–else
1 2 3 4 5 6 7 8 9 10 11 int main () { int input = 0 ; printf ("你要好好学习吗(1/0)" ); scanf ("%d" , &input); if (input == 1 ) printf ("要好好学习" ); else printf ("不要" ); return 0 ; }
2.while循环
1 2 3 4 5 6 7 8 9 10 11 int main () { int line = 0 ; while (line <= 100 ) { printf ("敲了一行代码%d\n" ,line); line++; } printf ("你已经是大牛啦" ); return 0 ; }
三、方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 int Add (int x , int y) { int z = x + y; return z; } int main () { int num1= 10 ; int num2 = 20 ; int sum = 0 ; int a = 100 ; int b = 200 ; sum = Add(num1, num2); printf ("结果是%d" , sum); sum = Add(a, b); printf ("sun = %d\n" , sum); scanf ("%d,%d" ,&c,%d) int sum=Add(c,d) printf ("%d\n" ,sun) return 0 ; }
add()自定义函数
四、数组
int arr[10]={1,2,3,4,5}
打印数组所有元素
1 2 3 4 5 6 7 int arr[10 ]={1 ,2 ,3 ,4 ,5 }int i=0 while (i<10 ){ printf ("%D" ,arr[i]); i=i+1 ; }
五、异或非
^ 异或:对应的二进制相同则为0,相异则为1
给你们句口诀与:全一则一 或:有一则一 异或:有一则一全一则零
六、常见关键字
typedef关键字
typedef:类型定义,这里理解为类型重命名
例:
1 2 3 4 5 6 typedef unsigned int unit;int main{ unsigned int num =0 ;uint num1=0 ; }
static关键字
用来修饰变量和函数的
1.修饰局部变量-称为静态局部变量
2.修饰全局变量-称为静态全局变量
3.修饰函数-称为静态函数
①
修饰局部变量时改变了变量存储位置,修饰全局变量时这个属性变成内部链接属性,其他源文件不能使用
register关键字–寄存器
1 2 3 4 5 int main () { register int num=3 return 0 ; }
define–定义常量和宏
宏 是有参数的–宏是完成替换的
define ADD(x,y) (x+y)【无类型的】
宏名 宏参数 宏体
7.指针
1.内存
内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的。
所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节。为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址。
指针就是地址----使用指针就是使用地址
指针的大小是相同的
指针需要多大空间,取决于地址的存储需要多大空间
2.指针是什么?
在计算机科学中,指针( Pointer )是编程语言中的一个对象,利用地址,它的值直接指向( points to )存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针"。意思是通过它能找到以它为地址的内存单元。
&a取到的地址是a四个字节的第一个字节
存放地址的变量叫指针变量
指针在32位平台为4个字节,64位为8个字节
%p—打印地址
3.指针和指针类型
指针类型决定了:指针解引用的权限有多大
指针类型决定了,指针走一步能走多远(步长)
int+4,char+1,double+8字节
4.野指针
野指针是指指向位置是不可知的(随机的,不正确的,没有明确限制的)
1.指针未初始化
2.越界访问
3.指针指向的空间释放
5.如何规避野指针
指针初始化
小心指针越界
指针指向空间释放即使置NULL
指针使用之前检查有效性
6.指针的运算
1.指针±整数
2.指针-指针
3.指针-指针得到的是指针之间元素的个数
4.指针的关系运算
7.指针与数组
数组名是数组首元素的地址
8.二级指针**
9.指针数组
存放指针的数组—int* p[5];//整型指针的数组
结论:指针数组是一个数组,每个数组元素存放一个指针变量
10.数组指针
int (*p)[5];
结论:数组指针是一个指针,它指向的是一个数组
11.解引用
在一个地址前面加上取值运算符“*”,即把一个地址取出来,这种操作就叫解引用
12.二维指针数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <stdio.h> int main () { int arr[4 ][5 ]={0 };int i,j,k=0 ; for ( i = 0 ; i < 4 ; i++) { for ( j = 0 ; j < 5 ; j++) { arr[i][j]=k++; } } printf ("*(arr+1):%p\n" ,*(arr+1 )); printf ("arr[1]:%p\n" ,arr[1 ]); printf ("&arr[1][0]:%p\n" ,&arr[1 ][0 ]); printf ("**(arr+1):%d\n" ,**(arr+1 )); printf ("*(*(arr+1)+3):%d\n" ,**(arr+1 )+3 ); printf ("arr[1][3]:%d\n" ,arr[1 ][3 ]); return 0 ; }
13.数组指针和二维数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int main () { int arr[2 ][3 ]={{0 ,1 ,2 },{3 ,4 ,5 ,}}; int (*p)[3 ]=arr; printf ("**(p+1):%d\n" ,**(p+1 )); printf ("**(arr+1):%d\n" ,**(arr+1 )); printf ("arr[1][0]:%d\n" ,arr[1 ][0 ]); printf ("**(p+1):%d\n" ,*(*(p+1 )+2 )); printf ("**(arr+1):%d\n" ,**(arr+1 )+2 ); printf ("arr[1][0]:%d\n" ,arr[1 ][2 ]); return 0 ; }
14. void指针–无类型指针
void指针我们把它称之为通用指针,就是可以指向任意类型的数据。也就是说,任何类型的指针都可以赋值给void指针。
15. null指针–如果一个指针不指向任何一个数据就是空指针
当你还不清楚要将指针初始化为什么地址时,请将它初始化NULL;在对指针进行解引用时,先检查该指针是否为NULL。这种策略可以为你今后编写大型程序节省大量的调试时间。
16. 指向指针的指针(二级指针)–**
1 2 3 4 5 6 int a=20 ;int *p=&a;int **pp=&p;pr(a) pr(*P) pr(**P)
17. 指向指针的指针和指针数组
避免重复分配内存
只需要进行一次修改
18.数组指针和二维数组
将array的首地址交给p,p+1就跳到了第二列
19.常量与指针
const关键字可将变量变成只读
指针可以修改为指向不同的常量
指针可以修改为指向不同的变量
可以通过解引用来读取指针指向的数据
不可以通过解引用修改指针指向的数据
1.常量指针
指向非常量的常量指针
——指针自身不可以被修改-
——指针指向的值可以被修改
指向常量的常量指针
一指针自身不可以被修改
一指针指向的值也不可以被修鸡
const接近哪个哪个就不可以改变
指针指代的是常量
2.指向常量的常量指针
20、malloc函数用法—
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include <stdio.h> #include <malloc.h> int fo (int *q) { *q=200 ; } int main () { int *p =(int *) malloc (sizeof (int )); *p=10 ; printf ("%d\n" ,*p); fo(p); printf ("%d\n" ,*p); return 0 ;}
八、函数
类型名 函数名(参数列表)
{
函数体
}
作用 :
避免了重复性操作
有利于程序的模块化
1、函数声明
2.函数小案例1----控制台输入求1+2+3+…(n-1)+n的和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <stdio.h> int sun (int a) { int sum=0 ; int i; for (i=0 ;i<=a;i++){ sum+=i; } return sum; } int main () { int a,sum=0 ; printf ("请输入一个数" ); scanf ("%d" ,&a); sum= sun(a); printf ("%d" , sum); return 0 ; }
3.函数小案例2------
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int max (int a,int b) { int temp; if (a>b){ temp=a; } else { temp =b; } return temp; } int main () { int a,b,temp=0 ; printf ("请输入两个数:" ); scanf ("%d %d" ,&a,&b); temp= max(a,b); printf ("最大值是:%d" ,temp); return 0 ; }
2、参数和返回值
形参 :形式参数–函数定义时写的参数
实参 :实际参数–函数调用时传的实际值
传值 :
传址 :
可变参数 ----include <stdarg.h>
3、指针函数
用指针变量作为函数的返回值,就是指针函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <stdio.h> char *fluth (char c) { switch (c) { case 'a' :return "鼠标" ; case 'b' :return "鼠标1" ; case 'c' :return "鼠标2" ; default :return "狗屁" ; } } int main () {char input; printf ("请输入一个字母:" ); scanf ("%c" ,&input); printf ("%s" , fluth(input)); }
4、函数指针–指向函数的指针
等价
5、函数指针作为参数
九、结构体
struct关键字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <stdio.h> struct Student { int age; float socre; char sex; }; int main () { struct Student st = {21 ,59.9 ,'m' }; printf ("%d %.2 f %c\n" ,st.age,st.socre,st.sex ); struct Student st2 ; st2.age=20 ; st2.socre=60 ; st2.sex='w' ; printf ("%d %.2f %c\n" ,st2.sex,st2.socre,st2.sex); struct Student *pst = &st; pst ->age=88 ; printf ("%d\n" ,pst->age); return 0 ; }
指针变量名->成员名﹐在计算机内部会被转化成(*指针变量名).成员名的方式来执行
pst -> age 含义: pst所指向的那个结构体变量中的age成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include <stdio.h> #include <string.h> struct Student { int age; double socre; char sex; char name[100 ]; }; int main () { struct Student st = {21 ,59.9 ,'m' ,"小李" }; printf ("%d %.2lf %c %s\n" ,st.age,st.socre,st.sex ,st.name); struct Student st2 ; st2.age=20 ; st2.socre=60 ; st2.sex='w' ; strcpy (st2.name,"小米" ); printf ("%d %.2lf %c %s\n" ,st2.sex,st2.socre,st2.sex,st2.name); struct Student *pst = &st; pst ->age=88 ; printf ("%d %s\n" ,pst->age,pst->name); return 0 ; }
小案例1–冒泡排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <stdio.h> void sort (int *a,int len) { int t=0 ; for (int i=0 ;i<len-1 ;i++){ for (int j=0 ;j<len-1 -i;j++){ if (a[j]>a[j+1 ]){ t=a[j]; a[j]=a[j+1 ]; a[j+1 ]=t; } } } } int main () { int a[6 ]={-1 ,0 ,7 ,4 ,9 ,3 }; sort(a,6 ); for (int i = 0 ; i < 6 ; ++i) { printf ("%d " ,a[i]); } printf ("\n" ); }
小案例二–用户输入成绩并排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 #include <stdio.h> #include <malloc.h> struct Student { int age; int score; char name[100 ]; }; int main () { int len; struct Student *parr ; printf ("请输入学生人数:\n" ); scanf ("%d" ,&len); parr=(struct Student *)malloc (sizeof (struct Student)*len); for (int i=0 ;i<len;i++){ printf ("请输入第%d个学生信息:" ,i+1 ); printf ("age=:" ); scanf ("%d" ,&parr[i].age); printf ("score=:" ); scanf ("%d" ,&parr[i].score); printf ("name=:" ); scanf ("%s" ,parr[i].name); } struct Student t ; for (int i=0 ;i<len-1 ;i++){ for (int j=0 ;j<len-1 -i;j++){ if (parr[j].score > parr[j+1 ].score){ t=parr[j]; parr[j]=parr[j+1 ]; parr[j+1 ]=t; } } } for (int i=0 ;i<len;i++){ printf ("请第%d个学生信息:" ,i+1 ); printf ("age=:%d\n" ,parr[i].age); printf ("score=:%d\n" ,parr[i].score); printf ("name=:%s\n" ,parr[i].name); printf ("\n" ); } return 0 ; }
十、枚举–enum
把一个事物的说有可能的取值都一一陈列出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <stdio.h> enum weekDay { Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday }; int f (enum weekDay i) { switch (i) { case 0 : printf ("Monday\n" ); break ; case 1 : printf ("Tuesday\n" ); break ; case 2 : printf ("Wednesday\n" ); break ; case 3 : printf ("Thursday\n" ); break ; case 4 : printf ("Friday\n" ); break ; case 5 : printf ("Saturday\n" ); break ; case 6 : printf ("Sunday\n" ); break ; } } int main () { f(Friday); return 0 ; }
代码更安全,
十一、进制
注意余数要倒序排序
八进制前面要加0,最大是7
十六进制前面要加0 X,最大0-9,a-f
在汇编中:在数字后加字母B表示二进制数,加字母О表示八进制数,加字母D表示十进制数,加字母H表示十六进制数。
进制转换----以15为例子
2进制 1111
15%2商7余1 1*2的3次方+1 *2的2次方+1 *1的1次方+1 *1的0次方=15
7%2商3余1
3%2商1余1
还余1
因此为1111
8进制 17
15%8商1余7
因此为17 1*8+7
%#X–打印16
十二、补码
原码
也叫符号-绝对值码
最高位0表示正1表示负,其余二进制位是该数字的绝对值的二进制位
例如 :5
的二进制是101–1表示负数 因此源码是1101
原码简单易懂加减运算复杂
存在加减乘除四种运算,
增加了CPU的复杂度
零的表示不唯一
反码
不用
移码
表示数值平移n位,n称为移码量
移码主要用于浮点数的阶码的存储
补码
十进制转二进制
正整数转二进制
除2取余,直到商位0,余数倒叙排序
负整数转二进制
先求与该负数相对应的正整数二进制的,然后将所有位取反,末尾加1,不够位数时,左边补1
例如:-3
3的二进制011,取反变成100,然后末尾加1变成 101—》11111101
零转二进制
全是0
二进制转十进制
如果首位是0,则表明是正整数,按普通方法
如果首位是1,则表明是复数
将所有位取反,末尾加1,所得的数字就是该复数的绝对值 前面全补1
十三、位运算符
&–按位与
&& 逻辑与 也叫并且(左边有右边是否相等-真1或假0)
&将两个二进制进行一个相与
1&1=1
1&0=0
0&1=0
0&0=0
eg: 5&7=5 21&7=5
|—按位或
||逻辑与
|按位或
1&1=1
1&0=1
0&1=1
0&0=0
~ 按位取反
就是把变量按二进制取反
^ 按位异或
相同为0,不同为1
1^0=1
0^1=1
1^1=0
0^0=0
<< 按位左移
i<<1 表示把i的所有二进制左移一位
左移n位相当于乘以2的n次方
答案下面的快,
>> 按位右移
i>>3 表示把i的所有二进制左移3位,左边一般都为0
右移n位相当于除以2的n次方
通过位运算符我们可以对数据精确到每一位