#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
//练习54:ferror函数使用
int main()
{
int c;//注意:int ,非char,要求处理EOF
FILE* fp=fopen("test,txt","r");
if(!fp)
{
perror("File opening failed");
return -1;
}
//fgetc当读取失败的时候或者遇到文件结束的时候,都会返回EOF
while((c = fgetc(fp)!= EOF))//标准C I/O读取文件循环
{
putchar(c);
}
//判断是什么原因结束的
if(ferror(fp))
puts("I/O error when reading");
else if(feof(fp))
puts("End of file reached successfully");
//关闭文件
fclose(fp);
fp == NULL;
return 0;
}
//练习53:perror函数使用,报错信息提示自定义
int main()
{
//strerror-把错误码对应的错误信息的字符串地址返回
//printf("%s\n",streeror);
//perror
FILE* pf = fopen("test2.txt","r");
if(pf == NULL)
{
perror("hehe");//不需要传送错误码信息,hehe:错误信息
return 0;
}
//读文件
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
练习52:文件的随机读取
//fseek和ftell和fwind
int main()
{
char ch;
//打开文件
FILE* pf = fopen("test.txt","r");
if(pf == NULL)
{
return 0;
}
//定义文件指针
fseek(pf,2,SEEK_CUR);
//读取文件
ch= fgetc(pf);
printf("%c\n",ch);//%c打印字符
//关闭文件
fclose(pf);
pf=NULL;
return 0;
}
int main()
{
int pos = 0;
//打开文件
FILE* pf=fopen("test.txt","r");
if(pf == NULL)
{
return 0;
}
//定位文件指针
fseek(pf,-2,SEEK_END);
pos = ftell(pf);
printf("%d\n",pos);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
练习51:二进制读写函数fread和fwrite
struct S
{
char name[20];
int age;
double score;
};
int main()
{
struct S s={"张丹",20,21.5};
FILE* pf=fopen("test.txt","wb");//以二进制形式写入
if(pf == NULL)
{
return 0;
}
//二进制形式写文件
fwrite(&s,sizeof(struct S),1,pf);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
int main()
{
struct S temp={0};
FILE* pf=fopen("test.txt","rb");//以二进制形式读取
if(pf == NULL)
{
return 0;
}
//二进制形式读文件
fread(&temp,sizeof(struct S),1,pf);
printf("%s %d %lf\n",temp.name,temp.age,temp.score);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
//练习50:sscanf和sprintf
struct S
{
int n;
float score;
char arr[10];
};
int main()
{
struct S s={100,3.14f,"abcdef"};
struct S tmp={0};
char buf[1024]={0};
sprintf(buf,"%d %f %s",s.n,s.score,s.arr);
printf("%s\n",buf);
sscanf(buf,"%d %f %s",&(tmp.n),&(tmp.score),&(tmp.arr));
printf("%d %f %s\n",tmp.n,tmp.score,tmp.arr);
return 0;
}
//练习49:文件操作2
//格式化输入输出函数fprintf();fscanf();
struct S
{
int n;
float score;
char arr[10];
};
int main()
{
struct S s={100,3.14f,"bit"};
//打开文件
FILE* pf=fopen("test.txt","w");
//判断
if(pf == NULL)
{
return 0;
}
//格式化形式写文件
fprintf(pf,"%d %f %s",s.n,s.score,s.arr);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
//练习48:文件操作1
int main()
{
int a=10000;
FILE* pf=fopen("text.text","wb");
fwrite(&a,4,1,pf);//二进制的形式写到文件中
fclose(pf);
pf=NULL;
return 0;
}
int main()
{
//打开二进制文件test.text.fopen打开
//相对路径
fopen("test.txt","r");
//绝对路径,\要再加一个\进行转义
fopen("D:\\C\\Review\\test11_24\\Project1\\test.txt","r");
//..表示上一级路径
//.表示当前路径
fopen("..\\..\\test.txt","r");
return 0;
}
int main()
{
FILE* pf=fopen("text.txt","r");//文件指针接收返回值
//判断是否打开成功,打开失败会返回null空指针
if(pf == NULL)
{
printf("%s\n",strerror(errno));
return 0;
}
else
{
printf("打开文件成功!\n");
}
fclose(pf);
pf = NULL;
return 0;
}
//顺序读文件
int main()
{
//打开或建立文件
FILE* pfwrite = fopen("test.txt","w");
//判断文件是否打开成功
if(pfwrite == NULL)
{
printf("%s\n",strerror(errno));
}
//写文件
fputc('b',pfwrite);
fputc('i',pfwrite);
fputc('t',pfwrite);
//关闭文件
fclose(pfwrite);
pfwrite = NULL;
return 0;
}
//顺序写文件
int main()
{
FILE* pfread = fopen("test.txt","r");
if(pfread == NULL)
{
printf("%s\n",strerror(errno));
return 0;
}
//读文件
printf("%c",fgetc(pfread));
printf("%c",fgetc(pfread));
printf("%c",fgetc(pfread));
printf("\n");
//关闭文件
fclose(pfread);
pfread = NULL;
return 0;
}
//键盘-标准输入设备-stdout
//屏幕-标准输出设备-stdin
//是一个程序默认打开的两个流设备
//程序默认打开3个。分别是
//stdin FILE*//stdout FILE*//stderr FILE*
int main()
{
int ch = fgetc(stdin);
fputc(ch,stdout);
return 0;
}
读取一行字符串
int main()
{
//读取字符串的送往地址
char buf[1024]={0};
//打开文件
FILE* pf=fopen("test.txt","r");
//判断
if(pf == NULL)
{
printf("%s\n",strerror(errno));
return 0;
}
//读取
fgets(buf,1024,pf);
printf("%s\n",buf);
fclose(pf);
pf=NULL;
return 0;
}
int main()
{
//打开文件
FILE* pf=fopen("test.txt","w");
//判断
if(pf == NULL)
{
printf("%s\n",strerror(errno));
return 0;
}
//写入
fputs("hello\n",pf);
fputs("hello\n",pf);
fclose(pf);
pf=NULL;
return 0;
}
int main()
{
//从键盘读取一行文本信息
char buf[1024]={0};
fgets(buf,1024,stdin);//标准输入读取
fputs(buf,stdout);//输出到标准输出流
//---------------
// gets(buf);
// puts(buf);
return 0;
}
//练习47:柔性数组的使用2
struct S
{
int n;
int* arr;
};
int main()
{
int i=0;
int * ptr;
//动态开辟空间,分别两次
struct S* ps=(struct S*)malloc(sizeof(struct S));
ps->arr = (int *)malloc(5*sizeof(int));
for(i=0;i<5;i++)
{
ps->arr[i]=i;
}
for(i=0;i<5;i++)
{
printf("%d ",ps->arr[i]);
}
printf("\n");
//调整大小
ptr=(int *)realloc(ps->arr,10*sizeof(int));
if(ptr !=NULL)
{
ps->arr =ptr;
}
for(i=5;i<10;i++)
{
ps->arr[i]=i;
}
for(i=0;i<10;i++)
{
printf("%d ",ps->arr[i]);
}
//释放内存
free(ps->arr);
ps->arr =NULL;
free(ps);
ps=NULL;
return 0;
}
//练习46:柔性数组的使用1
//优点:流程不易出错,方便内存释放,连续开辟一块动态内存,访问效率更高
struct S
{
int n;
int arr[];//大小可以调整,或者写为int arr[0];
};
int main()
{
struct S*ps=(struct S*)malloc(sizeof(struct S)+5*sizeof(int));
ps->n=100;
int i=0;
for(i=0;i<5;i++)
{
ps->arr[i]=i;
}
struct S* ptr=realloc(ps,44);
if(ptr != NULL)
{
ps=ptr;
}
for(i=5;i<10;i++)
{
ps->arr[i]=i;
}
for(i=0;i<10;i++)
{
printf("%d",ps->arr[i]);
}
return 0;
}
//练习45:动态内存使用错误---非法访问内存
//返回栈空间地址的问题,局部变量
char *GetMemory(void)
{
char p[]="hello world";//局部数组,在函数外之外生命周期结束了
return p;
}
void Test(void)
{
char* str=NULL;
str=GetMemory();
printf(str);
}
int main()
{
Test();
return 0;
}
//练习44:动态内存空间没有释放,内存泄露(错误示例)
void GetMemory(char* p)
{
p=(char*)malloc(100);
}
void Test(void)
{
char *str=NULL;
GetMemory(str);
strcpy(str,"hello world");
printf(str);//没有错误,同printf("abcdef");
}
int main()
{
Test();
return 0;
}
//1、运行代码程序会出现崩溃现象
//2、程序存在内存泄漏的问题
//str以值传递的形式给p
//p是GetMemory函数的形参,只能函数内部有效,等GetNemory函数返回之后,动态开辟内存尚未释放并且
//无法找到,所以会造成内存泄露
改正1---传地址
void GetMemory(char** p)
{
*p=(char*)malloc(100);
}
void Test(void)
{
char *str=NULL;
GetMemory(&str);
strcpy(str,"hello world");
printf(str);//没有错误,同printf("abcdef");
}
int main()
{
Test();
return 0;
}
改进2:使用return
//练习43:模拟实现memmove,处理内存重叠情况
//根据src和dest的大小来选择从前向后拷贝还是从后向前拷贝
//这个会报错,有问题,可修改的左值,迷惑,,,
void* my_memmove(void* dest, const void* src,size_t num)
{
void* ret=dest;
//
assert(dest);
assert(src);
//判断
if(dest < src)//从前向后
{
while(num--)
{
*(char*)dest = *(char*)src;
++(char*)dest;
++((char*)src);
}
}
else
{
while(num--)
{
(*(char*)dest+num) = *((char*)src+num);
}
}
return ret;
}
int main()
{
int i=0;
int arr1[]={1,2,3,4,5,6,7,8,9,10};
my_memmove(arr1,arr1+3,3);
for(i=0;i<10;i++)
{
printf("%d ",arr1[i]);
}
printf("\n");
return 0;
}
//练习42:模拟实现memcpy
void* my_memcpy(void* dest,const void* src,size_t num)//size_t就是unsigned int
{
void* ret = dest;
//指针判断
assert(dest);
assert(src);
//void*不能进行解引用,必须先强制转化
while(num--)
{
*(char*)dest = *(char*)src;
++(char*)dest;
++(char*)src;
}
return ret;
}
struct S{
char name[20];
int age;
};
int main()
{
struct S arr1[]={{"zhangsan",20},{"lisi",25}};
struct S arr2[3]={0};
my_memcpy(arr2,arr1,sizeof(arr1));//num为整个数组的长度,单位为字节
return 0;
}
//练习41:strtok函数的使用,分割1048916893@qq.com
int main()
{
char str[]={"1048916893@qq.com"};
char p[]={"@."};
char* ret=0;
//调用strtok函数会破坏原字符串,因此需要赋值
char buf[256]={0};
strcpy(buf,str);
//调用切割
ret=NULL;
for(ret = strtok(str,p);ret != NULL;ret = strtok(NULL,p))
{
printf("%s\n",ret);
}
return 0;
}
//练习40:模拟实现strstr寻找子串函数
//难!!考虑全面
char * my_strstr(char* p1,char* p2)
{
char* s1 = p1;
char* s2 = p2;
char* cur = p1;
assert(p1 !=NULL);
assert(p2 !=NULL);
if(*p2 == '\0')
{
return p1;
}
while(*cur)
{
s1 = cur;
s2 = p2;
while((*s1 != '\0')&&(*s2 !='\0')&&(*s1 == *s2))
{
s1++;
s2++;
}
if(*s2 == '\0')
{
return cur;
}
cur++;
}
return NULL;
}
int main()
{
char p1[]={"abcedf"};
char p2[]={"ced"};
char* ret=0;
ret=my_strstr(p1,p2);
if(ret != NULL)
{
printf("成功\n");
}
return 0;
}
//练习39:模拟实现strcmp函数
int my_strcmp(const char* str1,const char*str2)
{
assert(str1);
assert(str2);
while(*str1 == *str2)
{
if(*str1 == '\0')
{
return 0;
}
str1++;
str2++;
}
if(*str1 > *str2)
{
return 1;
}
else
{
return -1;
}
}
return (*str1 - *str2);
int main()
{
int ret=0;
char p1[]={"zbcedfg"};
char p2[]={"xyz"};
ret=my_strcmp(p1,p2);
printf("%d\n",ret);
return 0;
}
//练习38:实现追加字符串函数模拟实现
//strcat
char* my_strcat(char* dest,const char* src)
{
char* ret=dest;
//1、找到目标字符串的\0
while(*dest != '\0')
{
dest++;
}
//2、复制
while(*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[30]={"hello"};
char arr2[]={"world"};
char* temp=0;
temp=my_strcat(arr1,arr2);
printf("%s\n",temp);
return 0;
}
//练习37:在杨氏矩阵中寻找一个数字
//杨氏矩阵:每行每列都是递增
//要求:时间复杂度小于0(N)
//使用矩阵右上角或者左下角元素进行收缩,每次判断去掉一行或一列
//形参处必须声明,接收数组的大小,行列
int FindNum(int arr[3][3],int k,int row,int col)
{
int x=0;
int y=col-1;
//确定右上角元素坐标
while((x<=2)&&(y>=0))
{
if(arr[x][y]<k)
{
x++;
}
else if(arr[x][y]>k)
{
y--;
}
else
{
return 1;
}
}
return 0;
}
int main()
{
int arr[3][3]={{1,2,3},{4,5,6},{7,8,9}};
int ret=0;
//封装一个函数,先设定再实现
ret=FindNum(arr,7,3,3);
if(ret==1)
{
printf("找到了!\n");
}
else
{
printf("找不到!\n");
}
return 0;
}
//改进:可以通过&x,&y返回型参数来带回坐标值
//练习36:判断两个字符串,是否由左旋关系
//abcdefgabcdefg包含左旋后的所有情况--因此寻找此字串
//
int is_move(char* arr1,char* arr2)
{
int len1=0;
int len2=0;
char* temp=NULL;
//空指针判断
assert(arr1);
assert(arr2);
//1、追加字符串
len1=strlen(arr1);
len2=strlen(arr2);
if(len1 != len2)
{
return 0;
}
strncat(arr1,arr1,len1);
//2、判断子串
temp=strstr(arr1,arr2);
if(temp==NULL)
{
return 0;
}
else
{
return 1;
}
}
int main()
{
//不能给常量字符串,要以数组形式,可以改变
char arr1[20]={"abcdef"};//arr1[]不能空着,一定要开辟足够大的空间
char arr2[]={"defabc"};
int ret=0;
ret=is_move(arr1,arr2);
if(ret==1)
{
printf("YES!\n");
}
else
{
printf("NO!\n");
}
return 0;
}
练习35:左旋字符串
不能使用常量字符串,因为不能被修改,应该使用数组
//1、暴力求解法
void l_rotate(char *arr,int k)
{
int len=0;
char temp='0';
int i=0;
//传入参数有指针,判断assert
assert(arr);
len=strlen(arr);//到0停止,不包含0
for(i=0;i<k;i++)
{
int j=0;
//1----把第一位拿出来
temp=*arr;
//2----后面依次往前移
for(j=0;j<len-1;j++)
{
*(arr+j)=*(arr+j+1);
}
//3----把第一位放最后
*(arr+len-1)=temp;
}
}
int main()
{
char arr[]={"abcdef"};
int k=0;
l_rotate(arr,3);
printf("%s\n",arr);
return 0;
}
//2、三步逆序法
//abcdef
//ba fedc
//cdefab
void reverse(char* left,char* right)
{
//判断空指针
assert(left);
assert(right);
while(left<right)
{
char temp=0;
temp=*left;
*left=*right;
*right=temp;
left++;
right--;
}
}
void left_rotate(char *arr,int k)
{
int len=0;
//判断空指针
assert(arr);
len=strlen(arr);
reverse(arr,arr+k-1);//逆序左边,输入需要字符串的左边右边指针
reverse(arr+k,arr+len-1);//逆序右边
reverse(arr,arr+len-1);//整个逆序
}
int main()
{
char arr[]={"abcdefg"};
left_rotate(arr,3);
printf("%s\n",arr);
return 0;
}
//练习34:预测比赛结果
//A:B第二;我第三
//B:我第二,E第四
//C:我第一,D第二
//D:C最后,我第三
//E:我第四,A第一
//比赛结束后,每位选手都说对了一半,请编程确定比赛的名次
int main()
{
int a=0;
int b=0;
int c=0;
int d=0;
int e=0;
for(a=1;a<=5;a++)
{
for(b=1;b<=5;b++)
{
for(c=1;c<=5;c++)
{
for(d=1;d<=5;d++)
{
for(e=1;e<=5;e++)
{
if(((b==2)+(a==3)==1)
&&((b==2)+(e==4)==1)
&&((c==1)+(d==2)==1)
&&((c==5)+(d==3)==1)
&&((e==4)+(a==1)==1))
{
if(a*b*c*d*e==120)
{
printf("a==%d,b=%d,c=%d,d=%d,e=%d\n",a,b,c,d,e);
}
}
}
}
}
}
}
return 0;
}
//练习33:判断凶手
//A说:不是我
//B说:是C
//C说:是D
//D说:C在胡说
//已知3个人说了真话,1个人说的是假话
//判断谁是凶手
int main()
{
char killer ='0';
//依次假设ABCD为凶手
for(killer='a';killer<='d';killer++)
{
if((killer!='a')+(killer=='c')+(killer=='d')+(killer!='d')==3)
{
printf("killer = %c\n",killer);
}
}
return 0;
}
练习32:打印杨辉数列
1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
int main()
{
int arr[10][10]={0};
int i=0;
int j=0;
//首先将第一列和对角列全部置1
for(i=0;i<10;i++)
{
for(j=0;j<=i;j++)
{
//第一列和对角列
if((j==0)||(i==j))
{
arr[i][j]=1;
}
//中间
if((i>=2)&&(j>=1))
{
arr[i][j]=arr[i-1][j-1]+arr[i-1][j];
}
}
}
//打印
for(i=0;i<10;i++)
{
for(j=0;j<=i;j++)
{
printf("%d ",arr[i][j]);
}
printf("\n");
}
return 0;
}
//练习31:调整数组内容使奇数全部位于偶数前面
//有一些问题,arr[left]和arr[right]
//数组:1 2 3 4 5 6 7 8 9 10
void move(int *arr,int size)
{
int *left=arr;
int *right=arr+size-1;
while(left<right)
{
//从左边找偶数
while((left<right)&&((*left)/2==1))
{
left++;
}
//从右边找奇数
while((left<right)&&((*right)/2==0))
{
right--;
}
//交换
if(left<right)
{
int temp=0;
temp=*left;
*left=*right;
*right=temp;
}
}
}
void print(int *arr,int size)
{
int i=0;
for(i=0;i<size;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9};
int sz=0;
sz=sizeof(arr)/sizeof(arr[0]);
move(arr,sz);
print(arr,sz);
return 0;
}
//练习30:换汽水喝
int main()
{
//汽水分为买的+换的
int money=0;
int total=0;
int empty=0;
printf("请输入金额:\n");
scanf("%d",&money);
//买的汽水
total=money;
//换的汽水
empty=money;
while(empty>=2)
{
total += empty/2;
empty=empty/2+empty%2;
}
printf("汽水数为:%d\n",total);
return 0;
}
//练习29:找出1-10000的水仙花数
int main()
{
int i=0;
//1、产生1-10000数字
for(i=0;i<100000;i++)
{
int n=1;//记录每个i的位数
int tmp=i;
int ret=0;
//2、判断i
//123/10 n++
//12/10 n++
//1/10=0
while(tmp/=10)
{
n++;
}
//3、计算每位数的n次方之和
//得到每位数字%10
tmp=i;
while(tmp)
{
ret=ret+pow(tmp%10,n);
tmp/=10;
}
//4、判断是否等于i,即为水仙花数
if(ret==i)
{
printf("%d ",i);
}
}
return 0;
}
//练习28:计算实现a+aa+aaa+aaaa+……
int main()
{
int a=0;
int n=0;
int sum=0;
int i=0;
int ret=0;
printf("请输入a和n:\n");
scanf("%d%d",&a,&n);
for(i=0;i<n;i++)
{
ret=a+10*ret;
sum=sum+ret;
}
printf("结果为:%d\n",sum);
return 0;
}
//练习27:函数实现,字符串逆序
void reverse(char *str)
{
int len=strlen(str);
char *left=str;
char *right=str+len-1;
assert(str);
while(left<right)
{
char temp=0;
temp=*left;
*left=*right;
*right=temp;
left++;
right--;
}
}
int main()
{
char arr[256]={0};
printf("请输入字符串:\n");
//scanf("%s",arr);//abcdef
gets(arr);
reverse(arr);//逆序函数
printf("逆序后的字符串:%s\n",arr);
return 0;
}
//二维数组
int main()
{
int a[3][4]={0};
printf("%d\n",sizeof(a));//48,sizeof(数组名)计算的是整个数组的大小,
printf("%d\n",sizeof(a[0][0]));//4,计算首元素大小,单位字节
printf("%d\n",sizeof(a[0]));//16,a[0]代表第一行作为一维数组的数组名
//sizeof(arr[0])把数组名单独放在sizeof()内,计算的是第一行的大小
printf("%d\n",sizeof(a[0]+1));//4/8,没有单独方a[0],此时a[0]代表的是一维数组的首元素地址,
//把二维数组看做一维数组,首元素就是第一行数组,a[0]+1就是第2行数组地址,地址大小为4/8
printf("%d\n",sizeof(*(a[0]+1)));//4,a[0]+1解引用是第一行第二个元素,大小为4个字节
printf("%d\n",sizeof(a+1));//4/8,没有单独,所以是首元素地址,二维数组的首元素就是第一行数组,a+1就是第2行数组地址,地址大小为4/8
printf("%d\n",sizeof(*(a+1)));//16,对第2行的数组地址解引用,计算的是数组的大小
printf("%d\n",sizeof(&a[0]+1));//4/8,地址,第2行的地址
printf("%d\n",sizeof(*(&a[0]+1)));//16,计算第2行数组长度
printf("%d\n",sizeof(*a));//16,a是首元素地址,第一行地址,*a就是第一行,sizeof(*a)就是计算第一行的大小
printf("%d\n",sizeof(a[3]));//16,不会真的访问第4行,只知道是一个一维4列数组
return 0;
}
//字符数组
//strlen计算字符串长度,给地址,到\0为止
int main()
{
char arr[]={'a','b','c','d','e','f'};
printf("%d\n",strlen(arr));//随机值
printf("%d\n",strlen(arr+0));//随机值
printf("%d\n",strlen(*arr));//不合法
printf("%d\n",strlen(arr[1]));//不合法
printf("%d\n",strlen(&arr));//数组地址,随机值
printf("%d\n",strlen(&arr+1));//随机值
printf("%d\n",strlen(&arr[0]+1));//随机值
return 0;
}
//字符串数组
int main()
{
char arr[]="abcedf";
printf("%s\n,sizeof(arr)");//7,sizeof(arr)计算的是数组的大小,单位是字节
printf("%s\n,sizeof(arr+0)");//4/8,代表的是首元素地址,地址大小是4/8
printf("%s\n,sizeof(*arr)");//1,计算的是首元素的大小,1字节
printf("%s\n,sizeof(arr[1])");//1,首元素大小,1字节
printf("%s\n,sizeof(&arr)");//4/8,取地址是整个数组的地址,但还是地址,地址大小为4/8字节
printf("%s\n,sizeof(&arr+1)");//4/8,&arr+1是跳过整个数组的地址,还是地址,大小是4/8字节
printf("%s\n,sizeof(&arr[0]+1)");//4/8,第二个元素的地址,地址大小为4/8字节
return 0;
}
//一维数组
//数组名是首元素的地址
//1、sizeof(数组名)-数组名表示整个数组
//2、&数组-数组名表示整个数组
int main()
{
int a[]={1,2,3,4};
printf("%d\n",sizeof(a));//16,sizeof(数组名)-计算的是整个数组的总大小,sizeof的单位都是字节
printf("%d\n",sizeof(a+0));//4/8,数组名这里表示首元素的地址,a+0还是首元素地址,地址的大小就是4/8字节
printf("%d\n",sizeof(*a));//4,a表示首元素地址,*a解引用表示首元素,首元素大小是4字节
printf("%d\n",sizeof(a+1));//4/8,a+1表示第2个元素的地址,为4/8
printf("%d\n",sizeof(a[1]));//4,表示第2个元素,大小为4字节
printf("%d\n",sizeof(&a));//4/8,&a表示整个数组地址,但也是地址,所以是4/8
printf("%d\n",sizeof(*&a));//16,对整个数组地址解引用,即为整个数组,整个数组大小为16字节
printf("%d\n",sizeof(&a+1));//4/8,&a是数组的地址,&a+1虽然地址跳过整个地址,但是还是地址,大小为4/8字节
printf("%d\n",sizeof(&a[0]));//4/8,对首元素取地址,&a[0]是首元素地址
printf("%d\n",sizeof(&a[0]+1));//4/8,&a[0]+1是第2个元素
return 0;
}
//练习26:使用函数指针数组来进行计算器实现
方式2:使用回调函数,使用函数指针
void menu()
{
printf("**************************\n");
printf("***1.Add 2.Sub****\n");
printf("***3.Mul 4.Div****\n");
printf("*********0.exit***********\n");
printf("**************************\n");
}
int Add(int x,int y)
{
return x+y;
}
int Sub(int x,int y)
{
return x-y;
}
int Mul(int x,int y)
{
return x*y;
}
int Div(int x,int y)
{
return x/y;
}
void cal(int (*p)(int,int))
{
int x=0;
int y=0;
int ret=0;
printf("请输入两个操作数:");
scanf("%d%d",&x,&y);
ret=p(x,y);
printf("结果是%d\n",ret);
}
int main()
{
int input=0;
do{
menu();
printf("请选择数字:");
scanf("%d",&input);
switch(input)
{
case 0 :
printf("退出\n");
break;
case 1 :
cal(Add);
break;;
case 2 :
cal(Sub);
break;
case 3 :
cal(Mul);
break;
case 4 :
cal(Div);
break;
default:
printf("选择错误\n");
}
}while(input);
return 0;
}
//方式1:使用函数指针数组
void menu()
{
printf("**************************\n");
printf("***1.Add 2.Sub****\n");
printf("***3.Mul 4.Div****\n");
printf("*********0.exit***********\n");
printf("**************************\n");
}
int Add(int x,int y)
{
return x+y;
}
int Sub(int x,int y)
{
return x-y;
}
int Mul(int x,int y)
{
return x*y;
}
int Div(int x,int y)
{
return x/y;
}
int main()
{
int input=0;
int x=0;
int y=0;
int ret=0;
int(*pa[])(int,int)={0,Add,Sub,Mul,Div};
do{
menu();
printf("请选择数字:");
scanf("%d",&input);
if(input <=4 && input >=1)
{
printf("请输入两个操作数:");
scanf("%d%d",&x,&y);
ret = pa[input](x,y);
printf("结果是:%d\n",ret);
}
else if(input == 0)
{
printf("退出\n");
break;
}
else
{
printf("选择错误\n");
}
}while(input);
return 0;
}
//函数指针数组
int Add(int x,int y)
{
return x + y;
}
int Sub(int x,int y)
{
return x - y;
}
int Mul(int x,int y)
{
return x * y;
}
int Div(int x,int y)
{
return x / y;
}
int main()
{
//指针数组
int * arr[5];
//需要一个数组,这个数组可以存放4个函数的地址-函数指针的数组
int (*pa)(int,int)=Add;
int (*parr[4])(int,int)={Add,Sub,Mul,Div};//函数指针的数组
int i=0;
for(i=0;i<4;i++)
{
printf("%d\n",parr[i](2,3));
}
return 0;
}
//二级指针传参
void test(char **p)
{
}
int main()
{
char c='b';
char*pc=&c;
char**ppc=&pc;
char* arr[10];
test(&pc);//可以传一维指针的地址
test(ppc);//一维指针的指针
test(arr);//一维指针数组的数组名
return 0;
}
二维数组传参
void test(int *arr)//err
{
}
void test(int* arr[5])/err
{
}
void test(int (*arr)[5])//right
{
}
void test(int **arr)//err
{
}
int main()
{
int arr[3][5]={0};
test(arr);
}
//一维数组传参
#include <stdio.h>
void test(int arr[])
{
}
void test(int arr[10])
{
}
void test(int *arr)
{
}
void test2(int *arr[20])
{
}
void test2(int **arr)
{
}
int main()
{
int arr[10]={0};
int *arr2[20]={0};
test(arr);
test2(arr2);
return 0;
}
练习25:判断大端小端字节序存储模式
指针类型决定指针解引用可以访问的字节数
版本1
int main()
{
int a=1;
char* p=(char*)&a;
if(*p == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
//版本2:使用函数,精简
int check_sys()
{
int a=1;
return *(char*)&a;
}
int main()
{
int ret=0;
//定义一个函数,返回值为1即为小端;返回值为0即为大端
ret=check_sys();
if(ret == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
//练习24:使用指针实现strcpy
void my_strcpy(char* des,char*src)
{
while(*src!='\0')
{
*des=*src;
des++;
src++;
}
*des=*src;
}
///改进1:更加精简,判断条件更精妙
void my_strcpy(char* des,char*src)
{
while(*des++=*src++)
{
;
}
}
///改进2:先判断指针的有效性,避免程序出问题,但是容易隐匿错误
void my_strcpy(char* des,char*src)
{
if(des != NULL && src!= NULL)
{
while(*des++=*src++)
{
;
}
}
}
///改进3:使用assert()断言,发现错误时,及时报错
//包含头文件
#include <assert.h>
void my_strcpy(char* des,char*src)
{
assert(des != NULL);//断言,符合条件时继续执行,不符合时报错提示
assert(src != NULL);//断言判断!!
while(*des++=*src++)
{
;
}
}
改进4:使用const,char*
包含头文件,加上返回函数,函数功能更丰富
#include <assert.h>
char* my_strcpy(char* des,const char*src)
{
char* ret=des;
assert(des != NULL);//断言,符合条件时继续执行,不符合时报错提示
assert(src != NULL);//断言判断!!
while(*des++=*src++)
{
;
}
return ret;
}
int main()
{
char arr1[]={"#####################"};
char arr2[]={"bit"};
my_strcpy(arr1,arr2);
printf("%s\n",arr1);
return 0;
}
//练习23:递归计算N的K次方
//n^k=n*n^(k-1)
double Power(int n,int k)
{
if(k<0)
return 1.0/Power(n,(-k));
else if(k==0)
return 1.0;
else
return n*Power(n,k-1);
}
int main()
{
int n=0;
int k=0;
double ret=0.0;
scanf("%d%d",&n,&k);
ret=Power(n,k);
printf("%lf\n",ret);
return 0;
}
//练习22:使用递归来计算一个非负整数各位数字之和
//1729
//DigitSum(172)+9%10
//DigitSum(17)+2%10+9%10
//DigitSum(1)+7%10+2%10++9%10
//1%10+7%10+2%10++9%10
int DigitSum(int num)
{
int count=0;
if(num>9)
return count=DigitSum(num/10)+num % 10;
else
return num;
}
int main()
{
int num=0;
int sum=0;
printf("请输入数字:");
scanf("%d",&num);
sum=DigitSum(num);
printf("%d\n",sum);
return 0;
}
//练习21:分别打印二进制数中的奇数位和偶数位
//32:0000000000000000000000000000000011
void print(int m)
{
int i=0;
printf("偶数位:\n");
for(i=30;i>=0;i=i-2)
{
printf("%d ",(m>>i)&1);
}
printf("\n");
printf("奇数位:\n");
for(i=31;i>=0;i=i-2)
{
printf("%d ",(m>>i)&1);
}
printf("\n");
}
int main()
{
int num=0;
printf("请输入数字:\n");
scanf("%d",&num);
print(num);
return 0;
}
//练习20:数一个二进制数中的1的个数
//这个是最优解!!!!!
//n=n&(n-1)的次数,直至n!=0
//这个循环可以执行的次数=二进制中的1的个数
//计算子函数
//int count_bit_one(int n)
//{
// int count=0;
// while(n)
// {
// n=n&(n-1);
// count++;
// }
// return count;
//}
//练习19:数组练习
//自己写函数实现1、数组元素初始化
//2、打印数组元素
//3、reverse逆序排列数组元素
//初始化函数
void Init(int arr[],int size)
{
int i=0;
for(i=0;i<size;i++)
{
arr[i]=i;
}
}
//打印数组元素
void Print(int arr[],int size)
{
int i=0;
for(i=0;i<size;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
//逆序数组元素
void Reverse(int arr[],int size)
{
int left=0;
int right=size-1;
while(left<=right)
{
int temp=0;
temp=arr[right];
arr[right]=arr[left];
arr[left]=temp;
left++;
right--;
}
}
int main()
{
int arr[10]={0};
int size=0;
size=sizeof(arr)/sizeof(arr[0]);
//初始化数组元素
Init(arr,size);
//打印数组元素
Print(arr,size);
//逆序数组
Reverse(arr,size);
//打印数组元素
Print(arr,size);
return 0;
}
//练习18:实现strlen,用指针-指针
//
int my_strlen(char* arr)
{
char* str=arr;
char* ptr=arr;
while(*ptr != '\0')
{
ptr++;
}
return ptr-str;
}
int main()
{
char arr[]={"bityyyy"};
int num=0;
num=my_strlen(arr);
printf("数组长度为%d\n",num);
return 0;
}
//练习17:一个二进制数在内存中1的个数
//方式一:模2除2在处理负数时有问题(可以转换为unsigned int)可以解决负数问题
//方式二:依次右移,与1
int main()
{
int num=-1;
int count=0;
int i=0;
/*while(num)
{
if(num%2 == 1)
{
count++;
}
num=num/2;
}*/
for(i=0;i<32;i++)
{
if(1 == ((num>>i)&1))
{
count++;
}
}
printf("%d\n",count);
return 0;
}
//练习16:冒泡排序法,升序排序
//冒泡排序函数
//数组传过去的是数组首元素的地址,&arr[0]
//arr[]为一个指针
void bubble_sort(int arr[],int size)
{
//这个数组元素为size=9,需要排8趟,size-1
int i=0;
//采用flag对冒泡排序进行算法优化
for(i=0;i<size;i++)
{
//每趟需要比较
int flag=1;
int j=0;
for(j=0;j<size-1-i;j++)
{
if(arr[j]>arr[j+1])
{
int temp=0;
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
flag=0;
}
}
if(flag==1)
{
break;
}
}
}
//主函数
int main()
{
int arr[]={9,8,11,6,5,4,20,2,1};
int size=0;
int i=0;
size=sizeof(arr)/sizeof(arr[0]);
//排序函数
bubble_sort(arr,size);
for(i-0;i<size;i++)
{
printf("%d ",arr[i]);
}
return 0;
}
//练习15:求N的阶乘
//方式一:循环
//方式二:递归调用
int fac1(int n)
{
int i=0;
int ret=1;
for(i=1;i<=n;i++)
{
ret=ret*i;
}
return ret;
}
int fac2(int n)
{
if(n<=1)
{
return 1;
}
else
{
//!!!!!!!!!!!!!!!
return n*fac2(n-1);
}
}
int main()
{
int n=0;
int ret=0;
printf("请输入n:\n");
scanf("%d",&n);
ret=fac2(n);
printf("%d\n",ret);
return 0;
}
//练习14:求字符串的长度
//方式一:
int my_len(char* arr)
{
int count=0;
while(*arr !='\0')
{
count++;
arr++;
}
return count;
}
方式二:不使用创建临时变量,函数递归!!
分解;
!!!!!大事化小!!!!!!
1+my_len("it")
1+1+my_len("t")
1+1+1+my_len("\0")
1+1+1+0
函数的递归使用
int my_len(char* arr)
{
if(*arr != '\0')
{
return 1+my_len(arr+1);
}
else
{
return 0;
}
}
主函数体
int main()
{
//字符型要用char
char arr[]="bit";
int num=0;
num=my_len(arr);
printf("%d\n",num);
return 0;
}
//练习13:函数的递归
//打印出输入数字的每一位数字,使用函数递归的方式
//递归的两个条件:1、存在限制条件,2、每次递归越接近这个条件
void print(int input)
{
if(input>10)
{
print(input/10);
}
printf("%d ",input%10);
}
int main()
{
int input;
printf("请输入数字:\n");
scanf("%d",&input);
//函数调用
print(input);
return 0;
}
//练习12:
//猜数字游戏
//游戏(子函数)
void game()
{
int ret=0;
int guess=0;
printf("欢迎来到猜数字游戏!\n");
printf("请输入猜测数字:\n");
//系统随机生成随机数
//利用不断随时间变化的时间戳来作为生成随机数的变化变量
//time()函数可以获取系统时间戳,NULL为空指针
srand((unsigned int)time(NULL));
ret=rand();
ret = ret%100;
//printf("%d\n",ret);
do
{
scanf("%d",&guess);
if(guess>ret)
{
printf("猜大了\n");
}
else if(guess<ret)
{
printf("猜小了\n");
}
else
{
printf("恭喜你!猜对了!\n");
break;
}
}
while(1);
}
//主界面(子函数)
void win()
{
printf("*******************************\n");
printf("**********猜数字游戏***********\n");
printf("*******************************\n");
printf("请输入1或0,1开始游戏,0结束游戏\n");
}
int main()
{
int input=0;
do
{
win();
scanf("%d",&input);
switch(input)
{
case 1 :
game();
break;
case 0 :
printf("游戏结束!\n");
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
}
while(input);
return 0;
}
练习11:九九乘法表
1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
,,,
9*1=9 ,,,9*9=9
int main()
{
int i=0;
//确定行数
for(i=1;i<=9;i++)
{
//确定每行项数(列数)
int j=0;
for(j=1;j<=i;j++)
{
//%-2d可以更好地左对齐,%2d为右对齐,不够2位空格补齐
printf("%d*%d=%-2d ",i,j,i*j);
}
printf("\n");
}
return 0;
}
//练习10:分数求和
//1/1-1/2+1/3。。。。+1/99-1/100
int main()
{
int i=0;
double sum=0.0;
int flag=1;
for(i=1;i<=100;i++)
{
sum += flag*(1.0/i);
flag=-flag;
}
printf("%lf\n",sum);
return 0;
}
//练习9:判断输出100-200的素数
//试除法
//一个一个除->到sqrt->到在非偶数中找素数
//注意提高代码的效率,培养自己的代码思想
int main()
{
int i=0;
int j=0;
int count=0;
for(i=101;i<=200;i+=2)
{
for(j=2;j<= sqrt(i);j++)
{
if(i%j==0)
{
break;
}
}
if(j> sqrt(i))
{
printf("%d ",i);
count++;
}
}
printf("\ncount=%d ",count);
return 0;
}
//练习8:判断输出1000到2000内的闰年
//闰年的判断
//1、被4整除同时不被100整除
//2、被400整除
int main()
{
int count=0;
int i=0;
for(i=1000;i<=2000;i++)
{
if(((i%4==0) && (i%100!=0))||(i%400==0))
{
count++;
printf("%d ",i);
}
}
printf("\n,count=%d",count);
return 0;
}
//练习7:求出两个数的最大公约数
//辗转相除法
int main()
{
int m=0;
int n=0;
int r=0;
printf("请输入2个数字:\n");
scanf("%d%d",&m,&n);
///程序效率会更高
wile(r=m%n)
while(m%n)
{
r=m%n;
m=n;
n=r;
}
printf("最大公约数为%d",n);
}
//练习6:输出1至100中3的倍数
//!!!!!!!有一点疑问,怎么控制逢5换行
int main()
{
int i=0;
int j=0;
for(i=0;i<=100;i++)
{
if(i%3 ==0)
{
j++;
printf("%d ",i);
}
if(j%5 == 0)
printf("\n");
}
printf("\n");
return 0;
}
//练习5:比较3个数中的最大,中,最小
//按从大到小的顺序输出
int main()
{
int a=0;
int b=0;
int c=0;
printf("请输入3个数字:\n");
scanf("%d%d%d",&a,&b,&c);
if(a<b)
{
int temp=a;
a=b;
b=temp;
}
if(a<c)
{
int temp=a;
a=c;
c=temp;
}
if(b<c)
{
int temp=b;
b=c;
c=temp;
}
printf("%d %d %d",a,b,c);
return 0;
}
//练习题4
//演示多个字符从两端移动,向中间汇聚
int main()
{
char arr1[]={"Welcome to C world !"};
char arr2[]={"*********************"};
int num1=sizeof(arr1)/sizeof(arr1[0]);
int num2=sizeof(arr2)/sizeof(arr2[0]);
int left=0;
int right=num1-1;
printf("%s\n",arr1);
while(left <= right)
{
arr1[left]=arr2[left];
arr1[right]=arr2[right];
printf("%s\n",arr1);
left++;
right--;
}
return 0;
}
//练习题3,使用二分法查找
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9};
int m=0;
int mid=0;
int num=sizeof(arr)/sizeof(arr[0]);
int left=0;
int right=num-1;
printf("请输入查找的数字:");
scanf("%d",&m);
while(left<=right)
{
mid=(left+right)/2;
if(m>arr[mid])
{
left=mid+1;
}
else if(m<arr[mid])
{
right=mid-1;
}
else
{
printf("成功找到数字!下标为%d\n",mid);
break;
}
}
if(left>right)
{
printf("找不到!\n");
}
return 0;
}
//练习题3,在一个有序数组中查找某一个数字,
//第一种方法:按序查找
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9};
int i=0;
int m=0;
int num=0;
num=sizeof(arr)/sizeof(arr[0]);//确定数组元素个数
printf("请输入需要查找的数字:");
scanf("%d",&m);
for(i=0;i<num;i++)
{
if(m==arr[i])
{
printf("已经成功找到数字,下标为%d\n",i);
break;
}
}
if(i==num)
{
printf("查找失败!\n");
}
return 0;
}
//练习题2,计算1!+2!+3!+...+n!
int main()
{
//int i=1;
int s=0;
int n=1;
int sum=1;
int sum_0=0;
printf("请输入数字s:");
scanf("%d",&s);
for(n=1;n<=s;n++)
{
sum=sum*n;
sum_0 = sum_0 + sum;
}
printf("n!和为:%d\n",sum_0);
return 0;
}
练习题1-计算N的阶乘n!
int main()
{
int i=1;
int n=0;
int sum=1;
printf("请输入数字n:");
scanf("%d",&n);
for(i=1;i<n+1;i++)
{
sum=sum*i;
}
printf("n!为:%d\n",sum);
return 0;
}
C语言学习练习代码
最新推荐文章于 2023-09-22 21:16:54 发布