c语言基础 2

1.输入输出语句

1.1格式化输入输出

(1)printf()

                函数原型:#include    <stdio.h>

                int printf(const char *format,...)

返回值:成功返回输出的字符,失败返回-1

 格式符:

                                %d    ---->十进制的输出 

                                %f    ---->浮点数的输出

                                %s    ---->字符串的输出

                                %c    ---->字符的输出
                                
                                %e    ---->浮点的指数的输出

                                %x    ---->16进制的输出

                                %o    ---->8进制的输出

                                %p    ---->地址的输出

修饰符:

                                m     ---->输出的域宽,不够的用空隔齐,默认右对齐(域宽<数据本身的长度时,以数据的长度为准)

                                .n     ---->输出的小数位数,5舍6入

                                -        ---->在域内左对齐

                                0        ---->域宽不够时,用0来补齐

                                #        ---->十六或八进制的前导    0X,0

                                +        ---->有符号的正数之前显示+

                                l        ---->在d或f之前    制定精度为long或double

(2)scanf()

函数原型:

                #include <stdio.h>

                int scanf(const char *format,...)

                               格式控制串  地址表

返回值:成功返回成功输入的个数,int类型,如没有获取到,返回0,错误结束返回-1

格式控制串与printf的类似。

scanf("%4d%2d%2d",&y,&m,&n); (域宽可以限定输入的界限)

输入:20220711

输出:

        y: 2022        m: 07        n: 11

非法字符输入,,,,,会使变量赋值失败

输入:25,32,12

scanf("%d%d%d",&x,&y&z);

x:25        y=?        z=?

输入了非法字符,导致非法字符之后的数据输入失败。

垃圾字符的处理:

1.加空格    scanf("%c %c",&a,&b);    (字符读取中间加一个空格,会处理所有的垃圾字符,多个空格或多个回车)
2.%*nc 抑制赋    scanf("%c%*nc%c")    跳过这n次赋值,跳过n个垃圾字符
3.getchar();    两次scanf之间加一个getchar()    用getchar吃垃圾字符,一次只能吃一个

1.2.字符的输入输出

(1)字符的输入:

                #include<stdio.h>

                int getchar(void); 成功返回读取到的字符

                失败返回EOF(-1)

(2)字符的输出:

                int putchar(char c); 成功返回输出的字符

                失败返回EOF(-1)

1.3 字符串的输入输出:

1.gets():可能越界

        #include <stdio.h>
        char *gets(char *s);    成功返回首地址,失败返回NULL
        s;用来保存输入的数据的内存块
    
            输入的字符串自动补上‘/0’,输入的字符串不以空格结束,scanf的%s以空格结束,以回车结束
        fgets(数组名,最大长度,流(stdin键盘输入));
            arr[strlen(arr)-1]='\0'    会把回车也输入,需要把最后的回车置零

2.puts():


        #include <stdio.h>
        int puts(const char *s);(const 定义的元素不能修改)
                    成功返回非负数,失败返回EOF(-1)    
puts,自带换行功能,puts("");

2.控制语句

2.1顺序结构

自上而下,顺序执行

2.2选择结构

1.if-else
    if(表达式)    0为假,非0为真
    {
        语句块1;(表达式逻辑值为真)
    }
    else
    {
        语句块2;(表达式逻辑值为假)
    }


2.阶梯结构(在elseif里进行第二次if)
    if(表达式1)
    {
        语句块1:
    }
    else if(表达式2)
    {
        语句块2;
    }
    else if(表达式3)
    {
        语句块3;
    }
    ......
    else
    {
        语句块n;(以上表达式都不成立)
    }
3.嵌套结构(在语句块中进行第二次if)
    if(表达式1)
    {
        if(表达式2)
        {
            if(表达式3)
            {
                。。。。。。
            }
            else
            {
                语句块3;
            }
        }
        else
        {
            语句块2;
        }
    }
    else
    {
        语句块1;
    }

4.switch    (表示式是整数类型不考虑浮点数)            
    switch(表达式)
    {
         case 1:语句块1;break;
        case 2:语句块2;break;(break跳出switch)
            。
            。
        default:语句块n;
    }
当多个case所执行的语句块一样时,可以共用。case相邻,只用一次break;

三目运算符:
    (表达式1)?表达式2:表达式3
    表达式1的值为真则执行表达式2,为假则执行表达式3
        eg:max=(a>b)?a:b
        等价于   if(a>b)
                max=a;
            else 
                max=b;

1.3循环结构

(表达式比循环体多执行一次),表达式不成立,循环体结束
 循环一般有三个组成,初值,边界(结束点),自加或自减(方向)

1.goto跳转
    eg:
    ...
    loop:
    ...
    goto loop;(goto 会去到loop所标记的地方,继续向下运行)
    
2.while(表达式)(表达式成立执行)
{
    循环体;
}

先判断表达式,再执行循环体

3.do{
循环体
}while(表达式);
    先执行一次,再来判断表达式是否成立。
    
4.for循环
    for(表达式1;表达式2;表达式3)
    {
        循环体;
    }
    表达式1 一般给初值,表达式2 一般判断(做边界),表达式3,一般自加或自减
    for(;;)相当于while(1),初值与自增可以在循环体中写
    
    
辅助控制语句:
    break:跳出当前循环(一层)
    continue:解说本轮循环,继续下一次循环(一次)
    return:结束当前模块(结束函数),函数的返回值
    exit:结束一个进程

3.数组

3.1数组的定义

具有一片连续的存储空间,并且是相同数据类型的多个变量的集合

3.2数组的一般形式

<存储类型> <数据类型> <数组名> [ 表达式];

存储类型:一般默认为自动存储 auto

数据类型:看要存储的数据是什么类型,就选择什么类型的数据类型;

数组名:合法的标识符

表达式:数组的维数(元素个数,为常量表达式)

eg:int arr[5]; ----> 表示一个可以存储5个整形数据的数组

首地址和普通的指针不一样

首地址、地址常量

arr+1,表示第二个元素的地址

arr++(×)arr++---->arr=arr+1,数组名不能自加,赋值,原因:数组名为首地址、数组名为地址常量,常量不能自加

3.3数组的引用

数组只能逐个访问; 数组名+下标

数组名[下表];(下标从0开始)、

eg: int arr[5]---->arr[0] ,arr[1] ,arr[2] ,arr[3] ,arr[4]

3.4数组的初始化

1.数组的完全初始化(值以逗号隔开)
    int arr[5]={1,2,3,4,5};
2.数组的部分初始化(从左到右赋值,没赋值的部分自动补0)
    int arr[5]={1,2,3};
        eg: int arr[5]={0};数组的所有元素都赋值为0
3.不给下表的初始化:(数组大小由赋值决定,当我们给了n个初值name这个数组最多就只能存n个数据)
    int arr[]={1,2,3,4,5}

3.5数组的大小

数组所占字节数=单个元素所占字节数*元素个数

sizeof(数组名)    =   sizeof(数据类型)  * N

数组元素个数=sizeof(数组名)/sieof(数组类型)

​                    eg:    n=sizeof(arr)/sizeof(int);值用%ld来显示

3.6数组的常见错误

eg: int[5]

int[5]=100;//error

c语言不做越界检查,在使用数组的时候一定不要越界(0~4)

eg: int size=5;

int arr[size]={0};//error

数组的表达式不能为变量,size的值可能改变,但数组生成后长度不能改变

3.7常见的两种排序方法

冒泡排序:

顾名思义,水泡会自己向上浮,两个数据比较,小的一个向上移动,每次比较两个,一轮循环比较n-i-1次,进行n次循环。

比较n次,每次排列n-i-1次,(i表示第几次比较)

也就是两层循环,第一层从0~n-1,第二层控制0~n-i-1

eg:10个数字,第一次排列0~9,比较9次

第二次排列0~8,比较8次

......

第九次排列0~1,比较1次

比较内容根据从大到小排列,还是从小到大排序来决定,

eg:

        int arr[n],i,j;

        for(i=0;i<n;i++)

        {

                for(j=0;j<i-n-1;j++)

                {

                        if(arr[j]>arr[j+1])//交换

                                {

                                        a^=b;

                                        b^=a;

                                        a^=b;

                                 }

                }

        }

选择排序:

找最值的下标,一次循环中,找到最值,然后放到集合首位,进行n-1次循环,每次都在最值之外的集合中找到新的最值,再把他移至此次集合的首位。

循环n-1次,最后一次不用比较

k指向i//假设a[i]为最值

每次循环是i与之后的所有数据比较

如果k下标对应的元素不是最值,则把k指向最值的下表

每次循环完都要比较k的值是否变化,如变化,则把新的最值换至i所在位置

       

eg:

        int arr[n],i,j,k;

        for(i=0;i<n-1;i++)

        {

                k=i;//首先假设第一个值是最大值

                for(j=i;j<n;j++)//循环比较谁大的

                {

                         if(arr[j]>arr[k])//如果arr[j]更大,那么k就记录i的值,也就是记录最值的下标

                        {

                               k=j;

                        }

                }

                if(k!=i)//说明最大值换过,交换

                {

                         arr[i]^=arr[k];

                         arr[k]^=arr[i];       

                         arr[i]^=arr[k];

                }

        }

4.字符一维数组

1.一般形式:(char占一个字节)
        存储类型是char的一维数组
            eg:    char arr[5]
            
            char a[6];
    str="hello";//error 首地址是常量,不能改变
    
2.字符数组的初始化
    
    1)逐个字符常量赋值(用下标来赋值)
        ①完全初始化    char str[5]={'h','e','l','l','o'}(可以,但是输出麻烦)
        应该在最后加一个'/0',数组计算长度是需要+1            🤦‍♀️🤦‍♀️🤦‍♀️🤦‍♀️
        char str[6]={'h','e','l','l','o','\0'}
        printf("%s",首地址);
        输出:从首地址到'\0'结束,
        (一般会把字符数组当做字符串处理,完全初始化需要加上'\0')
        
        ②部分初始化    char str[5]={'h','e'}
        (没有赋值的地方,用'\0'赋值)
        char str[5]={65,66,67,68};
            字符赋值可以是字符('A'),也可以是ascii值(65)
            char str[5]={0};(全部赋值为'\0')
            
        ③不给下表的初始化
            char str[]={'h','e','\0'}
            末尾需要手动补上'\0'便于输出
    2)字符串常量赋值(注意大小)
        char str[6]="hello";
        char str[6]={"hello"};
        (“”输入的是字符串,自动在末尾补一个'\0')

5.字符串函数

eg:从终端输入一串字符,统计字符的个数
scanf    %s    遇空格结束,要读取空格用gets
            输出以 '\0' 结束
            
1.strlen():求字符串的有效长度,遇到'\0'结束
    原型:    #include <string.h>
        size_t strlen(const char *s);
        s:指向用来保存字符串内存块(字符数组)
        返回值:字符数组的有效长度ld(不包含'\0')
    sizeof()看的是总的大小
    strlen()是到'\0'的大小
    eg:
        char str1[32]="hello";
        char str1[]="how";
        实现把str2里面的内容拷贝到str1中
        
2.strcpy():字符串的拷贝
    原型:    #include <strings.h>
            char *strcpy(char *dest,const char *src)    将src指向的串拷贝到dest指向的空间
    返回值:返回dest的地址(目标串的首地址)
    注意:dest指向的空间需要足够大
        在拷贝的时候,连同src指向的串的'\0'一起拷贝,作为新串的'\0'

3.strcat():字符串的连接

    #include <strings.h>
    char *strcpy(char *dest,const char *src)
    
    将sec指向的串连接到dest指向的串后哦面
    
    返回值:返回dest的地址(目标串的首地址)
    
    注意:dest指向的空间需要足够大
    在拷贝的时候,连同src指向的串的'\0'一起拷贝,作为新串的'\0'(目的是为了dest这个数组后面有'\0'结尾)
    最后也要 str[i]='\0';
    如果初始化时已把字符数组全置为0,可以省略
            
4.strcmp():字符串的比较
    #include <strings.h>
    int strmp(const char *s1,const char *s2);
    比较s1和s2,从左往右比较ASCII值,遇到不同或'\0'结束
    返回值:
    s1>s2    返回差值    正整数
    s1<s2    返回-差值    负整数
    s1==s2    返回0

6.二维数组

1.二维数组的一般形式
    <存储类型><数据类型><二维数组名>[常量表达式1][常量表达式2],表达式定义的是行列数
    eg:
        int arr[2][3]--->表示一个两行三列的数组

2.二维数组的访问:
        数组名[行][列];
        下标从0开始

3.内存是一维的,二维数组按行序号优先存储

二维数组由多个一维数组组成
    eg:
            arr[2][3]
            由两个一维数组arr[0],arr[1]组成,取元素也是数组名+下标
            arr[0]是数组名,常量,表示地址
            
4.二维数组可以看成由多个元素组成(数量的组成)

5.二维数组的初始化: 

    🐱‍🚀🐱‍🚀
    没有赋值的地方补0
    第一维长度在分行初始化时可以省略
    初始化的内容定义了函数({}中有几个大括号就是几行)
    不给第一维下标初始化时,几行能存下,就有几行
    
1)分行初始化:    
    
    eg:
        int arr[2][3]={{1,2,3},{4,5,6}};
        int arr[2][3]={{1,2},{4}};
        int arr[][3]={{1,2,3},{4,5,6}};
        
        int arr[2][]={{1,2},{4}};//error 无法确定列数
        
2)按元素排列顺序初始化:
    从首位开始依次赋值
    eg:
        int arr[2][3]={1,2,3,4,5,6};
        int arr[2][3]={1,2,3,4};
        int arr[2][3]={0};
        int arr[][3]={1,2,3};
        //两行能存下就默认两行
        
        int arr[][3]={1,2};
        //变成一维数组 不建议使用
        
6.二维数组的大小
    二维数组所占字节数=单行所占字节数*行数
    sizeof(arr)=sizeof(arr[0])*m(行数)
    
    单行所占字节数=单个元素所占字节数*列数
    sizeof(arr[0])=sizeof(arr[0][0](数据类型))*n(列数)
    
    行数=sizeof(arr)/sizeof(arr[0])
    
    列数=sizeof(arr[0])/sizeof(arr[0][0](数据类型))
    
eg:打印杨辉三角

    1
    1 1
    1 2 1
    1 3 3 1
    1 4 6 4 1
    
    规律:
            a[i][j]=a[i-1][j-1]+a[i-1][j];
    
    分两类数据处理:
            j==0的,i==j的
            和规律内的
            
解题思路千千种,总有更合适的算法

补充:
    转义字符
    八进制形式的转义字符最多后跟三个数字,也即\ddd,最大取值是\177-->(127(十进制));
    十六进制形式的转义字符最多后跟两个数字,也即\xdd,最大取值是\x7f-->(127(十进制))。
    \017    八进制数,一个字符
    \082    八进制数,3个字符(八进制数0~7),不会出现8

        

常用的四种交换方式:

1.借助第三个变量

c=a;

a=b;

b=a;

2.两个数之间进行加减运算,以实现两个数的交换

a=a+b;

b=a-b;

a=a-b;

3.通过异或来进行交换(数字才可行)

a^=b 

b^=a 

a^=b 

4.通过位运算来实现交换(数据有多余的高位空间,不适用于大数)

a=a<<8;(int类型)

a=a+b;

b=a>>8;

a=a&0xff;

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值