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;
}