C语言知识点查缺补漏

1、控制不同进制的输出

int a = 100;
	printf("原样输出\n");
	printf("16进制为a=0x%x\n",a);
	printf("10进制为a=0d%d\n",a);
	printf("8进制为a=0o%o\n",a);

2、混合输入

#include<stdio.h>
int main()
{
	int a;
	char b;
	float c;
	printf("分别输入一个数字、字符、小数\n");
	scanf("%d%c%f",&a,&b,&c);
	printf("数字a = %d,字符 b = %c,小数c = %f\n",a,b,c);
	return 0;
}
当输入12w23.2时,编译器会自动识别整数字符和小数的。

3、puts与printf对比

#include<stdio.h>
int main()
{
	char a;
	puts("请输入一个人数字\n");
	a = getchar();//只能这么表示
	puts("你输入的数字是:");
	putchar(a);//输出a
	return 0;
}
printf()支持花样输出,puts只能输出字符串且自动换行。

4、C语言中三个数比较大小

#include<stdio.h>
int main()
{
	int data1;
	int data2;
	int data3;
	int change1;
	puts("请依次输入data1、data2、data3");
	scanf("%d%d%d",&data1,&data2,&data3);
	if(data1>data2)
	{
		change1 = data1;
		data1 = data2;
		data2 = change1;
	}
	if(data2>data3)
	{
		change1 = data2;
		data2 = data3;
		data3 = change1;
	}
	if(data1>data2)
	{
		change1 = data1;
		data1 = data2;
		data2 = change1;
	}
	printf("三个数从小到大依次排序为:%d %d %d\n",data1,data2,data3);
	return 0;
}
三个数比较大小最快的方法就是两个数依次比较。首先a与b比较,若a>b,则交换,否则不动,让最大的与第三个比较,此时最大的数以及到最右边了,接着比较左边两个数,大的一个放到右边。

5、break的一个应用

#include<stdio.h>
int main()
{
	int i;
	int totalmoney = 0;
	int money;
	float average;
	for(i=0;i<1000;i++)
	{
		printf("请输入捐款金额:\n");
		scanf("%d",&money);
		totalmoney = totalmoney + money;
		if(totalmoney>10000)
		{
			printf("捐款人数是:%d\n",i+1);
			average = (float)totalmoney/(i+1);
			printf("人均捐款是:%f\n",average);
			break;
		}
	}
	return 0;
}

6、求最大公约数、最小公倍数、水仙花数

//求最大公约数
#include <stdio.h>
int main()
{
    int a = 0;
    int b = 0;
    printf("请输入两个数求其最大公约数");
    scanf("%d%d",&a,&b);
    while(a!=b)
    {
        if(a>b)
        a = a - b;
        if(a<b)
        b = b - a;
    }
    printf("%d\n",a);
    return 0;
}

更相减损法
1、如果a > b a = a - b;
2、如果b > a b = b - a;
3、假如a = b,则 a或 b是最大公约数;
4、如果a != b;则继续从一开始执行;
5、也就是说循环的判断条件为a != b,直到a = b时,循环结束。
//求最小公倍数
#include <stdio.h>
int main()
{
    int a,b;
	printf("请输入两个数求其最小公倍数\n");
    scanf("%d %d",&a,&b);
    int i=1 ;
    while(1)
    {
        if(a*i%b==0)
        {
            break;
        }
            i++;
    }
    printf("%d\n",a*i);
}
使a*i%b==0成立的a*i即为最小公倍数,i=1,i++
由a*i,a*i一定可以被a整除,由%b,a*i一定可以被b整除
//求水仙花数,水仙花数是指一个三位数,它的每个位上的数字的三次幂之和等于它本身
#include<stdio.h>
int main()
{
	int num = 100;
	while(num<1000)
	{
		int a = num /1% 10;        //个位 
		int b = num / 10  %10;   //十位 
		int c = num / 100 %10;   //百位
		if(a*a*a+b*b*b+c*c*c == num)
		{
			printf("%d\t",num);
		}
		num++;
	}
	return 0;
} 
这是三位数的水仙花数,主要是取个位、取十位、取百位的一些思想!

7、斐不拿切数列

#include<stdio.h>
int main()
{
	int arr[30];
	arr[0] = 0;
	arr[1] = 1;
	int size_arr = sizeof(arr)/sizeof(arr[0]);
	int i;
	for(i=2;i<size_arr;i++)
	{
		arr[i] = arr[i-1]+arr[i-2];
	}
	for(i=0;i<size_arr;i++)
	{
		printf("%d\t",arr[i]);
		if(i%9==0)
		{
			puts("\n");
		}
	}
	return 0;
} 
数列第N项值等于前两项值相加,所以自定义出来数列前两项。

8、冒泡排序法

#include<stdio.h>
int main()
{
	int arr[] = {12,45,4,5,84,19,8,67,100,34,76};
	int i;
	int j;
	int temp;
	int size_arr = sizeof(arr)/sizeof(arr[0]);
	for(i=0;i<size_arr-1;i++)//6个数只比较5组
	{
		for(j=0;j<size_arr-1-i;j++)//每组比较的次数是依次递减
		{
			if(arr[j]>arr[j+1])
			{
				temp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = temp;
			}
		}
	}
	for(i=0;i<size_arr;i++)
	{
		printf("%d\t",arr[i]);
	}
	return 0;
} 
类比前面三个数比较大小!
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

9、简单选择排序法

#include<stdio.h>
int main()
{
	int arr[] = {12,45,4,5,84,19,8,67,100,34,76};
	int i;
	int j;
	int temp;
	int size_arr = sizeof(arr)/sizeof(arr[0]);
	for(i=0;i<size_arr-1;i++)//n个数只比较n-1次
	{
		for(j=i+1;j<size_arr;j++)//最大的放最左边,所以每次相比较的数都是第i+1个
		{
			if(arr[i]<arr[j])
			{
				temp = arr[i];
				arr[i] = arr[j];
				arr[j] = temp;
			}
		}
	}
	for(i=0;i<size_arr;i++)
	{
		printf("%d\t",arr[i]);
	}
	return 0;
} 
第一趟:从长度为len的序列中选出关键字最大(最小)的记录与第1个记录交换
第二趟:从第2个数据开始,从长度为 len-1 的序列中选出关键字最大(最小)的记录与第2个记录交换
第三趟:从第3个数据开始,从长度为 len-2 的序列中选出关键字最大(最小)的记录与第3个记录交换…
第 i 趟:从第 i 个数据开始,从长度为 len-i+1 的序列中选出关键字最大(最小)的记录与第 i 个记录交换

!!!对于这两种排序法,都采用两层循环,第一层循环都是要比较的趟数,第二层循环才是体现怎么比较。
对于冒泡排序,是相邻两个值比较,j与j+1;对于选择排序,始终是固定位置的值与其他比较!

10、二维数组

a[i][j]表示二维数组有i行,j列,可以看作有i个一维数组组成。
#include<stdio.h>
int main()
{
	int i;
	int j;
	int arr[2][3] = {1,2,3,4,5,6};
	for(i=0;i<2;i++)
	{
		for(j=0;j<3;j++)
		{
			printf("%p\t",&arr[i][j]);
		}
	}
	return 0;
} 
二维数组地址是连续的。二维数组可以不写行,不能不写列。因为数组会自动根据列数确定行数,不能根据行数来确定列数(后面会有多少零)a[][j]。

11、三目运算符

x>y?x:y
x是否大于y是的话结果是x否则为y

12、函数的递归

#include<stdio.h>
int getage_stu(int num)
{
	int age;
	if(num == 1)
	{
		age = 10;
	}
	else
	{
		age = getage_stu(num-1)+2;
		
	}
	return age;
}
int main()
{
	int num;
	puts("请输入你想知道第几个学生的年龄");
	scanf("%d",&num);
	printf("该学生年龄是%d\n",getage_stu(num));
	return 0;
} 
当前值和前一个值有关系就需要递归。
!!!必须要有停止项,比如这个题的第一项值为10。

12、形参中的数组没有大小,只是一个地址,就算写[2]也没有,地址的大小是8(64位)!
数组名就代表首地址!
13、全局变量与外部变量!

写在文件头的是全局变量,写在中间函数头的是外部变量!

14、指针的位数问题

#include<stdio.h>
int main()
{
	int a = 0x1234;
	int *p;//定义整数型指针
	char *c;//定义字符型指针
	p = &a;
	c = &a;
	printf("p = %p\n",p);
	printf("c = %p\n",c);
	printf("p = %x\n",*p);
	printf("c = %x\n",*c);
} 
这里的a是一个16进制数,也就是说a有4X4=16位,p指针有4个字节32位,c指针char有1个字节8位,
所以值输出以后,c的16进制只能输出低8位,即34.
!!!这个例子告诉我们不能把char型指针指向int型。
!!!注意所有的指针都是8字节(64位电脑)

在这里插入图片描述
15、强制指针指向固定的地址

	int *p = (int*)0x61FE33;
	printf("p=0x%p\n",p);

16、指针的访问效率远大于数组名的访问效率的!!

对于数组的访问,可以用
(1)指针名字当做数组
(2)数组当做指针用来+
int *p;
int arr[3] = {1,2,3};
p = arr;
p[i];
*(arr+i) ;
都是可以访问元素的
他们的区别就是:p是指针变量变量是可以++的;而arr是常量,指向的就固定是数组的首地址,常量不能用来++,常量是不能用来加上值之后又赋值给新的常量的!!!。

17、数组的逆序输出

#include<stdio.h>
int main()
{
	int a[7] = {1,23,45,32,65,78,89};
	int i;
	int temp;
	int len = sizeof(a)/sizeof(a[0]);
	for(i=0;i<(len/2);i++)
	{
		temp = a[i];
		a[i] = a[len-1-i];
		a[len-1-i] = temp;
	}
	for(i=0;i<len;i++)
	{
		printf("%d\t",a[i]);
	}
	return 0;
} 
这块不管对于数组长是奇数还是偶数,都可以利用这样的数组反转,两数下标和要为len-1;

18、二维数组地址认知

对于a[3][4]这样的二维数组可以看做是3个一维数组(每行代表一个数组),
a是父数组的名字,a[0]a[1]a[2]是三个子数组的名字,代表三个子数组的首地址&a[0][0]、&a[1][0]、&a[2][0];
对于a+1偏移的是整个一维数组的大小即16字节,对于a[0]+1偏移的是一维数组中一个元素大小。

#include<stdio.h>
int main()
{
	int arr[3][4] = {1,2,3,4,6,8,643,323,43,66,44,33};
	int i;
	int j;
	for(i=0;i<3;i++)
	{
		for(j=0;j<4;j++)
		{
			printf("数组元素地址:0x%p,数组元素值:%d\n",&arr[i][j],arr[i][j]);
			printf("数组元素地址:0x%p,数组元素值:%d\n",((arr[i])+j),*((arr[i])+j));
			printf("数组元素地址:0x%p,数组元素值:%d\n",*(arr+i)+j,*(*(arr+i)+j));
			printf("===================\n");
		}
		putchar('\n');
	}
	return 0;
} 
只有arr[i][j]里面的和j都明确指出了才表示数组元素值,否则都表示某个地址。
arr++跳的是一维数组大小。
printf("%p:   %p  ",p,++P);
这俩出来的地址是一样的,因为printf()是从右往左进行运算的,先进行++p的运算(先用),然后进行p取地址。
//数组指针
//若直接定义int *p2,p2=arr,偏移的是整个一维数组大小。
int (*p2)[4];
	p2 = arr;
	for(i=0;i<3;i++)
	{
		for(j=0;j<4;j++)
		{
			printf("%d  ",*(*(p2+i)+j));
		}
		putchar('\n');
	}

19、函数指针

函数名代表首地址
int (*p)(int a,int b)
int* p(int a,int b)//函数返回值为int* 型的地址
//函数调用
int (*p)();
int printwelcome();
p = printwelcome;
(*p)();//调用
//回调函数的应用
//有两个整数a,b,如果用户输入1则两数求最大值,如果输入2则两数求最小值,如果输入3则两数求和。
//函数的不同功能用函数指针来实现
#include<stdio.h>
#include <stdlib.h>
int getMax(int a,int b)
{
	int ret;
	ret = a>b?a:b;
	return ret;
}
int getMin(int a,int b)
{
	int ret;
	ret = a<b?a:b;
	return ret;
}
int getSum(int a,int b)
{
	int ret;
	ret = a+b;
	return ret;
}
int handlerret(int a,int b,int (*func)())
{
	int ret;
	ret = (*func)(a,b);
	return ret;
}
int main()
{
	int a = 10;
	int b = 20;
	int cmd;
	int ret;
	int (*func)();
	printf("请输入cmd的值:\n");
	scanf("%d",&cmd);
	switch(cmd)
	{
		case 1:
			func = getMax;
		break;
		case 2:
			func = getMin;
		break;
		case 3:
			func = getSum;
		break;
		default:
			printf("请输入一个合法数字:\n");
			exit(-1);
		break;
	}
	//先把func的功能给确定了,某个确定函数指向这个指针
	ret = handlerret(a,b,func);//结果输出
	printf("结果是:%d\n",ret);
	return 0;
} 
所谓的回调函数就是在一个函数里参数调用另外一个函数指针,前提是这个函数指针已经有了明确地址。

20、指针数组和数组指针

int (*p)[4]//()优先级高,是数组指针,指针指向一个数组
int *p[4];//[]优先级高,是指针数组,每一个位置都存放一个指针
//函数指针数组
#include<stdio.h>
#include <stdlib.h>
int getMax(int a,int b)
{
	int ret;
	ret = a>b?a:b;
	return ret;
}
int getMin(int a,int b)
{
	int ret;
	ret = a<b?a:b;
	return ret;
}
int getSum(int a,int b)
{
	int ret;
	ret = a+b;
	return ret;
}
int main()
{
	int a = 10;
	int b = 20;
	int (*pfunc[3])(int a,int b) = {getMin,getMax,getSum};//函数指针数组,每个元素位置存放一个函数的地址,[]优先级高
	for(int i=0;i<3;i++)
	{
		printf("%d \n",(*pfunc[i])(a,b));
	}
	return 0;
} 
#include <stdio.h>
int main()
{
	int arr[3][4] = {{11,22,33,32},{34,23,57,87},{56,76,87,67}};
	int num;
	int *parr;
	printf("定义你所要拿出的学生号0/1/2:\n");
	scanf("%d",&num);
	parr = (int*)(arr+num);//arr偏移的是16字节,parr偏移的是4个字节
	for(int i=0;i<4;i++)
	{
		printf("%d\n",*(parr+i));
	}
	return 0;
}
若要定义的指针需要存放二维数组,则要定义指针数组*p[4],若要存放的是一维数组,定义*p就可以。

21、二级指针

#include <stdio.h>
int main()
{
	int data = 10;
	int *p;
	p = &data;//p保存data的地址
	int *pp;
	pp = &p;//pp保存p的地址
	printf("data地址是:%p\n",&data);
	printf("p保存的data地址是:%p\n",p);//取存放的地址的时候不加&
	printf("pp保存p的地址是:%p\n",pp);
	printf("==========\n");
	printf("p自己的地址是:%p\n",&p);//取自己的地址的时候加&
	printf("*pp是:%p",*pp);//取pp的内容,即对pp指向的(地址p)取个内容,相当于取了data的地址
	return 0;
}
上面的代码中两个指针只能取出来p保存的地址,访问不了data的值,下面我们来看二级指针
#include <stdio.h>
int main()
{
	int data = 10;
	int *p;
	p = &data;//p保存data的地址
	int *pp;
	pp = &p;//pp保存p的地址
	printf("data地址是:%p\n",&data);
	printf("p保存的data地址是:%p\n",p);//取存放的地址的时候不加&
	printf("pp保存p的地址是:%p\n",pp);
	printf("==========\n");
	printf("p自己的地址是:%p\n",&p);//取自己的地址的时候加&
	printf("*pp是:%p\n",*pp);//对pp指向的(地址)p取个内容,相当于取了data的地址
	
	printf("===========\n");
	int **p2;
	p2 = &p;
	printf("**p2的值是:%d\n",**p2);
	return 0;
}

在这里插入图片描述

指针取内容就是对自己保存的地址取个值
#include <stdio.h>
void getscore(int num,int (*pscore)[4],int **ppos)
{
	*ppos = (int *)(pscore+num);//二级指针存放一级指针的地址
}
int main()
{
	int stu[3][4] = {{11,22,3,34},{23,45,65,76},{78,86,66,79}};
	int num;
	printf("请输入你想知道的学生号0/1/2:\n");
	scanf("%d",&num);
	int *ppos;
	getscore(num,stu,&ppos);//要改地址就把地址传过去,一级指针的地址用二级指针承接
	for(int i=0;i<4;i++)
	{
		printf("%d  ",*(ppos+i));
	}
	
	
	return 0;
}

22、字符串的输入输出

#include <stdio.h>
int main()
{
	char *pstr = "hello";//字符串常量不允许被修改
	char str[] = "hello";//字符串变量可以被修改
	puts(pstr);
	printf("%s\n",str);
	str[0] = i;
	return 0;
}

23、自己实现字符串的拷贝

#include <stdio.h>
void myncpy(char *des,char *src,int count)
{

	while(count != 0)
	{
		*(des++) = *(src++);
		count--;
	}
	
}
int main()
{
	char *pstr = "hellowelcome";
	char p[128] = {'\0'};
	myncpy(p,pstr,8);
	puts(p);
	return 0;
}

//字符串理解为字符数组,数组名代表地址

24、自己实现字符串的拼接

#include <stdio.h>
char *mystrcat(char *des,char *src)//先把在后面加的字符串地址移到最后,再一个一个遍历值
{
	char *bak;
	bak = des;
	while(*des != '\0')
	{
		des++;
	}
	while(*src != '\0')
	{
		*(des++) = *(src++);
	}
	return bak;
	
}
int main()
{
	char *pstr = "hellowelcome";
	char p[128] = "nji";
	mystrcat(p,pstr);
	puts(p);
	return 0;
}


25、结构体指针数组学生成绩管理系统

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Stu
{
	char name[128];
	int tickets;
};
int i;
int j;
int feipiao = 0;
struct Stu *strinit(struct Stu *xm,int *pnum)
{
	if(xm == NULL)
	{
		printf("输入选民个数\n");
		scanf("%d",pnum);
		xm = (struct Stu*)malloc(sizeof(struct Stu)*(*pnum));//选民类似于结构体数组了
		for(i=0;i<(*pnum);i++)
		{
			xm->tickets = 0;
			printf("请输入第%d个选民名字\n",i+1);
			scanf("%s",xm->name);
			xm++;
		}
	}
	return xm-(*pnum);
}
void printxm(struct Stu *xm,int num)
{
	for(i=0;i<num;i++)
	{
		printf("第%d个选民名字:%s \n",i+1,xm->name);
		xm++;
	}
}
void DoVot(struct Stu *xm,int num)
{
	int mark = 0;
	char vot_name[20];
	for(i=0;i<5;i++)
	{
		struct Stu *p = xm;
		printf("请输入你要投给谁:");
		memset(vot_name,'\0',sizeof(vot_name));
		scanf("%s",vot_name);
		for(j=0;j<num;j++)
		{
			if(strcmp(vot_name,p->name) == 0) //字符串比较,一样的话返回值为0
			{
				p->tickets++;
				p++;
				break;
			}
			else if((j == num-1) && (strcmp(vot_name,p->name) != 0))
			{
				printf("没有该选民\n");
				feipiao++;
			}
			p++;
		}
	
	}
	printf("废票数为:%d\n",feipiao);
}
void getmaxtickets(struct Stu *xm,int pnum)
{
	struct Stu *Max = xm;
	//Max = xm;
	for(i=1;i<pnum;i++)
	{
		if((xm->tickets)>(Max->tickets))
		{
			Max = xm;
		}
		xm++;
	}
	printf("票数最多的人是:%s ,得票为%d\n",Max->name,Max->tickets);
}

int main()
{
	struct Stu *xm = NULL;//定义选民
	int total_xm;
	xm = strinit(xm,&total_xm);//选民初始化成功
	printxm(xm,total_xm);//打印选民信息
	DoVot(xm,total_xm);//民众投票
	getmaxtickets(xm,total_xm);
	return 0;
}

26、链表

#include <stdio.h>

struct Stu
{
	int num;
	struct Stu *next;
};
void printlink(struct Stu *head)
{
	struct Stu *point = head;//不要改变链表头
	while(point != NULL)
	{
		printf("%d  ",point->num);
		point = point->next;
	}
	putchar('\n');
}
int main()
{
	struct Stu s1 = {1,NULL};
	struct Stu s2 = {2,NULL};
	struct Stu s3 = {3,NULL};
	s1.next = &s2;	
	s2.next = &s3;	
	printlink(&s1);
}

27、GDB调试

例如  gcc YB.C -g -o YB
gdb YB 

28、链表查找

int searchLink(struct Stu *head,int num)
{
	struct Stu *point = head;
	while(point != NULL)
	{
		if(point->num == num)
		{
			return 2;
		}
		point = point->next;
	}
	return 0;
}

尾插法

void insertfrombehind(struct Stu *head,int num,struct Stu *new)
{
	struct Stu *point = head;
	while(point != NULL)
	{
		if(point->num == num)
		{
			new->next = point->next;
			point->next = new;
		}
		point = point->next;
	}
}

头插法

struct Stu *insetfromfo(struct Stu *head,int num,struct Stu *new)
{
	struct Stu *point = head;
	if(point->num == num)
	{
		new->next = point;
		return new;
	}
	while(point->next != NULL)
	{
		printf("77\n");
		if((point->next)->num == num)
		{
			new->next = point->next;
			point->next = new;
			return head;
		}
		point = point->next;
	}
	printf("no this node\n");
	return head;
}

!!!头插法动态创建节点

struct Stu *creatlink(struct Stu *head)
{
	struct Stu *new;
	while(1)
	{
		new = (struct Stu *)malloc(sizeof(struct Stu));
		printf("请输入你要创建的数据:\n");
		scanf("%d",&(new->num));
		if(new->num == 0)//碰到输入为0就结束链表的动态插入
		{
			printf("0 quit \n");
			return head;
		}
		if(head == NULL)
		{
			head = new;
		}
		else
		{
			new->next = head;
			head = new;//习惯上这么写让new
		}
	}
	return head;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

￴ㅤ￴￴ㅤ9527超级帅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值