c语言学习笔记

数据类型数据类型
int %d scanf(“%d”,&i)
long %ld scanf(“%ld”,&j)
long long %lld scanf(“%lld”,&k)
float %f scanf(“%f”,&f)
double %lf scanf(“%lf”,&d)
char %c scanf(“%c”,&c)
字符串(char str[20],见第 4 章) %s scanf(“%s”,str)

float 能够表示的有效数字为 7 位,double会访问8字节的空间进行浮点计算
\t 横向跳格
\r 回车
\ 反斜杠
\b 退格 (BS) ,将当前位置移到前一列 008
\0 空字符,用于标示字符串的结尾,不是空格,打印不出,和佛家的空类 似
\ddd ddd 表示 1 到 3 位八进制数字,非常鸡肋,没什么用
\xhh hh 表示 1 到 2 位十六进制数字,非常鸡肋,没什么用
%% 一个’%'符号
%p 一个指针
%x 无符号十六进制数, 用小写字母
%X 无符号十六进制数, 用大写字母
%e 科学计数法, 使用小写"e"
%E 科学计数法, 使用大写"E"
%i 带符号整数=%d
%f 浮点数
%o 八进制
%s 一串字符
%o 八进制
%s 一串字符
通过%c 来打印输出时,得到的是字符,通过%d 打印输出时,得到 ASCII 值。
所有的 printf()的输出都是右对齐的,除非你在%符号后放置了负号.,负号表示左对齐
----->>>>小写字母转大写字母:–通过附录 1 的 ASCII 表可以发现小写字母与大写字母的差值 为 32,因此我们对 c 减去 32,就可以得到大写字母 A。
C规定以字符’\0’作为字符串结束标志。 但在输 出时不输出’\0’,因为‘\0’是显示不出的。
c的缓冲类型:
1) 全缓冲:在这种情况下,当填满标准 I/O 缓存后才进行实际 I/O 操作。全缓冲的典型 代表是对磁盘文件的读写。
2) 行缓冲:在这种情况下,当在输入和输出中遇到换行符时,执行真正的 I/O 操作。 这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的 I/O 操作。典型 代表是标准输入(stdin)和标准输出(stdout)。
3) 不带缓冲:也就是不进行缓冲,标准出错情况 stderr 是典型代表,这使得出错信息 可以直接尽快地显示出来。

#include<stdio.h>  //printf函数需要使用该头文件
#include<stdlib.h>  //system函数需要使用该头文件,system("pause")使我们通过C语言调用执行windows的批处理命令pause
#include PI 3//定义PI为3

1, day2-scanf-getchar-printf
ret=scanf("%d%c%f",&i,&c,&f) //要用百分号括起来,不然都是ret都是0和1
完整:(EOF)为-1,rewind刷新缓存区

#include<stdio.h>
void scanf_many_type(){
	int i,ret;
	char c;
	float f;
	double d;//双精度浮点型需要用%lf
while(rewind(stdin),(ret=scanf("%d %c%f%lf",&i,&c,&f,&d))!=EOF){判断循环条件,%c中间需要空格,循环打印
	printf("i=%d,c=%c,f=%5.2f,d=%f\n",i,c,f,d);//f输入满足5位
	}//ctrl+z停止
}
void use_getchar();//getchar函数声明
{
	char c;
	c=getchar();
	putchar(c);//只打印一个字符用putchar()
}
void printf_format(){
	int i=10;
	float f=98.3;
	printf("student_info_num=%03d,score=%5.2f\n",i,f);//03d,不足3位补0
	printf("student_info_num=%-3d,score=%5.2f\n",i,f);//加负号(-)向左对齐
	printf("%10s\n","hello");
}
int main(){
	//scanf循环输入
	//scanf_while();
	//多种数据类型混合输入
	//scanf_many_type();
	//联系getchar(),每次只读一个字符
	//use_getchar();
	//练习printf打印格式
	printf_format();
	system("pause");

}

2,day2-算术运算符-关系运算符-位运算符
0为假,非0为真
①取余运算

#include<stdio.h>
void calc_operator(){
	int i=12321,result;
	while(i){
		printf("%d\n",i%10+48);//不记得+48可以+'0'
		//因为字符+'0'可以得到对应字符的54321
		i/=10;
	}
	
}
int main(){
	//取余运算
	calc_operator();
	system("pause");
}

②算术优先级
-------------------等等
----------------------从右到左
–自减运算符
*取值运算符 *指针变量
&取地址运算符 &变量名
!逻辑非运算符 !表达式
(类型)强制类型转换 (数据类型)表达式
sizeof 长度运算符 sizeof(表达式)
----------------------从左到右

#include<stdio.h>
void use_logic(){
	int j=1,i=5;
	j==0&&printf("system is error\n");//若&&前面是假,&&后面就不用运算了
}
int main(){
	//短路运算
	use_logic();
	system("pause");
}

< 小于号 从左到右
if (3<year&&year>10)

③位运算符
<< 左移 变量<<表达式 左到右

右移 变量>>表达式 左到右
~ 按位取反:数位上的数是1变成0,0变成1
| 按位或:用两个数的每一位进行或,参加运算的两个对象只要有一个为1,其值为1
^ 按位异或:相同的数异或时,结果为0,任何数异或的结果时其本身
& 按位与 :用两个数的每一位进行与,两位同时为“1”,结果才为“1”,否则为0
3&5 即
     0000 0011
   &
     0000 0101
   =
    0000 0001

//右移,正数高位补0,负数,高位补1
#include<stdio.h>
void bit_calc(){
	//short i=0x70ff;//防止移动到符号位
	//i=i<<1;
	int i=5;//malloc(1<<10)
	printf("i<<1=%d\n",i<<1);//5左移1位后变成10
	printf("i>>1=%d",i>>1);//右移为减一除2
	printf("%d\n",i);
}
void xor(){
	//printf("%d\n",5&7)
	int a[3]={7,5,7,11,8,11};
	int i,ret=0;
	for(i=0;i<7;i++){
		ret=ret^a[i];
	}
	printf("ret=%d\n",ret);
}
int main(){
	//左移就是乘二
	//bit_calc();
	//异或
	xor();
	system("pause");
}

3,条件运算符-自增自减运算
4,关系表达式和逻辑表达式
①if->else if->else
if (){
}
else if(){
}
else if(){
}
else(){
}
②switch(表达式)
{
case 常量表达式:语句1;
case 常量表达式:语句2;
case 常量表达式:语句3;
case 常量表达式:语句4;
default:
printf("…");
}
③goto语句
向上跳转//100内的数字递增相加

#include<stdlib.h>
#include<stdio.h>
int main(){
	int i=1;
	int total=0;
lable:
	total=total+i;
	i++;
	if(i<100){
		goto lable;
	}
	printf("total=%d\n",total);
	system("pause");
	return 0;
}

goto语句向下跳转

#include<stdlib.h>
#include<stdio.h>
//goto向下跳转,实现部分代码不执行
int main(){
	int disk;
	scanf("%d",&disk);
	if(disk==0){
		goto lable_disk_error;
	}
	//写磁盘的操作
lable_disk_error:
	printf("system is error\n");
	system("pause");
	return 0;
}

5,str系列字符串操作函数

#include<string.h>
size_t strlen(char *str);//strlen函数用于统计字符串长度
char *strcpy(char *to,const char *from);//strcpy用于将某个字符串赋值到字符数组中
int strcmp(const char *str1;const char *str2);//strcmp函数用于比骄傲两个字符串的大小,strcmp(c,d),若c与d相等,返回值为0,c大于d,返回值为1;c小于d,返回值为-1
char *strcat(char *str1,const char *str2);//strcat用于将两个字符串连接到一起
//对于传参类型char *,直接放入字符数组的数组名即可

6,指针(*p为取该地址p所对应的值,p=&i;//p存储整型变量i的地址)
int a[N];
p=a;//保证等号两边的数值类型一致,p指向a数组的首地址即a[0]

int i=10;
int j=5;
p=&i;//p存储整型变量i的地址
printf("*p=%d\n",*p);//利用p间接获取整型变量i的值,*p为取该地址p所对应的值
一,注意

(1)指针变量前面的"*",表示该变量为指针型变量
如 float *pointer_1;
pointer_1是指针变量名
(2)必须指定指针变量的类型,只有整型变量才能放到指向整型变量的指针变量中,如下面是错误的

float a;
int * pointer_1;
pointer_1=&a;//会出错

(3)
①pointer_1=&a;
②&和的优先级相同,但要按自右向左的方向结合。因此&pointer_1与&a相同,都表示变量a的地址,也就是pointer_1
&a的含义是什么?
&a:得到a的地址
(&a):()为取地址的值,
(&a)等价于变量a
(4)
int *a;//a被声明为int 类型的指针
int *a,*b,*c;//这样才能声明三个指针
二,指针的使用场景(传递和偏移)
2.1 指针的传递

#include<stdio.h>
#include<stdlib.h>
void changr(int *j){
	*j=5;//间接访问得变量i
}
//指针的传递
int main(){
	int i=10;
	printf("before change i=%d\n",i);
	change(&i);//传递变量i的地址
	printf("after change i=%d\n");
	system("pause");
	return 0;
}

&i为传递i的地址,(int *j)表示j为指针变量,内部存的是变量i的地址,*j就访问到了i变量的值,*j=5就实现了对变量i的改变
2.2指针的偏移
减就是向前偏移,加就是向后偏移

#include<stdio.h>
#include<stdlib.h>
#define N 5
int main(){
	int a[N]={1,2,3,4,5};
	int *p;
	int i;
	p=a;//保证等号两边的数值类型一致,p指向a数组的首地址即a[0]
	for(i=0;i<N;i++){//正序输出,加为向后偏移
		printf("%3d",*(p+i));
	}
	printf(" \n");
	p=&a[4];//让指针p指向最后一个元素
	for(i=0;i<N;i++){//逆序输出
		printf("%3d",*(p-i));//指针指向最后一个元素,减表示先前偏移
	}
	printf(" \n");
	system("pause");
	return 0;
}

①顺序:由于p=a,p指向a数组的首地址:0x0028F768,(p+1)指向0x0028F76C,增长一个int类型的长度,故 *(p+1)指向a[1]。
②逆序:最数组最后一个元素a[4]进行取地址操作后,得到地址0X0028F778,,通过减法可以让数组元素逆序输出,可以看到p-1的值为0x0028F774
在这里插入图片描述
2.3指针与自增/自减运算符

#include<stdio.h>
#include<stdlib.h>
int mian(){
	int a[3]={2,7,8};
	int *p;
	int j;
	p=a;//p指向数组a的首地址,且表示p与a同类型
	j=*p++;//先把*p赋值给j,p再自加1
	printf("a[0]=%d,j=%d,*p=%d\n",a[0],j,*p);
	system("pause");
	return 0;
}

输出j=2,*p=7。*p表示取值,取a[0]赋值给j,然后p自增1,指向a[1]
2.4 指针与一维数组
利用指针改写数组的元素

#include<stdio.h>
#include<stdlib.h>
void change(char *d){
	*d='H';//由于指针d指向字符数组的首地址,将hello改写成Hello
	d[1]='E';//将Hello改写成HEllo
	*(d+2)='L';//将HEllo改写成HELlo
}
int main(){
	char c[10]="hello";//初始化字符串组用双引号""
	change(c);//把C作为实参传给change,d=c,指针d指向字符数组的首地址
	printf("%s\n",c);
}

2.5 指针与动态内存申请
2.5.1动态内存申请(申请堆)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
	int i;
	char *p;
	scanf("%d",&i);//输入要申请的空间大小
	p=(char*)malloc(i);//利用malloc动态申请堆空间,利用char*把申请的堆空间赋值为char类型
	strcpy(p,"malloc success");//把字符串放到p中,从p申请的堆栈首地址排列下来
	puts(p);//逐字符输出p中的字符串
	free(p);//free时必须使用malloc申请返回的指针,不能进行任何偏移
	printf("free suceess\n");
	system("pasuse");
}

p=(char*)malloc(i);把p指向申请堆空间的首地址,
strcpy(p,“malloc success”);//把字符串放到p中,从p申请的堆栈首地址排列下来
puts§;//逐字符输出p中的字符串
(C 库函数 char *strcpy(char *dest, const char *src) 把 src 所指向的字符串复制到 dest。)
2.5.2野指针

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
	int *p1,*p2,*p3;//定义指针
	p1=(int*)malloc(4);//申请四个字节空间,存放整型指针p1
	*p1=1;
	p2=(int*)malloc(4);
	*p2=2;
	free(p);//释放p1申请的空间,但未将p1赋值为null
	p3=(int*)malloc(4);
	*p3=3;
	printf("*p3=%d\n",*p3);//这次打印值为3
	*p1=100;//把100赋值给p1对应地址的值
	printf("*p3=%d\n",*p3);//输出为100
}

由于p1已经释放,但未释放,malloc把释放的空间给了p3,此时p1和p3指向同一块内存空间,给p1赋值就是给p3赋值,故输出是100
2.5.3栈空间和堆空间的差异

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//函数栈空间释放后,函数内所有局部变量消失
char *print_stack(){
	char c[]="I am print_stack";
	puts(c);//现在都用fgets()申请栈空间
	return 0;
}
//堆空间不会因函数执行结束而释放
char *print_malloc(){
	char *p;
	p=(char*)malloc(20);//申请堆空间
	strcpy(p,"I am print_malooc");
	puts(p);
	return p;
}
int main(){
	char *p;
	p=print_stack();//数据放在栈空间
	puts(p);//打印有异常,出现乱码
	p=print_malloc();//数据放在堆空间
	Puts(p);
	system("pause");
}

堆空间只有在执行free操作后才会释放,否则在进程执行中会一致有效
2.6 字符指针与字符数组的初始化
char *p=“hello” , 和char c[10]=“hello” 又什么区别呢?

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
	char *p="hello";//把字符串型常量"hello"的首地址给p,"hello"存在字符串常量区
	char c[10]="hello";//等价于strcpy(c,"hello");,字符数组c在栈空间有10字节大小的空间
	c[0]="H";//由于存在栈空间,所以可以修改
	printf("c[0]=%c\n",c[0]);
	printf("p[0]=%c\n",p[0]);
	//p[0]="H";非法,p[0]为字符常量区的空间,所以不可修改
	p="world";//将字符串world的地址赋给p
	//c="world";//非法
	system("pause");
	return 0;
}

①字符数组c在栈空间有10字节大小的空间,所以可以通过c[0]="H"修改
②p[0]为字符常量区的空间,所以不可修改,但是p作为一个指针变量,因此可以用p=“world”;,将world的首地址赋值给p
③c=“world”;中c等价于符号常量,因此这个操作非法
2.7深入理解const
4.二级指针
4.1 二级指针的传递

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void change(int **p, int *pj) {//*pj为定义pj为int类型的一级指针,**p为定义一个二级指针p
	int i = 5;
	*p = pj;//p为二级指针,*p表示p的地址,即pi的地址。*p=pj将pi的地址改为pj的首地址
}
int main() {
	int i = 10;
	int j = 5;
	int *pi;//定义指针pi
	int *pj;//定义指针pj
	pi = &i;//i的地址给pj,也就是pi指向i
	pj = &j;//j的地址给pj,也就是pj指向j
	printf("before change i=%d,*pi=%d,*pi=%d\n,*pj=%d\n", i, *pi, *pj);
	change(&pi, pj);//&pi为把pi的地址传给change,&pi的类型为二级指针,存的是pi指针的地址
	printf("after change i=%d,*pi=%d,*pi=%d\n,*pj=%d\n", i, *pi, *pj);
	system("pause");
	return 0;
}

4.2 二级指针的偏移

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include<string.h>
void print(char *p[]) {//这里可以写成char **p
	int i;
	for (i = 0; i < 5;++i) {
		puts(p[i]);
	}
}
//二级指针的偏移,服务的是指针数组
int main() {
	char *p[5];//定义一个指针数组
	char b[5][10] = {"lele","lili","lilei","hanmeimei","zhousi"};//定义字符数组
	int i, j, tmp;
	char *t;
	char **p2;//定义一个二级指针
	int a[5] = {3,7,9,2,4};//定义一个一维数组
	for (i = 0; i < 5;++i) {//让指针数组中的每个指针都指向一个字符串
		p[i] = b[i];
	}
	p2 = p;//让p2指向p
	for (i = 4; i > 0;--i) {//冒泡排序法
		for (j = 0; j < i;j++) {
			if(strcmp(p2[j], p2[j + 1])==1){//判断p2[j]是否大于p2[j+1]
				t=p2[j];
				p2[j]=p2[j+1];
				p2[j+1]=t;
			}
		}
	}
	printf(p2);//先打印排序结果
	puts("-----------------------------");
	for(i=0;i<5;++i) {
		puts(b[i]);
	}
	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值