Bootstrap

给初学者的c语言

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 函数。

这样,我们可以避免警告,并正确地打印字符串和整数变量。

希望这个解答对你有所帮助!如果还有其他问题,请随时提问

                   

;