初识C语言
dir 查看文件的目录
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;
$$
简单选择排序法
#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 -1 j<len i表示比对的轮数 j 就是i后一位数
$$
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
$$
数组作为函数的参数
数组形参
根据您提供的代码和错误信息,出现了函数调用参数数量不匹配的错误。根据错误信息看,您在函数调用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 //定义指针变量 int a ; printf("%d",*(&a));
$$
#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,二维数组 第一维数组的每一个元素都是一个数组。
$$
int arr[][]; arr[0]+1; //第一个数组的第二个元素 arr[0] //子数组的名字 也是子数组的首地址
$$
$$
arr[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
函数。
这样,我们可以避免警告,并正确地打印字符串和整数变量。
希望这个解答对你有所帮助!如果还有其他问题,请随时提问。