C程序的基本框架
#include<stdio.h>
int main()
{
//执行的代码
return 0;
}
gcc demo.c -o demo //把a,exe 改成demo
echo %errorlevel% 错误等级
数据表现形式
变量
四要素 变量值 类型 变量名 存储单元
int 4个字节,float 4 int float 编码格式不一样不能直接用不同的占位符直接输出
float
double
char
char*
驼峰命名法
int OneYear = 20;
void One_Year ()
{
//功能模块 函数写的东西
}
printf() 输出有 原样输出 %占位符/格式字符printf("%d",a)
printf("小黑子你好"); //原样输出
printf("%d",a); //%占位符输出
printf() 小练习 加减乘除
输入 scanf()
scanf()//z最好 多个变量 多个scanf()
原样输入,要输入相应的内容
scanf("%d",&data); // 不要在scanf里面+空格 和其他的符号 &取地址符号
scanf("%d%d%%d"&a,&b,&c); //正确方式
scanf("a=%d,b=%d,c=%d",&a,&b,&c);//这个要将括号里面的输入完全(错误方式)
1:scanf()函数混合输入
以上方法容易出错
其他输入输出方式
getchar();
putchar();
puts();
gets();
练习题
练习题1
输入大写字母 输出小写字母
练习题2
输入两个数 获得两个数的加减乘除 的值
练习题3
输入字符串 将输入的字符串加密 (在原来的基础之上往后移动四位)
总结
#include<stdio.h>
int main()
{
//原样输出
printf("jjjjj");
// %占位符输出
int a;
printf("%d",a); // %d %c %f %n.mf %-n.mf %p %x
//输入 scanf();
int b;
scanf("%d",b); //scanf()最好 一个i一个i用,
//原样输入
printf("%d",b);
//其他输入\输出方法
putchar(); 输出一个字符
puts(); 输出字符串
getchar(); 获得字符(你要输入的字符串)
gets(); 获取字符串
return 0;
}
#include<stdio.h>
int main()
{
int data;
char c = 'c';
char* f = "jdio";
float ff ;
printf("原样输出\n");
printf("占位符输出%d",data);
scanf("%d",&data);
putchar('');
getchar();
puts();
gets();
/*puts(); 与printf();的区别
puts(); 只能输出字符串,自动换行
printf(); 支持多样输出。不自动换行;
*/
}
换大小写字母
#include<stdio.h>
int main()
{
char a ;
char b;
printf("请输入字母\n");
scanf("%c",&a);
b=a+32;
printf("%c",a+32);
return 0;
}
2流程控制
1,控制语句
#include<stdio.h>
int main()
{
if(){
else if()
{
}
}else{
}
for(;;)
{
}
switch()
case:
return 0;
}
2 交换两个数字
3级交换数字
交换数字的时候要注意,要三次交换,先a<b a<c b<c
3逻辑运算
#或 与 非
逻辑运算if() 小练习 逻辑判断或与非
if() else() 小练习
if 嵌套语句运用
#include<stdio.h>
/*
嵌套用法
*/
int main()
{
int data1;
int data2;
int data3;
printf("相亲角\n");
puts("身体好么 好1,不好0");
scanf("%d",&data1);
if(data1 ==1)
{
printf("可以考虑交友\n");
puts("性格好么 好1 不好0");
scanf("%d",&data2);
if(data2 == 1)
{
printf("身体又好又温柔,真好\n");
puts("你有钱么");
scanf("%d",&data2);
if(data2 == 1)
{
printf("真名天子\n");
}else{
puts("身体很好,性格倒是不错,不过实力便是弱了些,再见");
}
}else{
puts("性格不合适");
}
}else{
printf("再见\n");
}
puts("相亲结束");
return 0;
}
switch case 用法
错误
a3.6_switch_case.c: In function 'main':
a3.6_switch_case.c:28:2: error: too few arguments to function 'gets'
gets();
^~~~
In file included from a3.6_switch_case.c:1:
C:/MinGW64/x86_64-w64-mingw32/include/stdio.h:658:17: note: declared here
char *__cdecl gets(char *_Buffer) __MINGW_ATTRIB_DEPRECATED_SEC_WARN;
解决方法
根据提供的错误信息,可以看出在你的代码文件 “a3.6_switch_case.c” 的第28行中,调用了函数 ‘gets’,但是没有传入任何参数。然而,根据C语言的标准库函数,‘gets’ 函数需要至少一个参数来接收输入的字符串。
需要修复这个问题,你可以在调用 ‘gets’ 函数时传入一个字符数组作为参数,用于接收输入的字符串。例如:
char input[100];
gets(input);
此外,需要注意的是,‘gets’ 函数在很多编译器中已经被标记为不安全和不推荐使用的函数,因为它容易导致缓冲区溢出的安全漏洞。建议使用更安全的函数替代,如 ‘fgets’ 函数。使用 ‘fgets’ 函数的示例代码如下:
char input[100];
fgets(input, sizeof(input), stdin);
使用 ‘fgets’ 函数时,需要指定接收输入的字符数组的大小,并传入 ‘stdin’ 作为最后一个参数,表示从标准输入中读取输入。
希望这些信息对你有所帮助!如果有任何其他问题,请随时提问。
正确代码
#include<stdio.h>
int main()
{
int data;
char cdata;
puts("please input the number");
scanf("%d",&data);
switch(data)
{
case 1:
puts("1");
break;//执行之后,跳出switch
case 2:
puts("2");
break;
case 3:
puts("3");
break;
case 4:
puts("4");
break;
default :
puts("other");
break;
}
getchar();
puts("please input string");
getchar(); // 吸收回车按键
//gets(); //gets 不建议使用 可以用 fgets();
scanf("%c",&cdata);
switch(cdata){
case 'a':
puts("ikun");
break;
case 'b':
puts("小黑");
break;
default :
puts("炒粉");
break;
}
return 0;
}
switch 学生成绩
#include<stdio.h>
int main()
{
int score;
puts("请输入成绩");
scanf("%d",&score);
switch(score/10){
case 0:;
puts("比蔡徐坤还蔡徐坤");
break;
case 1:
puts("你是真正的蔡徐坤");
break;
case 2:
puts("进步空间巨大");
break;
case 3:
puts("进步空间大");
break;
case 4:
case 5:
puts("59半步斗之气");
break;
case 6:
puts("60及格");
break;
case 7:
puts("70中等");
break;
case 8:
puts("80良好");
break;
case 9:
puts("90优秀");
break;
case 10:
puts("100顶尖");
break;
default:
puts("异常");
break;
}
return 0;
}
调试结果
计算折扣两种方法
if
#include<stdio.h>
int main()
{
float money;
int luCheng;
puts("您的路程为");
scanf("%d",&luCheng);
if(luCheng>=0 && luCheng<=100)
{
money =2;
printf("您行驶距离为%d\n您骑行的费用为%4.2f",luCheng,money);
}else if(luCheng>100 && luCheng<=500)
{
money = 2+(float)luCheng*0.008;
printf("您行驶的距离为%d\n您骑行的费用为%4.2f",luCheng,money);
}
else if(luCheng>500 && luCheng<=1000)
{
money = 2+(float)luCheng*0.006;
printf("您行驶的距离为%d\n您骑行的费用为%4.2f",luCheng,money);
}
else
{
money = 2+(float)luCheng*0.004;
printf("您行驶的距离为%d\n您骑行的费用为%4.2f",luCheng,money);
}
return 0;
}
switch case
#include<stdio.h>
int main()
{
float money;
int luCheng;
puts("please input lucheng number");
scanf("%d",&luCheng);
switch(luCheng)
{
case 0 ~ 100:
money = 2.00;
printf("您行驶的距离为%d\n您骑行的费用为%4.4f",luCheng,money);
break;
case 101~ 500:
money = 2.00+luCheng*0.008;
printf("您行驶的距离为%d\n您骑行的费用为%4.2f",luCheng,money);
break;
case 501~ 1000:
money = 2.00+luCheng*0.006;
printf("您行驶的距离为%d\n您骑行的费用为%4.2f",luCheng,money);
break;
case 999~ 5000:
money = 2.0+luCheng*0.005;
printf("您行驶的距离为%d\n您骑行的费用为%4.2f",luCheng,money);
break;
case 5001~10000 :
money = 2.0+luCheng*0.004;
printf("您行驶的距离为%d\n您骑行的费用为%4.2f",luCheng,money);
break;
default:
money = 2.0+luCheng*0.3;
printf("您行驶的距离为%d\n您骑行的费用为%4.2f",luCheng,money);
break;
}
return 0;
}
#include<stdio.h>
int main()
{
float money;
int luCheng;
puts("please input lucheng number");
scanf("%d",&luCheng);
switch(luCheng)
{
case 100:
money = 2.00;
printf("您行驶的距离为%d\n您骑行的费用为%4.4f",luCheng,money);
break;
case 500:
money = 2.00+luCheng*0.008;
printf("您行驶的距离为%d\n您骑行的费用为%4.2f",luCheng,money);
break;
case 1000:
money = 2.00+luCheng*0.006;
printf("您行驶的距离为%d\n您骑行的费用为%4.2f",luCheng,money);
break;
case 5000:
money = 2.0+luCheng*0.005;
printf("您行驶的距离为%d\n您骑行的费用为%4.2f",luCheng,money);
break;
case 10000:
money = 2.0+luCheng*0.004;
printf("您行驶的距离为%d\n您骑行的费用为%4.2f",luCheng,money);
break;
default:
//money = 2.0+luCheng*0.3;
printf("您行驶的距离为");/*%d\n您骑行的费用为%4.2f",luCheng,money)*/
break;
}
return 0;
}
作业
计算分段函数
#include<stdio.h>
int main()
{
int y;
int x;
puts("请输入一个数");
scanf("%d",&x);
if(x<1)
{
y=x;
printf("y的值为%d",y);
}else if(x>=1&&x<10)
{
y=2*x-1;
printf("y的值为%d=2*%d-1",y,x);
}else if(x>=10)
{
y=3*x-11;
printf("y的值为%d=3*%d-11\n",y,x);
}
return 0;
}
运行结果
个人成绩等级划分
#include<stdio.h>
int main()
{
int score;
puts("please input score");
scanf("%d",&score);
switch(score/10)
{
case 1:
case 2:
case 3:
case 4:
case 5:
printf("E不鸡格\n");
break;
case 6:
printf("D鸡哥\n");
break;
case 7:
printf("C中等\n");
break;
case 8:
printf("B良好\n");
break;
case 9:
printf("A优秀\n");
break;
case 10:
printf("S顶级\n");
break;
default:
printf("异常\n");
break;
}
return 0;
}
4 循环运算 for while do while
while
#include<stdio.h>
void jj()
{
int time;
int a;
while(a){
a=time--;
puts("徐坤");
}
}
int main()
{
int time;
unsigned int a;
time=2;
while(a)
{
a=time--;
puts("小黑");
}
return 0;
}
t--和--t的区别
t--(后置自减)先用 t 后减
--t (前置自减)t 先减 后用
int t = 5;
int result1 = t--; // result1 的值为 5,然后 t 的值变为 4
int t = 5;
int result2 = --t; // result2 的值先减为 4 ,然后 t 为4
for
九九乘法表
#include<stdio.h>
//乘法表
int main()
{
int a;
int b;
int c;
for(a=1;a<10;a++)
{
for(b=1;b<a;b++)
{
c=a*b;
printf("%d = %d*%d\n",c,a,b);
}
printf("\n");
}
printf("结束\n");
return 0;
}
break continue 的区别
for(renshu = 1; renshu <=1000; renshu++)
{
puts("请输入捐款数目:");
scanf("%d",&data);
ZongMoney = data+ZongMoney;
if(ZongMoney >= 100000)
{
puts("款项已经达到标准");
printf("钱总共有%d",ZongMoney);
break; //结束整个循环
}
}
for(data =100;data<=200;data++)
{
if(data%3 ==0)//被3整除的数
{
continue; //中断一个循环
}
printf("%d\n",data);
}
求取最小公倍数
#include<stdio.h>
//取最小公倍数 先比较两个数的大小,最小公倍数一定>=最大的数,
//然后依次取模
int main()
{
int data1;
int data2;
data1 =0;
data2 = 0;
int m;
puts("请输入两个数");
scanf("%d%d",&data1,&data2);
m = data1 < data2?data1:data2;
for(m;;m++)
{
if(m%data1==0 && m%data2==0)//
{
break;//中断整个循环
}
}
printf("%d",m);
return 0;
}
求取最大公约数
#include<stdio.h>
int main()
{
int data1;
int data2;
puts("please input tow number ");
scanf("%d%d",&data1,&data2);
int i;
int m;
int n;
for(i=1;i<=data1 && i<=data2;i++)
{
if(data1%i ==0&& data2%i ==0)
{
m=i;
//break;
}
}
n = data1*data2/m; //最小公倍数 == data1*data2 /最大公约数
printf("最大公约数是%d\n最小公倍数是%d",m,n);
return 0;
}
水仙花数
#include<stdio.h>
//求取 水仙花数 ==一个3位数 各位数字立方之和
// 153 ==1^3+5^3+3^3
int main()
{
int i;
int a;
int b;
int c;
for(i=100;i<=999;i++)
{
c = i%10;
b = (i/10)%10;
a = i/100;
if(i == a*a*a+b*b*b+c*c*c){
printf(" %d ",i);
}
}
return 0;
}
5,总结
#1 if语句
基本用法
if()//判断条件
{
//执行的模块
}else
{
}
连续判断
if()
{
}else if()
{
}else if()
{
}
嵌套用法
if()
{
if()
{
if()
{
}else{
}
}else{
}
}else{
}
switch case 用法
switch ()
{
case 1:
//执行的模块
break;
case 2:
break;
case 3:
break;
default :
break;
}
switch case 一般用于需要多种判断条件的时候
循环三剑客
fou
//基本用法
for(int i = 0;i<100;i++)
{
puts("jjjj");
}
//嵌套用法
int k;
for(int i;i<9;i++)
{
for(int j;j<i;j++)
{
k = i*j;
printf("%d=%d*%d",k,j,i);
}
printf("\n");
}
九九乘法表
#include<stdio.h>
//乘法表
int main()
{
int a;
int b;
int c;
for(a=1;a<10;a++)
{
for(b=1;b<=a;b++)
{
c=a*b;
printf(" %d=%d*%d ",c,a,b);
}
printf("\n");
}
printf("结束\n");
return 0;
}
while
//while 基本用法
while(time <100) //范围
{
puts("积极");//循环体
time--; //循环体
}
do while
do{
}while()
//日后再说,先循环,后判断条件
作业
求取最大公约数
#include<stdio.h>
int main()
{
int data1;
int data2;
puts("please input tow number ");
scanf("%d%d",&data1,&data2);
int i;
int m;
int n;
for(i=1;i<=data1 && i<=data2;i++)
{
if(data1%i ==0&& data2%i ==0)
{
m=i;
//break;
}
}
n = data1*data2/m; //最小公倍数 == data1*data2 /最大公约数
printf("最大公约数是%d\n最小公倍数是%d",m,n);
return 0;
}
最小公倍数
水仙花数
三位数 = 个个位数 三次方之和
3数组
1,定义一个数组
int a[10];
// 类型符 数组名 常量表达式
2,初始化数组
int a[10]={1,2,3,4,5,6,7,8,9,10};//全部赋值
int b[10]={1,2,3,4};//部分赋值
int c[10]={0}; //全部为零
int d[]={1,3,3,4,4,};//会根据大括号判断有多少个数
sizeof()
sizeof()//关键字 计算括号中对应数据的内存空间的大小
size_a = sizeof(a)/sizeof(a[0]);//计算个数
size_c = sizeof(c)/sizeof(c[0]);
size_b = sizeof(b)/sizeof(b[0]);
3,数组编程案列
数组初始化级逆序输出
#include<stdio.h>
int main()
{
int a[10];
int data;
int size;
int sizea;
int sizeb;
sizea = sizeof(a);
sizeb = sizeof(a[0]);
size = sizeof(a)/sizeof(a[0]);
for(data = 0;data<size;data++){
a[data] = data;
}
puts("初始化");
for(data = 0;data<size;data++)
{
printf("地址%p 数据%d\n",&a[data],a[data]);
}
puts("逆序输出");
for(data = size;data>=0;data--)
{
a[data] = data;
}
for(data = size ;data>=0;data--)
{
printf("%p %d\n",&a[data],a[data]);
}
printf("dome\n");
printf("%d\n",sizea);
printf("%d",sizeb);
return 0;
}
斐波那契数列输出
#include<stdio.h>
// a[i] = a[i-1]+a[i-2]
int main()
{
unsigned int arr[10];
int i;
int size;
arr[0]=0;
arr[1]=1;
size = sizeof(arr)/sizeof(arr[0]);
for(i=2;i<size;i++)
{
arr[i]=arr[i-1]+arr[i-2];
}
for(i=0;i<size;i++)
{
printf(" %d ",arr[i]);
}
printf("dome");
return 0;
}
冒泡排序法
#include<stdio.h>
int main()
{
int arr[]={12,34,5,5,5,666,53,343,4343,4332,53,432,534,2,5432};
int i;
int j;
int len;
int temp;
len = sizeof(arr)/sizeof(arr[0]);
for(i=0;i<len-1;i++)
{
for(j=0;j<len-i-1;j++)
{
if(arr[j]<arr[j+1])
{
temp = arr[i];
arr[i] =arr[i+1];
arr[i+1] = temp;
}
}
}
for(i=0;i<len;i++)
{
printf("%d ",arr[i]);
}
return 0;
}
0 1 2 3
0 1 2 3 4 2 1 3 4 2 3 1 4 2 3 4 1 1
1 2 3 4 3 2 4 3 4 2 2
2 3 4 4 3 3 3
2 4 4
i=len−1;j=len−1−i;
�
=
�
�
�
−
1
;
�
=
�
�
�
−
1
−
�
;
简单选择排序法
#include<stdio.h>
int main()
{
int i;
int j;
int temp;
int arr[]={1,2,5,6,66,5,55,6,22,6,22,55};
int len;
len = sizeof(arr)/sizeof(arr[0]);
for(i=0;i<len-1;i++)
{
for(j=i+1;j<len;j++)
{
if(arr[i]<arr[j])
{
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
for(i=0;i<len;i++)
{
printf(" %d ",arr[i]);
}
printf("\ndome");
return 0;
}
i<len−1j<leni表示比对的轮数j就是i后一位数
�
<
�
�
�
−
1
�
<
�
�
�
�
表
示
比
对
的
轮
数
�
就
是
�
后
一
位
数
4,二维数组
#include<stdio.h>
int main()
{
//定义一个二维数组
int arr[2][3]={{11,33,44},{33,55,66}};
int arr1[3][3]={1,2,3,4,5,6,7,8,9};
int i,j;
//遍历二维数组
for(i=0;i<2;i++)
{
for(j=0;j<3;j++)
{
printf("%d ",arr[i][j]);
}
printf("\n");
}
return 0;
}
二维数组初始化
// 二维数组 行可以省掉,但是列不能省
#include<stdio.h>
//3x4数组,求其最大的元素并输出,行和列
int main()
{
int i;
int j;
int max;
int arr[3][4]={1,3,22,34,54,54,32,3,7,66,5,234};
max = arr[0][0];
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
if(max<arr[i][j])
{
max = arr[i][j];
}
printf("%d ",arr[i][j]);
}
printf("\n");
}
printf("%d %d %d",max,i,j);
return 0;
}
4函数
函数作用
避免代码冗长
可以实现模块化设计
可以按功能进行划分
函数要先定义后使用跟 变量是一样的
函数的定义
三要素
函数名 (体现功能)
参数
返回值
无参数类型函数
站空位
案例
#include<stdio.h>
// 输入3个数 输出相应水仙花数 形式参数和实际参数 名 类型 值相同,地址不相同
// 生命周期: 被调用的时候才为 形式参数 申请内存空间,调用完后又被内存释放了;
int add(int data1, int data2,int data3) //形式参数
{
int ret;
ret = data1*data1*data1+data2*data2*data2+data3*data3*data3;
return ret;
}
int main()
{
int a;
int b;
int c;
int ret;
puts("请输入三个数");
scanf("%d%d%d",&a,&b,&c);//实际参数
ret = add(a,b,c);
printf("%d ",ret);
return 0;
}
#include<stdio.h>
int max(int x,int y)
{
int ret;
if(x<y)
{
ret = y;
}else if(x>y)
{
ret = x;
}else if(x=y)
{
ret = x =y;
}
//ret =a<b?a:b;//三目运算符
return ret;
}
int main()
{
int x;
int y;
puts("请输入两个数");
scanf("%d%d",&x,&y);
max(x,y);
printf("最大数位%d ",max(x,y));
}
函数的嵌套
案例
#include<stdio.h>
// 四个数比较大小 用函数实现
int max(int a,int b)
{
int ret;
ret = a>b?a:b;
return ret;
}
int bigdata(int a, int b, int c, int d)
{
int data;
data = max(a,b);
data = max(data,c);
data = max(data,d);
return data;
}
int main()
{
int a;
int b;
int c;
int d;
int big;
puts("please Input nums:");
scanf("%d%d%d%d",&a,&b,&c,&d);
big = bigdata(a,b,c,d);
printf("最大数为%d",big);
return 0;
}
这里用到了函数的嵌套法则,函数嵌套就是,当我们调用一个函数时,在这个函数又调用了其他的函数。
函数的递归
函数递归就是 在函数嵌套的过程中 把自己也嵌套进去了,这种情况容易出现死循环,递归不经常使用
#include<stdio.h>
//用递归的方式看年龄
int getAge(int num)
{
int ret;
if(num ==1)
{
ret =10;
}else{
ret = getAge(num-1)+2;
//现在年龄就是 上一个人的年龄+2 num-1就是上一个
}
return ret;
}
int main()
{
int num;
int age;
int agge;
puts("please Input You need num age :");
scanf("%d",&num);
agge = getAge(num);
printf("%d的年龄是%d",num,agge);
return 0;
}
以上是递归按照规律查找同学年龄的方式,
用递归求阶乘
#include<stdio.h>
#include<stdlib.h>
//递归求阶层
int getjiecheng(int a)
{
int ret;
if(a>=17)
{
printf("越界");
exit(-1); //直接退出程序 调用stdlib.h 库文件
}
if(a == 1)
{
ret = 1;
}else{
ret = getjiecheng(a-1)*a;
}
return ret;
}
int main()
{
int a;
int jiecheng;
puts("please Input You Need Numm");
scanf("%d",&a);
jiecheng = getjiecheng(a);
printf("%d的阶乘是%d",a,jiecheng);
return 0;
}
用递归的方式求取 阶乘。
阶乘a!=(a−1)∗a∗‘‘‘‘‘‘‘‘‘∗(a−n);;;;a!=(a−1)!∗a
阶
乘
�
!
=
(
�
−
1
)
∗
�
∗
‘
‘
‘
‘
‘
‘
‘
‘
‘
∗
(
�
−
�
)
;
;
;
;
�
!
=
(
�
−
1
)
!
∗
�
数组作为函数的参数
数组形参
根据您提供的代码和错误信息,出现了函数调用参数数量不匹配的错误。根据错误信息看,您在函数调用printArr()中没有传递足够的参数,但是函数printArr()在函数定义处声明了两个参数(int arr[]和int len)。
为了解决这个错误,您需要在函数调用printArr()中传递正确的参数数量,以匹配函数定义处的参数。根据函数定义处的声明,您需要传递一个int类型的数组和一个int类型的长度参数。
#include <stdio.h>
void printArr(int arr[], int len) {
int i;
for (i = 0; i < len; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
int len = sizeof(arr) / sizeof(arr[0]);
prin
arr 使用 sizeof 运算符的错误。警告信息指出 sizeof(arr) 返回的是指针类型 int * 的大小,而不是数组的大小。
在C语言中,当我们将数组传递给函数时,数组参数实际上是以指针的形式传递的,因此在函数内部无法通过 sizeof 运算符获取数组的大小。
#include<stdio.h>
//数组传参,形式参数的些许小问题。
// 传送过来的只是一个 地址 一个数组的首地址,数组首元素的地址
//形参中没有数组这个概念,即使标注数组的大小,也是无效的
//指针变量占 8个字节
void printArr(int arr[],int len)
{
int i;
printf("大小%d \n",len);
for(i=0;i<len;i++)
{
printf("%d ",arr[i]);
}
}
int main()
{
int len;
int arr[] = {1,2,3,4,5,6,7};
len = sizeof(arr)/sizeof(arr[0]);
printf("arr 的大小是%d\n",sizeof(arr));
printf("arr 元素有%d个\n",len);
printf("arr 单个元素大小是%d\n",sizeof(arr[0]));
printArr(arr,len);//数组名 代表数组首地址
printf(&arr[0],len); //第一个元素的地址也是 数组首地址
return 0;
}
数组实参
变量名 当作函数的实际参数
#include<stdio.h>
void dataa(int data)
{
data = data +1000;
printf("address %p, data %d",&data,data);
}
int main()
{
int data;
data=10;
printf("address %p %d \n",data);
dataa(data);
return 0;
}
当变量 为函数的实际参数的时候 只是将函数中变量的值进行传递,而地址并没有传递
这两个数据的地址是不相同的
数组名 当作函数实际参数
当数组名作为函数的实际参数的时候,不仅能够进行函数间的数值传递,而且能够将地址进行传递
#include<stdio.h>
int dataa(int arr[])
{
arr[0]=arr[0]+100;
printf("address %p ,data %d",&arr[0],arr[0]);
}
int main()
{
int arr[] = {1,33,4,23,35};
dataa(arr);
printf("\naddress %p ,data %d",&arr[0],arr[0]);
return 0;
}
地址是一样的
数组实战之计算不同班级平均分
在C语言中,当我们在函数调用中传递数组参数时,我们只需要传递数组名,而不需要使用[]符号。
为了解决这个问题,您需要在调用函数initArr()时,将数组名arr1作为参数传递,而不需要使用[]。
#include<stdio.h>
//计算两个班级 的平均分 5 10
void initArr(int arr[],int len)
{
int i;
for(i=0;i<len;i++)
{
printf("请输入第%d个同学的成绩\n",i+1);
scanf("%d",&arr[i]);
}
puts("dome\n");
}
void printArr(int arr[],int len)
{
int i;
printf("总人数是%d\n",len);
for(i=0;i<len;i++)
{
printf("第%d同学成绩是%d\n",i+1,arr[i]);
}
puts("\ndome");
}
float getpinjunfen(int arr[],int len)
{
int i;
float pingjunfen;
int sum;
for(i=0;i<len;i++)
{
sum = sum+arr[i];
}
pingjunfen = (float)sum/len;
return pingjunfen;
}
int main()
{
int arr1[5];
int arr2[10];
float aa;
float bb;
int len1 = sizeof(arr1)/sizeof(arr1[0]);
int len2 = sizeof(arr2)/sizeof(arr2[0]);
initArr(arr1,len1);
initArr(arr2,len2);
printArr(arr1,len1);
printArr(arr2,len2);
aa = getpinjunfen(arr1,len1);
bb = getpinjunfen(arr2,len2);
printf("1平均分为%2.2f\n2平均分为%2.2f",aa,bb);
printf("\n dome \n");
}
二维数组 和 函数 的概念 与实战
二维数组命名规范
int arr[][]; //错误的
int arr[][2] ={1,2,3,4,5,2,2,3,3,1,}; // 正确
int arr[2][3]// 正确
//二维数组命名 除了第一个维度不需要规定边界 第二维度,第n维度斗需要规定边界
// 注意两个点 二维数组的类型; 二维数组有多少个一维数组
二维数练习题
有3x4的矩阵,初始化并输出,然后求最大值并输出
#include<stdio.h>
// 输出4X5矩阵 求最大值
void initArr();
void printArr();
int getMax();
int main()
{
int arr[4][5];
int max;
int hang = 4;
int lie = 5;
initArr(arr,hang,lie);
printArr(arr,hang,lie);
max = getMax(arr,hang,lie);
printf("最大值为%d",max);
return 0;
}
//数组初始化
void initArr(int arr[][5],int hang,int lie)
{
int i;
int j;
for(i=0;i<hang;i++)
{
for(j=0;j<lie;j++)
{
printf("第%d行,第%d列",i+1,j+1);
scanf("%d",&arr[i][j]);
getchar();
}
}
printf("初始化完成\n");
}
//打印二维数组各个元素
void printArr(int arr[][5],int hang,int lie )
{
int i;
int j;
//遍历数组
for(i=0;i<hang;i++)
{
for(j=0;j<lie;j++) //当把j换成i的时候,会越界
{
printf("%d ",arr[i][j]);
}
printf("\n");
}
}
//获取最大值
int getMax(int arr[][5],int hang,int lie)
{
int i;
int j;
int max;
for(i=0;i<hang;i++)
{
for(j=0;j<lie;j++)
{
if(max<arr[i][j])
{
max =arr[i][j];
}
}
}
return max;
}
全局变量,外部变量,局部变量区别
#include<stdio.h>
int a = 10;
int b = 12;// 全局变量
void fun1()
{
printf("%d\n",a);
printf("%d\n",b);
}
int c = 1;
int d = 2; //外部变量
void fun2()
{
printf("%d\n",c);
printf("%d\n",c);
}
int main()
{
int aaa =11;
int bbb= 111; //局部变量
fun1();
fun2();
printf("%d\n",a);
printf("%d\n",b);
return 0;
}
程序是按照自上而下 的顺序进行编译的
全局变量是指变量不在函数中并且在最上面,外部变量上面有其他的函数,而且又不在函数内局部变量在函数中的变量
全
局
变
量
是
指
变
量
不
在
函
数
中
并
且
在
最
上
面
,
外
部
变
量
上
面
有
其
他
的
函
数
,
而
且
又
不
在
函
数
内
局
部
变
量
在
函
数
中
的
变
量
全局变量实战
#include<stdio.h>
//计算一个班级学生的平均分
int max;
int min;
float getAver(int arr[],int len)
{
int i;
int sum =0 ;
max = min = arr[0];//确定 取值范围 初始化
for(i=0;i<len;i++)
{
printf(" %d ",arr[i]);
if(max<arr[i])
{
max = arr[i];
}
if(min>arr[i])
{
min=arr[i];
}
sum = sum +arr[i];
}
return (float)sum/len;
}
int main()
{
int arr[] = {22,33,3};
int len;
len = sizeof(arr)/sizeof(arr[0]);
float aver;
aver = getAver(arr,len);
printf("最高分%d\n最低分%d\n平均分%2.2f\n",max,min,aver);
//printf(); 有优先级 先执行函数,后执行变量
return 0;
}
作业
在C语言中,当我们声明函数的参数时,不需要使用分号(;)来表示前向声明。
void init(int a; int b) //这里的;改为,
{
}
void initt(int a,int b)
{
}
#include <stdio.h>
void initArr(int arr[], int len) {
// 在这里初始化数组
}
int main() {
int arr[10];
int len = sizeof(arr) / sizeof(arr[0]);
initArr(arr, len);
// 在这里使用数组
return 0;
}
1,作业代码
#include<stdio.h>
/*
作业:输入十个数
求最大值,及下标
*/
void initArr(int arr[],int len)
{
int i;
printf("请输入10个数据\n");
for(i=0;i<len;i++)
{
scanf("%d",&arr[i]);
}
printf("\n初始化完成\n");
}
void printArr(int arr[], int len)
{
int i;
for(i=0;i<len;i++)
{
printf("%d ",arr[i]);
}
printf("\n打印结束");
}
int getMax(int arr[],int len)
{
int i;
int j;
int max=arr[0];
for(i=0;i<len;i++)
{
if(max<arr[i])
{
max = arr[i];
j=i;
}
}
return max;
}
int getj(int arr[],int len)
{
int i;
int j;
int max=arr[0];
for(i=0;i<len;i++)
{
if(max<arr[i])
{
max = arr[i]; //已经得到数组中最大的值
//但是下标问题,还没有解决
}
}
//再次遍历数组 寻找到与max的元素,这时候就可以找到下标了
for(i = 0;i<len;i++)
{
if(max == arr[i])
{
j = i+1;
}
}
return j;
}
int main()
{
int arr[10];
int len;
int max;
int j;
len =sizeof(arr)/sizeof(arr[0]);
initArr(arr,len);
printArr(arr,len);
max= getMax(arr,len);
j= getj(arr,len);
printf("最大值为%d 下标为%d",max,j);
return 0;
}
需求:输入10个数,然后输出最大值,以及最大值的下标。
定义一个有10个元素的数组,通过数组初始化,输出数组的元素,然后再通过 getmax()找到max
然后再找到下标。
初始化数组
void initArr(int arr[],int len)
{
int i;
printf("请输入10个数据\n");
for(i=0;i<len;i++)
{
scanf("%d",&arr[i]);
}
printf("\n初始化完成\n");
}
输出数组 遍历数组
void printArr(int arr[], int len)
{
int i;
for(i=0;i<len;i++)
{
printf("%d ",arr[i]);
}
printf("\n打印结束");
}
找到最大值
int getMax(int arr[],int len)
{
int i;
int j;
int max=arr[0];
for(i=0;i<len;i++)
{
if(max<arr[i])
{
max = arr[i];
j=i;
}
}
return max;
}
找到最大值的下标值
找最大值的下标值有很多种方法,这里是简单的方法,通过再次遍历数组,找出与max相等的元素,然后将其下标读取出来。直接返回
int getj(int arr[],int len)
{
int i;
int j;
int max=arr[0];
for(i=0;i<len;i++)
{
if(max<arr[i])
{
max = arr[i]; //已经得到数组中最大的值
//但是下标问题,还没有解决
}
}
//再次遍历数组 寻找到与max的元素,这时候就可以找到下标了
for(i = 0;i<len;i++)
{
if(max == arr[i])
{
j = i+1;
}
}
return j;
}
主函数
int main()
{
int arr[10];
int len;
int max;
int j;
len =sizeof(arr)/sizeof(arr[0]);
initArr(arr,len);
printArr(arr,len);
max= getMax(arr,len);
j= getj(arr,len);
printf("最大值为%d 下标为%d",max,j);
return 0;
}
2,封装冒泡排序法
#include<stdio.h>
void initArr(int arr[],int len)
{
int i;
int j;
int temp;
for(i=0;i<len-1;i++)
{
for(j=0;j<len-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<len;i++)
{
printf("%d ",arr[i]);
}
for(i=0;i<len;i++)
{
printf("\n%p ",&arr[i]);
}
}
int main()
{
int arr[] = {1,33,4,32,54,42,32,12};
int len = sizeof(arr)/sizeof(arr[0]);
initArr(arr,len);
return 0;
}
封装冒泡排序法,是需要数组传参。数组传参是将地址传过去,并不只是值。
3,封装选择牌序
#include<stdio.h>
void initxuanze(int arr[],int len)
{
int i;
int j;
int temp;
for(i=0;i<len-1;i++)
{
for(j=i+1;j<len;j++)
{
if(arr[i]<arr[j])
{
temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
}
}
}
for(i=0;i<len;i++)
{
printf("%d ",arr[i]);
printf("%p \n",&arr[i]);
}
}
int main()
{
int arr[] = {12,33,44,55,55};
int len;
len = sizeof(arr)/sizeof(arr[0]);
initxuanze(arr,len);
return 0;
}
上部分总结
初识C语言
变量 标识符
int float char double
printf()
//原样输出
//占位符输出
//可以多样输出
printf("");
scanf()
流程控制
顺序结构 选择结构 循环结构
顺序结构
数组
函数
5指针
1,初识指针
指针变量 存放地址的变量
#include<stdio.h>
int main()
{
int *p;
printf("");
return 0;
}
#include<stdio.h>
// 指针就是地址
// 指针变量就是用来 存放 地址的变量
// 定义一个指针变量 *标识的作用 产生在定义与声明的时候
// 使用指针变量 * 运算的作用
int main()
{
int a = 10;
int *p; //*是标识符 告诉系统我是 指针变量 用来保存 地址
p = &a; //p等于 取地址 a
printf("数据 %d \n",a);
printf("地址 %p \n",&a);
printf("数据 %d \n",*(&a)); //*是取值运算符,将内存地址的数据取出来。
printf("指针变量访问数据 %d \n",*p);
printf("指针变量 %d",sizeof(*p));
return 0;
}
指针变量的类型
不同的类型决定不同访问空间的大小int∗pdata;char∗pchar决定增量
不
同
的
类
型
决
定
不
同
访
问
空
间
的
大
小
�
�
�
∗
�
�
�
�
�
;
�
ℎ
�
�
∗
�
�
ℎ
�
�
决
定
增
量
#include<stdio.h>
int main()
{
int a = 0x1234;
int *p = &a;
char *c = &a;
printf("地址是%p 数据是%d\n",p,*p);
printf("地址是%p 数据是%d\n",c,*c);
printf("地址是%p 数据是%x\n",p,*p);
printf("地址是%p 数据是%x\n",c,*c);
printf("地址是%p 数据是%x\n",++p,*p);
printf("地址是%p 数据是%x\n",++c,*c);
return 0;
}
通过不同的类型 ++p 增量也会不同
访问变量 通过指针访问变量 通过变量名访问变量
警告,存在将int*类型的指针赋值给char*类型的指针的不兼容指针类型警告。
指针使用的场景
用函数封装两数交换的方法
#include<stdio.h>
//两个数交换
void jiaohuan(int *pdata1,int *pdata2)
{
int temp;
temp = *pdata1;
*pdata1 = *pdata2;
*pdata2 = temp;
printf("%d %d\n",*pdata1,*pdata2);
}
int main()
{
int data1;
int data2;
printf("交换前\n");
scanf("%d%d",&data1,&data2);//输入两个数
printf("%d %d\n",data1,data2);
jiaohuan(&data1,&data2);
printf("交换后\n");
printf("%d %d\n",data1,data2);
return 0;
}
指向指针的固定区域
错误
C语言中,整数常量的后缀用于指定整数的类型,但是FE55不是有效的后缀。
如果您想要将一个具体的地址赋值给指针变量,您需要使用合适的地址表示方法。
#include <stdio.h>
int main() {
int *p = (int *)0x61FE55; // 使用16进制表示地址
// 使用指针进行操作
*p = 10;
printf("%d\n", *p);
return 0;
}
#include<stdio.h>
int main()
{
int a = 11;
printf("0x%p \n",&a); //打印a的地址
int *p = (int *)0x000000000061FE55;
printf("0x%p \n",p); //打印上面的地址
}
#include<stdio.h>
int main()
{
int a = 11;
printf("0x%p \n",&a); //打印a的地址 volatile 防止系统优化
volatile unsigned int *p = (volatile unsigned int *)0x000000000061FE55;
printf("0x%p \n",p); //打印上面的地址
}
3,作业 封装 输入三个数
int∗p//定义指针变量inta;printf("
�
�
�
∗
�
/
/
定
义
指
针
变
量
�
�
�
�
;
�
�
�
�
�
�
(
"
#include<stdio.h>
//输入3个数 以大到小顺序输出
void changData(int *data1,int *data2,int *data3)
{
int a;
int b;
int c;
int temp;
printf("取值 %d %d %d\n",*data1,*data2,*data3);
printf("取值 %p %p %p\n",*data1,*data2,*data3);
printf("取地址 %p %p %p\n",&data1,&data2,&data3);
if(*data1<*data2)
{
temp = *data1;
*data1 = *data2;
*data2 = temp;
}
if(*data1<*data3)
{
temp = *data1;
*data1 = *data3;
*data3 = temp;
}
if(*data2<*data3)
{
temp = *data2;
*data2 = *data3;
*data3 = temp;
}
printf("取地址 %d %d %d\n",&data1,&data2,&data3);
printf("取值 %p %p %p\n",*data1,*data2,*data3);
printf("取地址 %p %p %p\n",&data1,&data2,&data3);
printf("%d %d %d\n",*data1,*data2,*data3);
}
int main()
{
int data1;
int data2;
int data3;
scanf("%d%d%d",&data1,&data2,&data3);
printf("原来的顺序\n");
printf("%d %d %d\n",data1,data2,data3);
printf("交换后\n");
changData(&data1,&data2,&data3);
printf("%d %d %d",data1,data2,data3);
return 0;
}
2 ,通过指针迎合数组
1,定义 指针变量指向数组
#include<stdio.h>
int main()
{
int arr[] = {1,3,2,43,2,55};
int *p;
int *q;
int len ;
int i;
len = sizeof(arr)/sizeof(arr[0]);
p = arr;
q = arr;
for(i =0;i<6;i++)
{
printf("%d ",*(p+i)); //指针的偏移 偏移程度取决于 类型
}
printf("第二元素是 %d\n",*(p+1));
printf("第一元素是 %d\n",*q);
return 0;
}
2,通过指针引用数组元素
1,下标法
2,指针法
1,指针偏移
指针偏移 就是 指针往前移 或者往后移
#include<stdio.h>
int main()
{
int arr[] = {1,3,2,43,2,55};
int *p;
int *q;
int len ;
int i;
len = sizeof(arr)/sizeof(arr[0]);
p = arr;
q = arr;
for(i =0;i<len;i++)
{
printf("%d ",*(p+i)); //指针的偏移 偏移程度取决于 类型
}
printf("\n");
p = arr; // 从新回到数组首地址 从新 遍历数组
for(i = 0;i<len;i++)
{
printf("%d ",*p++);
}
printf("\n");
p = arr;
for(i = 0;i<len;i++)
{
printf("%d ",*p);
p++;
}
printf("\n");
printf("第二元素是 %d\n",*(p+1));
printf("第一元素是 %d\n",*q);
return 0;
}
2,取内容
指针和数组名 的见怪不怪
指针当作数组名 下标法访问 朝花夕拾
#include<stdio.h>
int main()
{
int arr[5]= {11,3,23,4,5};
int *p = arr;
int i;
int len ;
len = sizeof(arr)/sizeof(arr[0]);
printf("%d \n",sizeof(arr));// 4 字节 x 5 = 20
printf("%d \n",len);
printf("%d \n",sizeof(int *)); //用8个字节表示一个地址
printf("%d \n",sizeof(char*));
printf("%d \n",sizeof(float*));
for(i = 0;i<len;i++)
{
printf("%d ",arr[i]);
}
putchar('\n');
for(i = 0;i<len;i++)
{
printf("%d ",*(p+i));
}
putchar('\n');
for(i = 0;i<len;i++)
{
//printf("%d ",*arr++); *p 是指针变量
// arr++ 是指针常量,编译不过。
printf("%d ",*(arr+i));
}
putchar('\n');
for(i = 0;i<len;i++)
{
printf("%d ",*(&arr[i]));
}
return 0;
}
3,两种方法 效率对比
函数与指针 与数组的结合
封装冒泡
#include<stdio.h>
//用指针封装 冒泡排序法
void initArr(int *arr,int len)
{
int i;
puts("初始化开始");
for(i = 0;i<len;i++)
{
scanf("%d",arr++);
}
puts("初始化结束");
}
void printArr(int *arr,int len)
{
int i;
for(i = 0;i<len;i++)
{
printf("%d ",*arr++);
}
}
void maopaoArr(int *arr,int len)
{
int i;//交换的轮数
int j;//每一轮交换的次数
int temp;//临时变量
for(i=0;i<len-1;i++)
{
for(j=0;j<len-i-1;j++)
{
if(*(arr+j)>*(arr+j+1))
{
//printf("aa ");
temp = *(arr+j);
*(arr+j) = *(arr+j+1);
*(arr+j+1) = temp;
}
}
}
}
int main()
{
int arr[5];
int len;
len = sizeof(arr)/sizeof(arr[0]);
puts("程序开始");
initArr(arr,len);
printArr(arr,len);
maopaoArr(arr,len);
printf("\n");
printArr(arr,len);
return 0;
}
封装选择
#include<stdio.h>
#define mian main
// 用指针封装选择排序
void initArr(int *arr,int len)
{
int i;
for(i=0;i<len;i++)
{
scanf("%d",arr++);
}
}
void printArr(int *arr,int len)
{
int i;
for(i=0;i<len;i++)
{
printf("%d ",*arr++);
}
}
void xuanze(int *arr,int len)
{
int i;
int j;
int temp;
for(i = 0;i<len-1;i++)
{
printf("bb\n");
for(j=i+1;j<len;j++)
{
printf("aa\n");
if(*(arr+j)>*(arr+i))
{
temp = *(arr+i);
*(arr+i) = *(arr+j);
*(arr+j) = temp;
}
}
}
}
int mian()
{
int arr[5];
int len ;
len = sizeof(arr)/sizeof(arr[0]);
initArr(arr,len);
printArr(arr,len);
xuanze(arr,len);
printf("\n");
printArr(arr,len);
return 0;
}
封装交换
#include<stdio.h>
// 数组 翻转
void initArr(int *arr ,int len)
{
int i;
for(i =0;i<len;i++)
{
scanf("%d",arr++);
}
}
void printArr(int *arr,int len)
{
int i;
for(i =0;i<len;i++)
{
printf("%d ",*arr++); //*取值 运算符(在这里是)
}
}
void fanzhuan(int *arr,int len)
{
int i;
int j;
int temp;
for(i = 0;i<len/2;i++)
{
j = len-1-i;
temp = *(arr+i);
*(arr+i) = *(arr+j);
*(arr+j) = temp;
}
}
int main()
{
int arr[5];
int len ;
len = sizeof(arr)/sizeof(arr[0]);
printf("%d \n",len);
initArr(arr,len);
printArr(arr,len);
printf("dome\n");
fanzhuan(arr,len);
printArr(arr,len);
return 0;
}
3,二维数组地址的认知
1,二维数组 第一维数组的每一个元素都是一个数组。
intarr[][];arr[0]+1;//第一个数组的第二个元素arr[0]//子数组的名字也是子数组的首地址
�
�
�
�
�
�
[
]
[
]
;
�
�
�
[
0
]
+
1
;
/
/
第
一
个
数
组
的
第
二
个
元
素
�
�
�
[
0
]
/
/
子
数
组
的
名
字
也
是
子
数
组
的
首
地
址
arr[0]+1;指针指向子数组的时向后偏移了一位指向了子数组首地址的后一位
�
�
�
[
0
]
+
1
;
指
针
指
向
子
数
组
的
时
向
后
偏
移
了
一
位
指
向
了
子
数
组
首
地
址
的
后
一
位
#include<stdio.h>
int main()
{
int arr[3][4]={{1,2,33,2},{33,11,44,55},{5,32,12,345}};
printf("父数组的地址是:%p 偏移%p\n",arr,arr+1); //父亲偏移了16
printf("子数组的地址是:%p 偏移%p\n",arr[0],arr[0]+1);//孩子偏移了4
printf("子数组的地址是:%p 偏移%p\n",*(arr+0),*(arr+0)+1);//孩子偏移了4
return 0;
}
二维数组 地址写法应用
int a[3][4];
a; //表示
a[0]+1;//第0行第1列 *(a+0)+1
a[1], *(a+1);
&a[1] a+1
a[2],*(a+2);
a[1]+2 ,*(a+1)+2, &a[1][2]; //取1 2 地址
*(a[1][2]) ,*(*(a+1)+2), *(&a[1][2] ) ,*(a[1]+2) ,a[1][2] //取1 , 2值
4,数组指针
1,初识数组指针
int (*p) 指针变量
*()取值运算符
int arr[3][4] = ;
int (*p)[4]; //定义一个数组指针
p = arr;
能不能定义一个指针,指针偏移的时候 也偏移对应的数组 // 数组指针 定义一个指针 指向数组 // 数组指针才是真正等同于 二维数组的名字
#include<stdio.h>
int main()
{
int arr[3][4]={{1,3,34,2},{21,34,5,54},{21,5,54,22}};
int i;
int j;
for(i = 0;i<3;i++)
{
for(j = 0;j<4;j++)
{
printf("%d ",arr[i][j]);
}
printf("\n");
}
putchar('\n');
for(i = 0;i<3;i++)
{
for(j = 0;j<4;j++)
{
printf("%d ",*(*(arr+i)+j));
}
printf("\n");
}
putchar('\n');
// 能不能定义一个指针,指针偏移的时候 也偏移对应的数组
// 数组指针 定义一个指针 指向数组
// 数组指针才是真正等同于 二维数组的名字
int (*p1)[4]; //数组指针定义方式
p1 = arr;
for(i = 0;i<3;i++)
{
for(j = 0;j<4;j++)
{
printf("%d ",*(*(p1+i)+j));
}
printf("\n");
}
return 0;
}
2,数组指针和二维数组的配合
#include<stdio.h>
// 用户输入行列的值 然后输出 行列对应的数字
void initscanfhanglie(int *hang,int *lie )
{
puts("请输入行和列");
scanf("%d%d",hang,lie);
puts("输入完成");
}
int getdata(int (*p)[4],int hang,int lie)
{
int data;
data = *(*(p+hang)+lie);
return data;
}
int main()
{
int arr[3][4] = {{11,3,4,2},{33,55,66,22},{334,65,7,90}};
//用户 行列数
int hang,lie;
int data;
initscanfhanglie(&hang,&lie);
//获取 行列 对应的数字
data = getdata(arr,hang,lie);
printf("%d %d %d",hang,lie,data);
return 0;
}
5,函数指针
1,定义函数指针
函数名就是地址 数组名也是地址
在程序中定义一个函数,编译系统为函数代码分配存储空间,,这段存储空间的起始地址
(入口地址)就是这个函数的指针。
2,定义函数指针变量
int a;
int *p;
char c;
char *p;
int (*p)(int a,int b); ///定义函数指针
int *p(int a,int b);
函数指针 的好用的地方
根据程序运行过程的不同情况,调用不同的函数
练习题 输入a b 根据 1,2,3模式 1,求最大值 2,求最小值 3,求和
#include<stdio.h>
#include<stdlib.h>
//输入 两个数 有3个模式 1最大值 2最小值 3求和
int getMax(int data1,int data2)
{
int max;
max = data1>data2?data1:data2;
return max;
}
int getMin(int data1,int data2)
{
int min;
min = data1<data2?data1:data2;
return min;
}
int getSum(int data1,int data2)
{
int sum;
sum = data1+data2;
return sum;
}
int getmode(int data1,int data2, int (*pfunc)(int,int))
{
int ret ;
ret = pfunc(data1,data2);
return ret;
}
int main()
{
int a;
int b;
int ret;
printf("请输入两个数\n");
scanf("%d%d",&a,&b);
putchar('\n');
printf("请输入对应的模式 1 最大值,2最小值,3求和\n");
int cmd;
int (*pfunc)(int,int);
scanf("%d",&cmd);
switch(cmd)
{
case 1:
pfunc =getMax;
break;
case 2:
pfunc = getMin;
break;
case 3:
pfunc =getSum;
break;
default:
printf("错误\n");
exit(-1);
break;
}
ret = getmode(a,b,pfunc);
printf("输入的两个数为%d %d \n %d结果为%d",a,b,cmd,ret);
return 0;
}
回调函数
指针数组
一个数组中的元素 均为指针类型的数据 成为指针数组。
指针数组中每一个 元素存放一个地址,相当于一个指针变量
int (*p)[2]; //这个是指向一推数组的指针变量
int a;
int b;
int c;
int d;
int *p[3] = {&a,&b,&c}; //指针数组
int *p[2][3];
3,使用函数指针
1,函数调用概念和变量一样
直接访问(变量名,函数名)
间接访问 (指针 函数指针)
4,指针数组 和数组指针的区别
数组指针(pointer to an array):
数组指针指的是一个指针,它指向一个数组的内存块。
数组指针的声明包括指针名和所指向数组的元素类型,但不包括数组大小。
通过解引用数组指针加上索引来访问数组中的元素。
示例代码
int (*arr)[10];//声明一个指针,指向一个具有10个元素的数组
int arr[10]; //数组
int (*ptr)[10]; // 声明一个指针,指向包含10个整数元素的数组
int arr[10]; // 声明一个包含10个整数元素的数组
ptr = &arr; // 将数组的地址赋值给指针
(*ptr)[0] = 5; // 通过指针访问数组元素,并赋值
指针数组(array of pointers):
指针数组是一个数组,在数组中的每个元素都是指针,指向不同的内存块。
指针数组的声明包括指针数组的名字和每个指针所指向的数据类型。
指针数组的每个元素都可以指向不同类型的数据(指针类型除外)。
示例代码:
int *arr[5]; // 声明一个包含5个指针元素的指针数组
int num1 = 5, num2 = 10, num3 = 15;
arr[0] = &num1; // 指针数组的第一个元素指向 num1
arr[1] = &num2; // 指针数组的第二个元素指向 num2
arr[2] = &num3; // 指针数组的第三个元素指向 num3
*arr[0] = 7; // 通过指针数组访问并修改所指向的数据
数组指针指向一个数组的内存块,而指针数组是一个包含指针的数组。
数组指针的声明形式为 elementType (*ptr)[size],而指针数组的声明形式为 elementType *arr[size]。
数组指针可以通过解引用和索引操作访问数组元素,指针数组可以通过索引操作访问每个指针所指向的对象。
数组指针和指针数组的应用场景和使用方式有所不同,具体取决于程序的需求。
5,指针函数
指针函数 就是 返回值 是指针变量的函数
int *a(int a,int b)
{
int *p;
p = &a;
return p;
}
#include<stdio.h>
int *getPosPerson(int pos,int (*arr)[4])
{
int *p;
p = (int *)arr+pos;
return p;
}
int main()
{
int arr[3][4] = {
{11,33,54,43},
{80 ,94,76,98},
{79,80,76,45},
};
int pos;
int *ppos;
printf("请输入学生的学号0 1 2\n");
scanf("%d",&pos);
ppos = getPosPerson(pos,arr);
for(int i = 0;i<4;i++)
{
printf("%d ",*ppos++);
}
return 0;
}
6,二级指针
#include<stdio.h>
int main()
{
int data1 = 100;
int *p;
p = &data;
printf("%p ",p);
int **p2;
p2 =&p;
printf(" p的地址是%p ",p2);
return 0;
}
#include<stdio.h>
int main()
{
int data = 100;
int *p = &data; //P保存的是data的地址;
printf("data的地址是%p \n",p);
int**p2=&p;
p2 =&p;
int a = (int )**p2;
printf("pp2 保存的是 p的地址 %p \n",p2);
printf("*p2 是%p \n",*p2);
printf("**p2 是%p ,",**p2);
return 0;
}
1,野指针
定义一个 指针变量 如果 我们没有给这个指针变量 要保存的地址 那这个指针变量 就是一个野指针。系统会随机为这个指针变量分配保存的地址。
int *p; //p后面没有要保存的地址,所以这个指针变量就是野指针
6,字符串
1,字符串就是字符数组
1,定义的几种格式
#include<stdio.h>
int main()
{
int *char = "holle word";
}
#include<stdio.h>
int main()
{
//比较蠢的方式
char arr[]={'f','e','e','r','w','e','r','f','s'};
//比较人性的方式
char arr1[]="hello";
//比较常用的方式
char *arr2 = "困困";
int len =sizeof(arr)/sizeof(arr[0]);
int i;
for(i=0;i<len;i++)
{
printf("%c",arr[i]);
}
putchar('\n');
printf("%s\n",arr1);
printf("%s\n",arr2);
return 0;
}
#include<stdio.h>
#include<string.h>
int main()
{
int a;
int data1[] = {1,2,3,4,5};
char cdata[] = {'h','o','l','l','e'};
char cdata1[] = "holle";
a = len (data1);
printf("%d ",a);
return 0;
}
2,和整型数组在存储上的区别
字符串多了一个 ‘ \0’ 长度多了一个字节
#include<stdio.h>
int main()
{
//字符串和 字符数组的区别
//字符串存储 比字符数组多了‘\0’结束标志
int data1[] = {1,2,3,4,5};
char data2[] = {'f','e','e','r','t','h','e','n','\0'};
char data3[] = "feerthen";
char *data4 = "feerthen";
int len;
int len1;
int len2;
int len3;
len = sizeof(data1)/sizeof(data1[0]);
len1 = sizeof(data2)/sizeof(data2[0]);
len2 = sizeof(data3)/sizeof(data3[0]);//字符串多了一个'\0'结束标志
len3 = sizeof(data4)/sizeof(data4);
printf("%d \n",len);
printf("%d \n",len1);
printf("%d \n",len2);
printf("%d \n",len3);
return 0;
}
3,sizeof和strlen的区别
sizeof() 计算字符串所有的元素(包括''\0')
strlen() 只计算有效部分
#include<stdio.h>
#include<string.h>
int main()
{
char data[] = "hello";
printf("data sizeof :%d\n",sizeof(data));
printf("data strlen :%d\n",strlen(data));
return 0;
}
4,动态开辟字符串
1,malloc 动态开辟内存空间
free(p); //把前面malloc申请的空间释放掉。防止内存泄露,防止悬挂指针。
realloc(p,newlen); //realloc 是在 malloc分配地址不够的情况下 进行扩容地址
memset(p,'\0',12); //把p里面的12 个字节全部初始化成 ‘\0’
p = (char*)malloc(12); //动态开辟12个字节
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
char *p; //野指针
p = (char *)malloc(1);// p有了具体的内存指向
*p = 'c';
free(p); //把前面malloc申请的空间释放掉。防止内存泄露,防止悬挂指针。
printf("p的字符是%c\n",*p);
printf("%p\n",p);
p = (char*)malloc(12); //动态开辟12个字节
printf("扩容前的地址%x\n",p);
int len = strlen("jfiopeqqp12345321421421414126678");
int newlen = len-2+1;
realloc(p,newlen); //realloc 是在 malloc分配地址不够的情况下 进行扩容地址
memset(p,'\0',12); //把p里面的12 个字节全部初始化成\0
printf("扩容后的地址%x\n",p);
p = strcpy(p,"jfiopeqqp12345321421421414126678");
puts(p);
//printf("%s",p);
return 0;
}
5,几种字符串常用的API
strcpy()
char* copy(char*p,char*str)
{
if(p == NULL||str == NULL)
return NULL;
char* ber;
ber =p;
while(*str != '\0')
{
*p = *str;
p++; //指针偏移
str++;
}
*p = '\0';//循环结束时+一个'\0'结束标志
return ber;
}
char* copy1(char* p,char*str)
{
if(p == NULL||str == NULL)
return NULL;
char* ber;
ber =p;
while(*str != '\0')
*p++ = *str++;
*p = '\0';//循环结束时+一个'\0'结束标志
return ber;
}
char* copy2(char* p,char*str)
{
if(p == NULL||str == NULL)
return NULL;
char* ber;
ber =p;
while((*p++=*str++) != '\0');
*p = '\0';//循环结束时+一个'\0'结束标志
return ber;
}
strncopy()
这种方式有点bug
char* ncopy(char*p,char*str,int count)
{
if(p == NULL||str == NULL)
return NULL;
char* ber;
ber =p;
while(*str != '\0',count>0)
{
*p = *str;
p++; //指针偏移
str++;
count--;
}
//当我们字节的值大于所需要拷贝内容的字节时,用这个
if(count >0)
{
while(count>0)
{
count--;
*p++ = '\0';
}
return ber;
}
*p = '\0';//循环结束时+一个'\0'结束标志
return ber;
}
这种方式考虑就很全了
当 count 大于要复制的内容时,后面的字节我不知道有什么东西,有可能会产生不可估量的影响,所以要对后面剩余的字节进行填充。
当 count 小于复制内容时,会出现越界,所以我们要当count等于0时 给一个结束标志。
char* ncopy1(char*p,char*str,int count)
{
if(p == NULL||str == NULL)
return NULL;
char* ber = p;
while(count && (*p++ = *str++))
count--;
if(count)
while(--count)
*p++='\0';
return ber;
}
dst :destination的缩写 src:source的缩写 strcpy : string copy
char* strcpy(char*dst, const char *src)
{
if ((dst == NULL) || (src == NULL))
return NULL;
char *ret = dst; //[1]
while ((*dst ++= *src++) != '\0'); //[2]
return ret; //[3]
}
const :防止在赋值的给dst的时候发生改变;
ret :return ,返回的是dst的首地址。
while ((*dst ++= *src++) != ‘\0’); 当 *src =‘\0’ 的时候为false while()结束。
*dst ++= src++的时序问题 首先:dst= *src 然后:dst++和src++顺序不定,不同的编译器可能顺序不同 ———————————————— 版权声明:本文为CSDN博主「七 六 伍」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:阅读源码之——strcpy()函数源码解读(学习)_strcpy函数源码_七 六 伍的博客-CSDN博客
assert() 断言函数
assert() 他是一个宏 他的作用就是用来 测试 程序是否有问题 偶尔用几下
如果用完可以用 #define NDEBUG 让assert()失效
**所在头文件:<assert.h>*
*函数原型:void assert (int expression);*
*参数:expression即要检测的表达式*
*返回值:无返回值*
“断言”在语文中的意思是“断定”、“十分肯定地说”,在编程中是指对某种假设条件进行检测,如果条件成立就不进行任何操作,如果条件不成立就捕捉到这种错误,并打印出错误信息,终止程序执行。
assert() 会对表达式expression进行检测:
如果expression的结果为 0(条件不成立),那么断言失败,表明程序出错,assert() 会向标准输出设备(一般是显示器)打印一条错误信息,并调用 abort() 函数终止程序的执行。
如果expression的结果为非 0(条件成立),那么断言成功,表明程序正确,assert() 不进行任何操作。
———————————————— 版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:assert断言函数简介_assert函数_桦秋静的博客-CSDN博客
assert(expression) 使用方法
#include<stdio.h>
#include<assert.h>
int main()
{
int a;
int b;
scanf("%d%d",&a,&b);
float c = (float)a/b;
assert(b!=0); //当b=0的时候 表示断言失败 其会 想设备打印一条信息,
//而后通过abort()函数终止程序运行
printf("%2.2f",c);
return 0;
}
assert() 检测的时候 表达式写简单点, 一般是一个assert()检测一个表达式 。如果一个assert()检测多个表达式,就不知道是哪个表达式有问题,无法正确排除错误。
assert(expression1);
assert(expression2);
assert() 不用会改变环境的语句 作为断言的 表达式
#include<stdio.h>
#include<assert.h>
int main()
{
int a;
int i;
while(i<=100)
{
++i;
assert(++i<100); //当i 到100的时候终止运行了
printf("aaaa%d\n",i);
}
return 0;
}
在 Debug 模式下运行,程序循环到第 101 次时,i 的值为 100,++i <= 100不再成立,断言失败,程序终止运行。
而在 Release 模式下运行,编译参数中设置了 NDEBUG 宏(如果编译器没有默认设置,那么需要你自己来设置),assert() 会失效,++i <= 100这个表达式也不起作用了,while() 无法终止,成为一个死循环。
定义了 NDEBUG 宏后,assert(++i <= 100)会被替换为((void)0)。
导致程序在 Debug 模式和 Release 模式下的运行结果大相径庭的罪魁祸首就是++运算,我们本来希望它改变 i 的值,逐渐达到 while 的终止条件,但是在 Release 模式下它失效了。
———————————————— 版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:assert断言函数简介_assert函数_桦秋静的博客-CSDN博客
修改后的代码
把 ,++i 移出来
#include<stdio.h>
#include<assert.h>
int main()
{
int a;
int i;
while(i<=100)
{
++i;
assert(100); //当i 到100的时候终止运行了
printf("aaaa%d\n",i);
}
return 0;
}
字符串拼接 strcat() 实现
字符拼接 strcat( str, ber ) 可以将 ber 的字符串 拼接到 str 的尾部
1,调用方式
#include<stdio.h>
#include<string.h>
int main()
{
char str[120] = "我们shi_ikun";
char*p = "苍天已死,黄天当立";
strcat(str,p);
puts(str);
return 0;
}
效果
2,自己写strcat()拼接函数
char* Mystrcat(char* dst,const char* src)
{
char* der = dst;
while(*dst)
dst++;
while((*dst++=*src++)!='\0');
return der;
}
char* Mystrcat1(char* dst,const char* src)
{
assert(dst !=NULL ); //断言 如果=NULL就报错
assert(src !=NULL);
char* der = dst;
while(*dst!='\0')
*dst++;
while(*src!='\0')
*dst++=*src++;
return der;
}
#include<stdio.h>
#include<assert.h>
char* Mystrcat(char* dst,const char* src)
{
char* der = dst;
while(*dst)
dst++;
while((*dst++=*src++)!='\0');
return der;
}
char* Mystrcat1(char* dst,const char* src)
{
assert(dst !=NULL ); //断言 如果=NULL就报错
assert(src !=NULL);
char* der = dst;
while(*dst!='\0')
*dst++;
while(*src!='\0')
*dst++=*src++;
return der;
}
char* strcopy(char* dst,char* src)
{
assert(dst !=NULL ); //断言 如果=NULL就报错
assert(src !=NULL);
char*der = dst;
while((*dst++ = *src++)!='\0');
*dst ='\0';
return der;
}
int main()
{
char c[123] = "苍天已死,黄天当立" ;
char* p = " 岁在甲子,天下大吉";
char*a =Mystrcat1(c,p);
puts(a);
return 0;
}
字符比较strcmp()的使用与实现
int strcmp(const char* s1,const char* s2);
//若s1 = s2 返回0 s1<s2 返回负数 ;s1>s2 返回正数;
// 比的是 ASII码值
int strncmp(const char* s1, const char* s2, size_t n);
//功能是将s1与s2进行比较,最多比较 前n个字节
//若s1=s2 (字符串)返回0;
//若S1>S2 (字符串) 返回 >0的数;
//若s1<s2 (字符串)返回<0 的数
调用 strcmp()
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char* a1 = "iz";
char* a2 = "ik";
int ret = strcmp(a1,a2);
printf("ret = %d",ret);
return 0;
}
自己手写 strcmp()比较函数
int cdeclstrcmp (const char * src, const char * dst)
{
int ret = 0 ;
while( !(ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
++src, ++dst;
if ( ret < 0 )
ret = -1 ;
else if ( ret > 0 )
ret = 1 ;
return( ret );
}
我们要看的是while循环这个语句, ! (ret = (unsigned char )src - (unsigned char )dst)意思是拿指针变量src所指向的字符值(即src)减去指针变量dst所指向的字符值(即dst),差值赋给ret,再取非运算,最后与dst进行与运算; 拿abc例,第一次因为a=a,则执行++src,++dst;2次自加后,ret值为负,跳出while语句,执行if语句的判断,输出为-1; 这里要注意的是: 1.unsigned char是强制转换类型。 2.若src和dst都为空串,返回值是多少呢?因为空串不是指地址为空,还是有地址的,这样就很明确了。
#include<stdio.h>
//字符比较函数
int Mystrcmp(const char* s1,const char* s2)
{
int der = 0;
int str1 = 0;
int str2 = 0;
char* backstr1 = s1;
char* backstr2 = s2;
while(*s1 && *s2 && (*s1==*s2))
{
s1++;
s2++;
}
if(*s1||*s2)
{
s1 = backstr1;
s2 = backstr2;
while(*s1)
{
str1+=*s1;
s1++;
}
while(*s2)
{
str2+=*s2;
s2++;
}
}
der = backstr1 - backstr2;
if(der<0)
{
der = -1;
}
if(der >0)
{
der =1;
}
return der;
}
int cdeclstrcmp (const char * src, const char * dst)
{
int ret = 0 ;
while( !(ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
++src, ++dst;
if ( ret < 0 )
ret = -1 ;
else if ( ret > 0 )
ret = 1 ;
return( ret );
}
int main()
{
char* a = "ikun";
char* b = "icao";
int a1;
int a2;
a2 = cdeclstrcmp(a,b);
a1 = Mystrcmp(a,b);
printf("%d",a2);
}
7,结构体 struct
1,结构体的定义 struct
结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构。
通俗的来说其实就是,开辟一个新的变量来存储这个变量的不同属性,比如,学生成绩,它有语数外三科成绩,因为这三科成绩属 于同一个人。**
结构体可以说是 C语言面向对象的工具
#include<stdio.h>
#include<string.h>
struct Student
{
int num;
int age;
char sex;
char name[32];
double score;
char addr[32];
};
int main()
{
struct Student stu1;
stu1.num = 1;
stu1.age = 14;
stu1.sex = 'w';
strcpy(stu1.name,"蔡徐坤");
stu1.score = 98.3;
strcpy(stu1.addr,"贵阳");
printf("学号:%d\n",stu1.num);
printf("年龄:%d\n",stu1.age);
printf("性别:%c\n",stu1.sex);
printf("名字:%s\n",stu1.name);
printf("分数:%2.2lf\n",stu1.score);
printf("地址:%s\n",stu1.addr);
return 0;
}
2,结构体和数组
结构体数组 是指 一个数组里面 的 每一个元素 都是一个结构体。每一个元素都 包含了 这个结构体里面所定义的所有属性。
访问结构体其内部定义的属性时有两种访问方式,一种是通过变量名,一种是通过结构体指针
变量名 struct Student s.num。通过 . 来访问 结构体内部属性
结构体指针 p->num 通过 -> 来访问 结构体内部的属性
结构体 里面 存放的数据 的地址是连续的,结构体里存放的每一个 数据 地址都是独立的
结构体 所占内存空间大小 = 结构体里面所有 数据 字节之和。
printf("age: %d name: %s\n",kun.age,kun.name);//以变量名直接访问结构体里面不同类型的变量。用"."
printf("age: %d name: %s",ps->age,ps->name);//通过结构体指针直接访问结构体内部数据。用"->"
结构体数组的运用
#include<stdio.h>
struct Student
{
int num;
char name[32];
int age;
char sex;
double score;
char addr[32];
};
int main()
{
int arr[3] = {1,3,2};
int len ;
int i;
struct Student arr2[3] = {
{1,"蔡徐坤",18,'w',98.5,"贵阳"},
{2,"李素",21,'m',92.2,"六盘水"},
{3,"徐坤",73,'m',100,"北京"}
};
len = sizeof(arr2)/sizeof(arr2[0]);
for(i = 0;i<len;i++)
{
printf("学号:%d 姓名:%s 年龄:%d 性别:%c 分数:%-2.2lf 地址:%s\n",
arr2[i].num,arr2[i].name,arr2[i].age,arr2[i].sex,arr2[i].score,arr2[i].addr);
}
return 0;
}
选票系统
此过程分为 初始化候选人,唱票环节, 打印选票数据,输出最终的选票结果。
#include<stdio.h>
#include<string.h>
struct Xuanmin
{
char name[32];
int tickets;
};
int main()
{
struct Xuanmin ikun[3];
struct Xuanmin max;
int feipiao;
int i,j;
int len ;
int ticketer = 5;
char tmpName[32];
int mak;
len = sizeof(ikun)/sizeof(ikun[0]);
//初始化,环节
for(i = 0;i<len;i++){
ikun[i].tickets = 0;
printf("请输入第%d候选人的名字\n",i+1);
scanf("%s",&ikun[i].name);
}
//唱跳环节
for(i = 0;i<5;i++)
{
mak = 0;
printf("请输入您投票人的名字\n");
memset(tmpName,'\0',sizeof(tmpName));
scanf("%s",&tmpName);
for(j = 0;j<len;j++)
{
if(strcmp(tmpName,ikun[j].name)==0)
{
ikun[j].tickets++;
mak = 1;
}
}
if(mak ==0){
printf("没有此候选人 \n");
feipiao++;
}
}
for(i = 0;i<len;i++)
{
printf("名字:%s 票数:%d\n",ikun[i].name,ikun[i].tickets);
}
max = ikun[0];
for(i=0;i<len;i++){
if(max.tickets<ikun[i].tickets)
{
max = ikun[i];
}
}
printf("%s以%d票当选,废票有%d\n",max.name,max.tickets,feipiao);
return 0;
}
用typedef 关键字 和结构体运用
#include<stdio.h>
#include<string.h>
typedef struct
{
int ticker;
char name[32];
}Expectant;
案例
#include<stdio.h>
#include<string.h>
typedef struct
{
int ticker;
char name[32];
}Expectant;
int main()
{
Expectant arr[3];
Expectant *parr;
Expectant max;
int i,j;
int take = 5;
char tmpName;
int make;
int feipiao = 0;
int len = sizeof(arr)/sizeof(arr[0]);
for(i = 0;i<len;i++)
{
printf("请输入第%d个候选人姓名: ",i+1);
arr[i].ticker = 0;
scanf("%s",&arr[i].name);
}
for(i = 0;i<take;i++)
{
make = 0;
printf("请输入您选举候选人的名字\n");
memset(&tmpName,'\0',sizeof(tmpName));
scanf("%s",&tmpName);
for(j = 0;j<take;j++){
if(strcmp(&tmpName,arr[j].name)==0)
{
arr[j].ticker++;
make = 1;
}
}
if(make == 0)
{
printf("没有此候选人\n");
feipiao++;
}
getchar();
}
for(i=0;i<len;i++)
{
printf("候选人姓名:%s 票数:%d 废票有:%d\n ",arr[i].name,arr[i].ticker,feipiao);
}
max = arr[0];
for(i = 0;i<len;i++)
{
if(max.ticker<arr[i].ticker)
{
max = arr[i];
}
}
printf("恭喜 %s以 %d 票当选省委书记!!!!!!!!\n",max.name,max.ticker);
return 0;
}
1,结构体指针
1,用变量访问 结构体里面的 属性 就要用 ‘.’
2,用指针间接访问 结构体里面的属性 用‘->’
#include<stdio.h>
#include<string.h>
typedef struct
{
int ticker;
char name[32];
}Expactant;
int main()
{
Expactant arr[3];
Expactant *parr;
Expactant max;
parr = arr;
//Expactant max;
int i,j;
int len ;
char tempname[32];
int take=5;
int make = 0;
len = sizeof(arr)/sizeof(arr[0]);
//初始化arr
for(i=0;i<len;i++)
{
parr->ticker =0;
printf("第%d号候选人姓名:\n",i+1);
scanf("%s",parr->name);
parr++;
}
//唱票环节
parr = arr;
make = 0;
for(i=0;i<take;i++)
{
printf("请输入您选择的候选人\n");
memset(tempname,'\0',sizeof(tempname));
scanf("%s",&tempname);
parr = arr;
for(j = 0;j<len;j++){
if(strcmp(tempname,parr->name)==0)
{
parr->ticker++;
make = 1;
}parr++;
}
if(make == 0)
{
printf("没有候选人\n");
}
}
parr=arr;
for(i=0;i<len;i++)
{
printf("候选人名字:%s 候选人票数%d\n",parr->name,parr->ticker);
parr++;
}
//指针++每次都会遍历到数组尾巴,下次遍历要记得从新 把指针指向数组首地址
max = arr[0];
parr = arr;
for(i = 0;i<len;i++)
{
if(max.ticker<parr->ticker)
max.ticker = arr[i].ticker;
parr++;
}
printf("恭喜%s 以%d 的票数当选省委书记!!!!!!!\n",max.name,max.ticker);
return 0;
}
2,结构体指针,数组,函数结合
所需要的头文件
以及结构体
#include<stdio.h>
#include<string.h>
#include <stdlib.h>
typedef struct
{
int ticker;
char name[32];
}Expactant;
结构体指针 函数 初始化 候选人
Expactant *initXm(Expactant*p,int *pn)
{
int i;
int tmpename;
if(p == NULL){
printf("请输入参与竞选的人数\n");
scanf("%d",pn);
p = (Expactant*)malloc(*pn*sizeof(Expactant));
}
for(i = 0;i<*pn;i++)
{
p->ticker = 0;
printf("请输入第%d个选民的名字:\n",i+1);
scanf("%s",p->name);
p++;
}
return p-*pn;
}
唱票环节
int getWot(Expactant *p,int len )
{
Expactant *pbak = p;
int i,j;
int feip = 0;
char tempname[32];
//int take=5;
int make = 0;
make = 0;
p->ticker = 0;
for(i=0;i<len;i++)
{
printf("请输入您选择的候选人\n");
memset(tempname,'\0',sizeof(tempname));
scanf("%s",&tempname);
p = pbak; //把pbak给到p让p回到 首地址
for(j = 0;j<len;j++){
if(strcmp(tempname,p->name)==0)
{
p->ticker++;
make = 1;
}
p++;
}
if(make == 0)
{
printf("没有候选人\n");
feip++;
}
}
return feip;
}
输出函数
void printXm(Expactant*p,int pn)
{
int i;
for(i=0;i<pn;i++)
{
printf("名字:%s,票数:%d\n",p->name,p->ticker);
p++;
}
}
主函数
int main()
{
int feip;
Expactant *XM = NULL;
int len = 0;
XM = initXm(XM,&len);
printXm(XM,len);
//getWot(XM,len );
feip = getWot(XM,len);
printf("废票有%d\n",feip);
printXm(XM,len);
return 0;
}
4,联合体/共用体基本概念
**联合体 union {}** 联合体就是共用体,联合体是多种数据类型 共同使用一个空间,也就是说,共用体里面的数据类型不管有多少种,多少个,他们的**地址**是一样的。共用体最大地址是由 共用体里面 最大的数据类型决定的。共用体里面 哪个数据类型所占的字节最大 就确定 这个共用体占了多少个字节。例如:如果最大数据类型是 double 一个double 八个字节 就说明这个共用体就有八个字节的内存空间。
共用体的基本用法
union St{
int num;
int age;
char[32] name;
};
int main()
{
union St s1;
s1.num = 1; //为共用体 num属性赋值
printf("%d ",s1.num);
return 0;
}
#include<stdio.h>
struct TestT
{
int idata;
char cdata;
double ddata;
};
union TestU
{
int idata;
char cdata;
double ddata;
};
int main()
{
struct TestT t1 = {1,'a',9.2};
union TestU u1;
u1.idata = 2;
u1.cdata = 'c';
u1.ddata = 89.2;
//union TestU u2;
//u2.cdata = 'd';
//union TestU u3;
//u3.ddata = 2.3;
printf("t1 idata = %d\n",t1.idata);
printf("t1 cdata = %c\n",t1.cdata);
printf("t1 cdata = %2.2lf\n",t1.ddata);
printf("t2 cdata = %d\n",u1.idata);
printf("t2 cdata = %p\n",&u1.idata);
printf("t2 cdata = %c\n",u1.cdata);
printf("t2 cdata = %p\n",&u1.cdata);
printf("t2 cdata = %2.2lf\n",u1.ddata);
printf("t2 cdata = %p\n",&u1.ddata);
return 0;
}
2,联合体的作用
联合体(union)是C语言中的一种特殊数据类型,它允许在同一内存位置存储不同类型的成员变量。联合体的大小等于其最大成员的大小。
联合体的主要作用是节省内存空间。通过使用联合体,可以在相同的内存位置上存储不同类型的数据,从而避免为每种类型分配独立的内存空间。
除了节省内存外,联合体还可以用于以下几个方面:
存储不同类型的数据:联合体允许在不同时间存储不同类型的数据。你可以根据需要在联合体中使用一个成员,而其他成员则被忽略。
数据类型的转换:联合体可以用于进行类型转换。通过在不同类型的成员之间进行赋值,可以将数据从一种类型转换为另一种类型。
给成员起别名:联合体可以为不同的成员变量提供相同的内存位置,这样可以为这些成员变量起不同的别名,方便访问。
需要注意的是,联合体在同时存储不同类型的数据时,只能使用一个成员来访问数据,而其他成员的值会被覆盖。因此,在使用联合体时要确保正确地访问和操作成员变量,以避免出现意外的结果。
共用体的应用
#include<stdio.h>
struct St
{
char name[32] ;
int age;
char sex;
char zhiye;
union {
int class;
char kemu[32];
}mes;
};
int main()
{
int i;
int len;
struct St arr[3];
len = sizeof(arr)/sizeof(arr[0]);
fleg:
for(i=0;i<3;i++)
{
printf("请输入您的职业。\n[s]:学生,[t]:老师\n");
scanf("%c",&(arr[i].zhiye));
//if(arr[i].zhiye !='s'||arr[i].zhiye!='t'){
//goto fleg;
//printf("输入错误,请从新输入\n");
// }
if(arr[i].zhiye =='s')
{
printf("请输入班级\n");
scanf("%d",&(arr[i].mes.class));
printf("请输入您的名字\n");
scanf("%s",&(arr[i].name));
}
if(arr[i].zhiye == 't')
{
printf("请输入您授课的科目\n");
scanf("%s",&(arr[i].mes.kemu));
printf("请输入您的名字\n");
scanf("%s",&(arr[i].name));
}
getchar();
if(arr[i].zhiye!='s' && arr[i].zhiye!= 't')
{
printf("输入错误,请从新输入\n");
goto fleg;
}
//getchar();
}
for(i = 0;i<3;i++)
{
if(arr[i].zhiye =='s')
printf("学生姓名:%s 班级;%d\n",arr[i].name,arr[i].mes.class);
if(arr[i].zhiye == 't')
printf("教师姓名:%s 科目:%s\n",arr[i].name,arr[i].mes.kemu);
}
return 0;
}
3,枚举类型enum
如果一个变量只有几种可能的值,比如星期几 son mon tus wed thu fri sat
在C语言中,枚举类型(enumeration)用于定义一组具有命名值的常量。枚举类型允许用一个易记的名字来表示一组相关的常量,增强了代码的可读性和可维护性。
枚举类型的定义格式如下:
enum 枚举类型名 {
枚举常量1,
枚举常量2,
...
};
其中,枚举类型名 是你为枚举类型起的名字,可以根据需要自定义。
在枚举类型的定义中,你可以列出多个枚举常量,每个枚举常量用逗号分隔。枚举常量通常是大写字母命名,以表示它们是常量。
以下是一个示例,展示如何定义一个表示颜色的枚举类型:
#include <stdio.h>
enum Color {
RED,
GREEN,
BLUE
};
int main() {
enum Color color1;
enum Color color2;
color1 = RED;
color2 = BLUE;
printf("Color1: %d\n", color1);
printf("Color2: %d\n", color2);
return 0;
}
在上述示例中,我们定义了一个名为 Color 的枚举类型,包含了三个枚举常量 RED、GREEN 和 BLUE。然后,在 main 函数中声明了两个枚举类型的变量,并将其中的一个变量赋值为 RED,另一个为 BLUE。最后,通过 %d 格式说明符将枚举常量打印为整数值。
输出结果为:
Color1: 0
Color2: 2
每个枚举常量都会被赋予一个默认的整数值,从0开始递增。在上面的示例中,RED 被赋值为0,GREEN 没有直接赋值,默认为1,BLUE 被赋值为2。
你也可以在定义枚举时为每个枚举常量指定特定的值,如:
enum Month {
JAN = 1,
FEB = 2,
MAR = 3,
...
};
这样,JAN 的值为1,FEB 的值为2,以此类推。
定义一个 enum类型
enum WeekDay {xinqi1,xinqi2,xinqi3,xinqi4,xinqi5,xinqi6,xinqi7};
// 默认情况下第一个元素是0
可以忽略枚举类型名 直接定义枚举变量,枚举类型里面的元素 名字不能重复
enum {w,e,q,r,s}w1,w2;
4,typedef关键字介绍
给已有的变量取名字,配合 结构体 使用 可以不用写struct 开头
1,typedef 定义作用
在C语言中,typedef 关键字用于为已有的数据类型起一个新的名字。它提供了一种简化和增强代码可读性的方式,使数据类型的定义更加清晰和易于理解。
typedef 的定义格式如下:
typedef 旧类型名 新类型名;
通过使用 typedef,你可以为已有的数据类型起一个新的别名。这个别名就可以像原始类型一样使用,但是它的名称更具有描述性,更方便理解。
以下是一些 typedef 的使用示例:
#include <stdio.h>
typedef int 整数; // 为 int 类型定义别名为 整数
typedef float 小数; // 为 float 类型定义别名为 小数
typedef struct {
int 年;
int 月;
int 日;
} 日期; // 为结构体类型定义别名为 日期
int main() {
整数 a = 10;
小数 b = 3.14;
日期 d = {2023, 8, 2};
printf("a: %d\n", a);
printf("b: %f\n", b);
printf("日期: %d-%d-%d\n", d.年, d.月, d.日);
return 0;
}
在上述示例中,我们使用 typedef 分别为 int 类型定义了别名 整数,为 float 类型定义了别名 小数,以及为结构体类型定义了别名 日期。这样,我们可以直接使用这些别名来声明变量,并使用它们的更具描述性的名称。
typedef 还可以对指针类型进行别名定义,例如:
typedef int* 整数指针;
这样,整数指针 就成为 int* 类型的别名。
使用 typedef 可以提高代码的可读性,使数据类型的含义更加明确,降低阅读和理解代码的难度。
2,案例
#include<stdio.h>
typedef struct
{
int num;
char name[32];
int age;
}person,*pperson; //*pperson 是指针变量
void print(person p)
{
printf("号数: %d 姓名:%s 年龄:%d\n",p.num,p.name,p.age);
//printf("号数: %d 姓名:%s 年龄:%d\n",p.num,p.name,p.age);
}
void print1(pperson p) //这里p是指针变量 pperson 是 我们人为定义的 结构体指针变量类型
{
printf("号数: %d 姓名:%s 年龄:%d\n",p->num,p->name,p->age);
}
int main()
{
person p1 = {1,"简佳人儿",23};
person p2 = {2,"肥嘟嘟",19};
pperson pp1 = &p1;
pperson pp2 = &p2;
print(p1);
print(p2);
print1(pp1);
print1(pp2);
return 0;
}
结构体类型之间不能直接进行比较操作。因此,在比较两个结构体类型的对象时,编译器会报错。
如果你需要比较两个结构体对象的某个字段的值,则可以使用该字段的具体值进行比较。比如,假设 struct Xuanmin 中有一个字段 score,你希望比较两个结构体对象的 score 字段的值大小,可以通过 ikun[i].score 和 max.score 来获取这两个对象的 score 值,然后进行比较。
#include <stdio.h>
struct Xuanmin {
int score;
};
int main() {
struct Xuanmin ikun[3] = { {80}, {90}, {70} };
struct Xuanmin max = {0};
int i;
for (i = 0; i < 3; i++) {
if (ikun[i].score > max.score) {
max = ikun[i];
}
}
printf("Max score: %d\n", max.score);
return 0;
}
在上述示例中,我们通过比较 ikun[i].score 和 max.score 的值来找到最高分数的结构体对象。
a3.6_switch_case.c: In function 'main': a3.6_switch_case.c:28:2: error: too few arguments to function 'gets' gets(); ^~~~ In file included from a3.6_switch_case.c:1: C:/MinGW64/x86_64-w64-mingw32/include/stdio.h:658:17: note: declared here char *cdecl gets(char *_Buffer) MINGW_ATTRIB_DEPRECATED_SEC_WARN;
根据提供的错误信息,可以看出在你的代码文件 “a3.6_switch_case.c” 的第28行中,调用了函数 ‘gets’,但是没有传入任何参数。然而,根据C语言的标准库函数,‘gets’ 函数需要至少一个参数来接收输入的字符串。
需要修复这个问题,你可以在调用 ‘gets’ 函数时传入一个字符数组作为参数,用于接收输入的字符串。例如:
char input[100];
gets(input);
此外,需要注意的是,‘gets’ 函数在很多编译器中已经被标记为不安全和不推荐使用的函数,因为它容易导致缓冲区溢出的安全漏洞。建议使用更安全的函数替代,如 ‘fgets’ 函数。使用 ‘fgets’ 函数的示例代码如下:
char input[100];
fgets(input, sizeof(input), stdin);
使用 ‘fgets’ 函数时,需要指定接收输入的字符数组的大小,并传入 ‘stdin’ 作为最后一个参数,表示从标准输入中读取输入。
希望这些信息对你有所帮助!如果有任何其他问题,请随时提问。
2023-07-25 10:36
F:\AIOT\IOT\a_1_C语言基础\第三章流程控制>gcc a3.7_switch_case_xueshengchengji.c a3.7_switch_case_xueshengchengji.c: In function 'main': a3.7_switch_case_xueshengchengji.c:25:12: error: expected ';' before ':' token case 0:~6:;
根据提供的错误信息,可以看到在你的代码文件 “a3.7_switch_case_xueshengchengji.c” 的第25行中,出现了语法错误。错误提示显示在 ‘case’ 语句块的冒号 “:” 之前缺少了一个分号 “;”。
在 switch 语句中,每个 case 后面的语句块结束之前需要加上分号。请检查你的代码,查找并修复这个错误。
正确示例:
case 0:
case 1:
// 执行语句块
break;
错误示例(缺少分号):
case 0: // 错误:缺少分号
case 1:
// 执行语句块
break;
希望这个解答对你有所帮助!如有任何其他问题,请随时提问。
2023-07-25 14:44
t--和--t的区别
“t–” 和 “–t” 都是 C 语言中的操作符,用于对变量进行自减操作。它们的区别在于它们的执行时机和返回值:
“t–”(后置自减操作符):先使用变量 t 的当前值,然后再将 t 的值减 1。
执行时机:t-- 是在当前语句执行完之后再进行自减操作。
返回值:t-- 的返回值是变量 t 自减前的值。
示例代码:
int t = 5;
int result1 = t--; // result1 的值为 5,然后 t 的值变为 4
“–t”(前置自减操作符):先将 t 的值减 1,然后再使用变量 t 的新值。
执行时机:–t 是在当前语句执行之前就进行自减操作。
返回值:–t 的返回值是变量 t 自减后的值。
示例代码:
int t = 5;
int result2 = --t; // t 的值先减为 4,然后 result2 的值为 4
总结:
如果你希望先使用变量的值再进行自减操作,可以使用后置自减操作符 “t–”。
如果你希望先进行自减操作再使用变量的值,可以使用前置自减操作符 “–t”。
需要注意的是,无论是 “t–” 还是 “–t” 都会改变变量 t 的值。因此,在使用时请根据具体需求选择合适的自减操作符。
希望这个解答对你有所帮助!如果还有其他问题,请随时提问。
2023-07-25 15:35
a3.13_for1.c: In function 'main': a3.13_for1.c:15:8: warning: passing argument 1 of 'puts' makes pointer from integer without a cast [-Wint-conversion] puts('a'); ^~~ In file included from a3.13_for1.c:1: C:/MinGW64/x86_64-w64-mingw32/include/stdio.h:672:32: note: expected 'const char *' but argument is of type 'int' int _cdecl puts(const char *Str);
根据提供的错误信息,可以看到在你的代码文件 “a3.13_for1.c” 的第15行中,调用了函数 ‘puts’,但是传入的参数是一个字符常量 ‘a’,而不是一个字符串。
‘puts’ 函数的参数类型应该是一个指向字符的指针,即字符串。而单引号括起来的 ‘a’ 表示一个字符,而不是字符串。
要修复这个问题,你需要将参数传递为字符串,即将参数用双引号括起来。示例代码如下:
puts("a");
这样就将字符常量 ‘a’ 转换为了字符串 “a”,然后作为参数传递给了 ‘puts’ 函数。
希望这个解答对你有所帮助!如果还有其他问题,请随时提问。
2023-07-25 16:26
最大公约数
求两个数的最大公约数有多种方法,其中常见的有辗转相除法和欧几里得算法(辗转相减法)两种。
辗转相除法(也称为欧几里得算法):
基本思想:假设两个数为 a 和 b,通过反复用较小数去除较大数取余,直到余数为 0,则最后一个非零余数即为最大公约数。
具体步骤:
将 a 除以 b,得到余数 r1。
将 b 除以 r1,得到余数 r2。
后续继续将 r1 除以 r2,如此反复,直到余数 ri 为 0。
最后一个非零余数 ri-1 即为最大公约数。
示例代码如下:
int gcd(int a, int b) {
if (b == 0) {
return a;
}
return gcd(b, a % b);
}
辗转相减法:
基本思想:假设两个数为 a 和 b,通过反复用较大数减去较小数,直到两个数相等或其中一个数为 0,则最后一个非零数即为最大公约数。
具体步骤:
如果 a 等于 b,则 a 为最大公约数。
如果 a 大于 b,则 a 减去 b,得到差值 c,再次使用 c 和 b 进行比较。
如果 b 大于 a,则 b 减去 a,得到差值 c,再次使用 c 和 a 进行比较。
如此反复,直到两个数相等或其中一个数为 0。
最后一个非零数即为最大公约数。
示例代码如下:
int gcd(int a, int b) {
while (a != b) {
if (a > b) {
a -= b;
} else {
b -= a;
}
}
return a;
}
可以根据需要选择其中一种方法来求解最大公约数。这些示例代码中的函数 gcd(a, b) 接受两个整数参数 a 和 b,并返回它们的最大公约数。
希望这个解答对你有所帮助!如果还有其他问题,请随时提问。
2023-07-25 17:21
size_t
size_t 是C语言中的一个数据类型,它用于表示内存大小或对象的大小。它是无符号整数类型,通常是一个无符号整数的别名。
在C标准库中,很多函数的参数或返回值的类型使用了 size_t,例如 strlen 函数的返回值类型就是 size_t。
size_t 的大小在不同的平台上可能会有所不同,但通常它是足够大以容纳任何对象的大小。它是一种机器相关的类型,在 32位系统上一般是 32位,在 64位系统上一般是 64位。
使用 size_t 类型的一个常见用法是在内存分配函数(如 malloc、realloc、calloc)中指定分配的字节数。此外,它还可以用于循环计数器以及表示数组的索引等场景。
下面是一个使用 size_t 的示例:
#include <stdio.h>
int main() {
size_t n = 10;
size_t i;
for (i = 0; i < n; i++) {
printf("%zu\n", i);
}
return 0;
}
在打印循环计数器的时候,使用 %zu 格式说明符来输出 size_t 类型的值。
希望这个解答对你有所帮助!如果还有其他问题,请随时提问。
2023-08-01 11:08
size_t源码
size_t 是 C 语言的标准库类型,通常由编译器提供。它的具体实现可以在编译器的头文件中找到。
size_t 的定义通常位于 <stddef.h> 头文件中,该头文件中还定义了其他与大小相关的类型和宏。
以下是一个 stddef.h 头文件中可能包含的 size_t 的简化示例定义:
#ifndef _SIZE_T
#define _SIZE_T
typedef /*implementation-defined*/ size_t;
#endif /* _SIZE_T */
具体的实现细节可以因编译器而异。在不同的平台和编译器上,size_t 的具体定义可能存在差异。在上述示例中,size_t 被定义为一个 implementation-defined 的类型。具体来说,它可能是 unsigned int、unsigned long、unsigned long long 等。
使用特定的编译器来编译代码时,可以查看其相应的标准库头文件,以了解 size_t 的实际定义。例如,在使用 GCC 编译器的情况下,可以查看 /usr/include/stddef.h 文件。
需要注意的是,虽然可以查看 size_t 的实现,但为了编写可移植的代码,应该始终使用标准库头文件 stddef.h 中定义的 size_t,而不是直接依赖于具体实现。
希望这能回答你的问题!如果还有其他问题,请随时提问。
2023-08-01 11:09
0取反得到什么
在计算机中,对整数进行取反操作是一种按位操作,通常使用位求反(bitwise NOT)运算符进行。
当一个整数进行位求反运算时,将会对其所有位进行取反操作,即将所有二进制位的0变为1,将所有二进制位的1变为0。
例如,对于二进制数 0000 0000,也就是十进制数 0,进行位求反运算后,结果为 1111 1111,也就是十进制数 -1。
需要注意的是,位求反运算会根据数据类型的大小仅对有效的位进行操作。例如,对于32位整数,位求反运算只会对前32位进行取反,如果有更高位的话,不会受到影响。
请记住,对于有符号整数,取反操作将会得到其按位取反后的结果,而不是取负数的操作。如果要得到一个有符号整数的相反数,应使用负号(取负)运算符。
希望这个解答对你有所帮助!如果还有其他问题,请随时提问。
2023-08-01 19:17
a_8.1_jiegoutichushi.c: In function 'main': a_8.1_jiegoutichushi.c:19:12: error: assignment to expression with array type stu1.name = "ikun";
根据你提供的错误信息,请注意在C语言中,数组是一种特殊的数据类型,无法直接使用赋值操作符将一个字符串赋值给一个数组。出现错误的原因是你尝试将一个字符串赋值给 stu1.name 这个数组。
如果你想给一个数组赋值,可以使用字符串拷贝函数 strcpy 或字符串赋值函数 strncpy 来完成。这两个函数可以将一个字符串复制到数组中。
示例代码如下:
#include <stdio.h>
#include <string.h>
struct Student {
char name[20];
int age;
};
int main() {
struct Student stu1;
// 使用 strcpy 函数将字符串赋值给数组
strcpy(stu1.name, "ikun");
stu1.age = 18;
printf("Name: %s\n", stu1.name);
printf("Age: %d\n", stu1.age);
return 0;
}
在上述示例中,我们使用 strcpy 函数将字符串 “ikun” 复制到 stu1.name 数组中。这样就可以给数组赋值了。
当然,要确保目标数组有足够的空间来容纳要复制的字符串,以免发生内存溢出的情况。在使用字符串拷贝函数时应当特别注意。
希望这个解答对你有所帮助!如果还有其他问题,请随时提问。
2023-08-01 19:59
a_8.3_struct_array_xuanpiao.c: In function 'main': a_8.3_struct_array_xuanpiao.c:54:9: error: invalid operands to binary < (have 'struct Xuanmin' and 'struct Xuanmin') if(max<ikun[i])
根据你提供的错误信息,请注意在C语言中,结构体类型之间不能直接进行比较操作。因此,在比较两个结构体类型的对象时,编译器会报错。
如果你需要比较两个结构体对象的某个字段的值,则可以使用该字段的具体值进行比较。比如,假设 struct Xuanmin 中有一个字段 score,你希望比较两个结构体对象的 score 字段的值大小,可以通过 ikun[i].score 和 max.score 来获取这两个对象的 score 值,然后进行比较。
示例代码如下:
#include <stdio.h>
struct Xuanmin {
int score;
};
int main() {
struct Xuanmin ikun[3] = { {80}, {90}, {70} };
struct Xuanmin max = {0};
int i;
for (i = 0; i < 3; i++) {
if (ikun[i].score > max.score) {
max = ikun[i];
}
}
printf("Max score: %d\n", max.score);
return 0;
}
在上述示例中,我们通过比较 ikun[i].score 和 max.score 的值来找到最高分数的结构体对象。
请根据你的实际需求,选择要比较的字段,并进行相应的更改。
希望这个解答对你有所帮助!如果还有其他问题,请随时提问。
2023-08-02 09:51
a_8.4_struct_pointer.c: In function 'main': a_8.4_struct_pointer.c:13:11: error: assignment to expression with array type ps->name ="蔡徐坤";
根据你提供的错误信息,请注意在C语言中,数组是一种特殊的数据类型,无法直接使用赋值操作符将一个字符串赋值给一个数组。出现错误的原因是你尝试将一个字符串赋值给 ps->name 这个数组。
如果你想给一个数组赋值,可以使用字符串拷贝函数 strcpy 或字符串赋值函数 strncpy 来完成。这两个函数可以将一个字符串复制到数组中。
示例代码如下:
#include <stdio.h>
#include <string.h>
struct Student {
char name[20];
int age;
};
int main() {
struct Student s;
struct Student *ps;
ps = &s;
strcpy(ps->name, "蔡徐坤");
ps->age = 18;
printf("Name: %s\n", ps->name);
printf("Age: %d\n", ps->age);
return 0;
}
在上述示例中,我们使用 strcpy 函数将字符串 “蔡徐坤” 复制到 ps->name 数组中。这样就可以给结构体中的数组字段赋值了。
当然,要确保目标数组有足够的空间来容纳要复制的字符串,以免发生内存溢出的情况。在使用字符串拷贝函数时应当特别注意。
希望这个解答对你有所帮助!如果还有其他问题,请随时提问。
2023-08-02 10:26
a_8.11_struct_union.c:22:21: note: (near initialization for 'u1') a_8.11_struct_union.c:22:25: warning: excess elements in union initializer union TestU u1= {2,'d',9.3};
根据你提供的警告信息,请注意在C语言中,联合(union)是一种特殊的数据类型,它只能存储其中一个成员的值。在初始化联合时,只能为其中一个成员赋值。
发生警告的原因是你在初始化联合时给了多余的元素。在你的代码中,联合 u1 的定义如下:
union TestU u1 = {2, 'd', 9.3};
根据警告信息,联合 u1 包含了超过一个成员的初始化值。联合只能存储一个成员的值,因此,应该只使用一项初始化值。
你可以根据需要选择给联合的一个成员赋值,如下所示:
union TestU {
int num;
char character;
float decimal;
};
int main() {
union TestU u1 = {2}; // 给联合的整型成员赋值
// 其他代码...
return 0;
}
在上面的示例中,我们给联合 u1 的整型成员 num 赋值为2。这样,联合 u1 就只有一个成员的初始化值,不会出现警告。
需要注意的是,在使用联合时需谨慎,确保正确地访问和操作联合的成员。
希望这个解答对你有所帮助!如果还有其他问题,请随时提问。
2023-08-02 16:24
联合体的作用
联合体(union)是C语言中的一种特殊数据类型,它允许在同一内存位置存储不同类型的成员变量。联合体的大小等于其最大成员的大小。
联合体的主要作用是节省内存空间。通过使用联合体,可以在相同的内存位置上存储不同类型的数据,从而避免为每种类型分配独立的内存空间。
除了节省内存外,联合体还可以用于以下几个方面:
存储不同类型的数据:联合体允许在不同时间存储不同类型的数据。你可以根据需要在联合体中使用一个成员,而其他成员则被忽略。
数据类型的转换:联合体可以用于进行类型转换。通过在不同类型的成员之间进行赋值,可以将数据从一种类型转换为另一种类型。
给成员起别名:联合体可以为不同的成员变量提供相同的内存位置,这样可以为这些成员变量起不同的别名,方便访问。
需要注意的是,联合体在同时存储不同类型的数据时,只能使用一个成员来访问数据,而其他成员的值会被覆盖。因此,在使用联合体时要确保正确地访问和操作成员变量,以避免出现意外的结果。
希望这个解答对你有所帮助!如果还有其他问题,请随时提问。
2023-08-02 19:44
枚举类型的定义
在C语言中,枚举类型(enumeration)用于定义一组具有命名值的常量。枚举类型允许用一个易记的名字来表示一组相关的常量,增强了代码的可读性和可维护性。
枚举类型的定义格式如下:
enum 枚举类型名 {
枚举常量1,
枚举常量2,
...
};
其中,枚举类型名 是你为枚举类型起的名字,可以根据需要自定义。
在枚举类型的定义中,你可以列出多个枚举常量,每个枚举常量用逗号分隔。枚举常量通常是大写字母命名,以表示它们是常量。
以下是一个示例,展示如何定义一个表示颜色的枚举类型:
#include <stdio.h>
enum Color {
RED,
GREEN,
BLUE
};
int main() {
enum Color color1;
enum Color color2;
color1 = RED;
color2 = BLUE;
printf("Color1: %d\n", color1);
printf("Color2: %d\n", color2);
return 0;
}
在上述示例中,我们定义了一个名为 Color 的枚举类型,包含了三个枚举常量 RED、GREEN 和 BLUE。然后,在 main 函数中声明了两个枚举类型的变量,并将其中的一个变量赋值为 RED,另一个为 BLUE。最后,通过 %d 格式说明符将枚举常量打印为整数值。
输出结果为:
Color1: 0
Color2: 2
每个枚举常量都会被赋予一个默认的整数值,从0开始递增。在上面的示例中,RED 被赋值为0,GREEN 没有直接赋值,默认为1,BLUE 被赋值为2。
你也可以在定义枚举时为每个枚举常量指定特定的值,如:
enum Month {
JAN = 1,
FEB = 2,
MAR = 3,
...
};
这样,JAN 的值为1,FEB 的值为2,以此类推。
希望这个解答对你有所帮助!如果还有其他问题,请随时提问。
2023-08-02 20:53
typedef 的定义作用
在C语言中,typedef 关键字用于为已有的数据类型起一个新的名字。它提供了一种简化和增强代码可读性的方式,使数据类型的定义更加清晰和易于理解。
typedef 的定义格式如下:
typedef 旧类型名 新类型名;
通过使用 typedef,你可以为已有的数据类型起一个新的别名。这个别名就可以像原始类型一样使用,但是它的名称更具有描述性,更方便理解。
以下是一些 typedef 的使用示例:
#include <stdio.h>
typedef int 整数; // 为 int 类型定义别名为 整数
typedef float 小数; // 为 float 类型定义别名为 小数
typedef struct {
int 年;
int 月;
int 日;
} 日期; // 为结构体类型定义别名为 日期
int main() {
整数 a = 10;
小数 b = 3.14;
日期 d = {2023, 8, 2};
printf("a: %d\n", a);
printf("b: %f\n", b);
printf("日期: %d-%d-%d\n", d.年, d.月, d.日);
return 0;
}
在上述示例中,我们使用 typedef 分别为 int 类型定义了别名 整数,为 float 类型定义了别名 小数,以及为结构体类型定义了别名 日期。这样,我们可以直接使用这些别名来声明变量,并使用它们的更具描述性的名称。
typedef 还可以对指针类型进行别名定义,例如:
typedef int* 整数指针;
这样,整数指针 就成为 int* 类型的别名。
使用 typedef 可以提高代码的可读性,使数据类型的含义更加明确,降低阅读和理解代码的难度。
希望这个解答对你有所帮助!如果还有其他问题,请随时提问。
2023-08-02 21:24
a_8.7_struct_puinter3_hanshu.c: In function 'printArr': a_8.7_struct_puinter3_hanshu.c:58:48: error: subscripted value is neither array nor pointer nor vector printf("候选人姓名: %s 候选人票数:%d",arr[i].name,arr[i].tickets);
根据你提供的错误信息,编译错误发生在函数 printArr 中的 printf 语句。错误提示说,订阅的值既不是数组、指针,也不是向量。
问题在于你使用了 . 运算符来访问结构体数组 arr 中的成员变量。然而,结构体数组应使用索引操作符 [] 来访问特定的元素。
要解决这个错误,你需要将 . 运算符改为 [] 索引操作符,代码如下所示:
printf("候选人姓名: %s 候选人票数:%d", arr[i].name, arr[i].tickets);
通过使用 [] 索引操作符,你可以正确地访问结构体数组中特定索引位置的结构体,并访问其成员变量。
希望这个解答对你有所帮助!如果还有其他问题,请随时提问。
a_8.6.1_struct_pointer.c: In function 'main': a_8.6.1_struct_pointer.c:13:10: error: assignment to expression with array type s1.name = "坤坤";
根据你提供的错误信息,编译错误发生在 main 函数中的第 13 行。错误提示说,你尝试将一个表达式赋值给一个数组类型的表达式。
问题在于你尝试将字符串常量赋值给结构体 s1 的 name 成员,但是 name 成员是一个数组类型,不能直接进行赋值操作。
要解决这个错误,你可以使用字符串拷贝函数 strcpy 来将字符串常量赋值给结构体 s1 的 name 成员。需要确保结构体 s1 的 name 成员数组足够大以容纳字符串常量。
以下是一个修改后的示例:
#include <stdio.h>
#include <string.h>
struct Student {
char name[20];
int age;
float gpa;
};
int main() {
struct Student s1;
strcpy(s1.name, "坤坤");
s1.age = 20;
s1.gpa = 3.8;
printf("姓名:%s\n", s1.name);
printf("年龄:%d\n", s1.age);
printf("GPA:%f\n", s1.gpa);
return 0;
}
在上述示例中,我们引入了头文件 <string.h>,并使用 strcpy 函数将字符串常量 "坤坤" 复制到结构体 s1 的 name 成员中。
使用字符串拷贝函数 strcpy 可以安全地将字符串复制到结构体数组中,确保不会发生缓冲区溢出等问题。
希望这个解答对你有所帮助!如果还有其他问题,请随时提问。
a_8.6.2_struct_pointer_app.c: In function 'main': a_8.6.2_struct_pointer_app.c:29:10: warning: passing argument 1 of 'memset' makes pointer from integer without a cast [-Wint-conversion] memset(tmpName,'\0',sizeof(tmpName));
根据你提供的警告信息,警告发生在 main 函数中的第 29 行。警告说,你将整数类型的值作为指针传递给了 memset 函数。
问题在于 tmpName 是一个字符数组,而 memset 函数需要使用指针作为第一个参数,以指定要设置的内存块的起始地址。然而,你传递给 memset 函数的 tmpName 是一个数组名,当作为参数传递时,会隐式地转换为指向数组首元素的指针,所以产生了警告。
要解决这个警告,你可以使用数组的地址(即数组名前加上 & 符号)作为 memset 函数的第一个参数。
以下是一个修改后的示例:
#include <stdio.h>
#include <string.h>
struct Student {
char name[20];
int age;
float gpa;
};
int main() {
struct Student s1;
char tmpName[20];
strcpy(tmpName, "坤坤");
memset(&tmpName, '\0', sizeof(tmpName));
printf("姓名:%s\n", s1.name);
printf("年龄:%d\n", s1.age);
printf("GPA:%f\n", s1.gpa);
return 0;
}
在上述示例中,我们首先定义了一个临时的字符数组 tmpName,并使用 strcpy 函数将字符串常量 "坤坤" 复制到 tmpName 中。然后,我们使用 memset 函数来将 tmpName 数组的内容初始化为全零。注意,在向 memset 函数传递 tmpName 的地址时,我们使用了 & 符号来获取数组的地址。
这样,我们可以避免警告,并正确地使用 memset 函数对数组进行内存初始化。
希望这个解答对你有所帮助!如果还有其他问题,请随时提问。
a_8.7_struct_pointer5_hanshu.c: In function 'main': a_8.7_struct_pointer5_hanshu.c:78:9: warning: passing argument 1 of 'printf' from incompatible pointer type [-Wincompatible-pointer-types] printf(XM,len);
根据你提供的警告信息,警告发生在 main 函数中的第 78 行。警告说,你将一个不兼容的指针类型作为参数传递给了 printf 函数的第一个参数。
问题在于在 printf 函数的第一个参数中,你传递了 XM,而 XM 是一个指向字符数组 char XM[20] 的指针。然而,printf 函数期望的第一个参数是一个字符串格式的连续字符序列,而不是一个指针。
要解决这个警告,你应该传递一个格式字符串,而不是指针。你可以使用 %s 占位符来表示字符串,并在 printf 函数的第一个参数中提供格式字符串和需要打印的变量。
以下是一个修改后的示例:
#include <stdio.h>
void printInfo(char *name, int age) {
printf("姓名:%s\n", name);
printf("年龄:%d\n", age);
}
int main() {
char XM[20] = "小明";
int age = 18;
printInfo(XM, age);
return 0;
}
在上述示例中,我们定义了一个函数 printInfo,接受一个字符指针 name 和一个整数 age 作为参数。在 printInfo 函数内部,我们使用 %s 占位符来打印字符串,并使用 %d 占位符来打印整数。
在 main 函数中,我们传递了 XM 字符数组和 age 变量作为参数调用了 printInfo 函数。
这样,我们可以避免警告,并正确地打印字符串和整数变量。
希望这个解答对你有所帮助!如果还有其他问题,请随时提问