9th day

 P199 - 格式控制符的总结

    1.printf函数中的 占位符 / 格式控制符

        格式控制符的作用:    

            1.不同类型的数据在变量中存储的形式是不一样的,所以在读取变量中的数据的时候,类型不同,读取的方式也不同。

             为了保证可以正确读取出存储在变量中的数据,我们应该使用正确的格式控制符。

                %c: 从给定变量的地址开始,只读一个字节,然后把这个字节读出来,以其还原成ascii字符。

                %d: 从给定变量的地址开始,连读4个字节

                %f: 从给定变量的地址开始,连读4个字节

            变量中的数据如何存储的?那么就应该如何读取,这样才可以拿到正确的数据。

        格式控制符的总结:

        int 整形

                %d    读取int类型的数据,以十进制的形式输出   *****

                %o    读取int类型的数据,以八进制的形式输出

                %x    读取int类型的数据,以十六进制的形式输出

                %hd     short

                %ld     long

                %lld    long long 

                

                %u      unsigned int

                %hu     unsigned short

                %lu     unsigned long                   *****

                %llu    unsigned long long

        实型

            float           %f

            double          %lf  (%.2lf)

        字符型

           char    %c

        地址型:    %p

 P200 - 垃圾值得由来

    1.变量的回收。

      在大括号执行完毕之后,定义在这个大括号中的变量就会被系统的立刻回收。

      声明变量的时候其实是这样的,找系统为你从高地址向低地址分配指定字节数的连续空间。   

      如何回收?

      当变量回收的时候,其实就是告诉系统,变量不再使用了,可以分配给别的变量了。变量所占用的字节的数据不会清空

      当再声明1个变量的时候,这个新变量有可能就是刚刚被回收的那个变量占用的空间。

      那么这个时候,这个新变量中是有值的。值就是上次那个变量所遗留下来的数值。这就叫做垃圾值。

      所以,我们声明1个局部变量,最好先为其初始化为0;

    2.全局变量

      当将全局变量声明出来以后,系统会自动的将全局变量中的数据清零。

 P201 - 数组的概念

    1. 数组:数据的组合。

    2. 特点:

        a. 可以存储多个数据。

        b. 一个数组中只能存储类型相同的多个数据。创建数组的时候就指定。

        c. 数据中可以存储的数据的个数是固定的。创建数组的时候指定。

        d. 存储在数组中的数据方便管理。

 P202 - 如何声明数组

    1.创建数组之前首先要确定两点

        a.确定要存储的这多个数据的类型

        b.这个数组最多可以存储多少个数据

    2.声明数组的语法

        存储的多个数据的类型  数组名称[这个数组最多可以存储多少个数据]       

int arr[5] // array 数组

        代表创建1个数组,这个数组的名字叫做arr,这个数组最多可以存储5个数据。每一个数据的类型必须是int类型的。

    3.几个相关术语:

        1.元素:数组里的每一个成员,就叫做数组的元素

        2.下标/索引:为了区分每一个元素,C系统给每个元素编了一个号码

                    这个号码从0开始,依次递增。这个号码就是数组的下标/索引。

       3.长度:数组当中元素的个数。也就是说这个数组能存储多少个数据。

 P203 - 如何往数组中存储数据

        

    1.数组中存储数据的是元素,而不是数组。

      数组名代表的是整个数组,所以不能直接给数组赋值。

    2.语法:

        数组名[元素的下标] = 数据 ;

        arr[1] = 100 ;

        将100赋值给arr数组中下标位1的那个元素。

P205 - 为元素赋值注意两点

    3.注意:

        1.微元素赋值的时候,赋值的数据类型要和元素的类型一致。

        当赋值的数据的类型跟元素的类型不一致的时候,会做自动类型转换。

        2.下标不能越界。

        数组的下标的范围:0->数组长度-1

P206 - 如何取出存储在数组中的数据

     4.取出在数组中的元素的数据: 

            数组名[下标]

P207 - 数组的遍历

for(int j = 0 ; j < 数组的长度 ; j ++)
{
    arr[j];
}

 P208 - 关于数组的长度

    

    1.在声明数组的时候必须要声明数组的长度

    2.数组的长度可以是常量、变量、表达式(长度就是表达式的结果)、字符(ascii码)。

    3.数组的长度不能是小数,也不能是负数。

    4.数组的长度可以是1.也可以是0。(但是没有卵用)

    5.数组的长度也可以是一个宏,宏值必须是整数。

 P209 - 数组的元素和默认值和初始化

    1.当我们声明了数组没为元素赋值,里面是有垃圾值的。   

    2.数组的初始化。

        1.最傻的方式,用下标挨个赋值。

        2.在声明数组的时候就初始化数组的元素。(使用这种方式初始化,长度不能用变量)

            int arr[3] ={10,20,30};

        3.在使用第二种方式的时候,可以省略数组的长度。(长度由大括号的数据来决定)

            int arry[]={1,2,3,4,5,6,7,8,9,10};

        4.第四种初始化方式,只为数组前面的元素赋值。

            int arr[5]={1};

          这时候数组的第0个元素的值是1,其他的元素的值自动初始化为0.

          所以我们要将一个数组中所有的元素初始化为0,就int arr[5]={0};

        5.第五种初始化方式,指定下标的初始化。其他的元素的值就自动初始化为0了。

  P212 - 数组在内存中的存储形式

     1.变量在内存中的存储方式.

        a.不同类型的变量在内存中占据不同的字节数.1个变量占用的字节一定是连续的.

            int     4

            double  8

            float   4

            char    1

        b.在为变量分配字节空间的时候,是从高地址向低地址分配的连续空间.

          先声明的变量是在高字节,后声明的变量是在低字节。

        c.任何数据在内存中都是以其二进制的补码存储的.低位存储在低字节,高位存储在高字节。

        d.每1个字节在内存中都有1个地址。十六进制数。变量的地址:是组成这个变量的低字节的地址。

        e.使用&取地址运算符可以直接拿到变量的地址。

        f.使用%p打印地址类型的数据。

    2.数组在内存中是如何存储的呢?

         int arr[3];

         a.声明1个数组,在内存中从高字节向低字节申请连续的(数组的长度*每1个元素的字节数)个字节的空间。

         b.下标为0的元素在低字节。

         c.元素的值还是按照之前那样 存储的是 数据的二进制的补码。

         d.数组的元素的本质就是1个普通类型的变量。1个数组就是由多个普通类型的变量联合而成的。

 P213 - 数组的地址问题

    1. 数组地址是数组当中字节最低的地址

    2. 数组地址是数组中下标为0的元素的地址。

    3. 数组地址是数组中下标为0的元素的低字节地址。

    4. 重点:

       数组名就代表数组的地址。

       C语言的数组不代表整个数组,代表这个数组的地址。

       C语言的数组名中存储的就是数组的地址。

       我们不能直接打印数组名,这样得不到数组的元素的值。因为数组中存储的是数组的地址。

       所以我们应该使用%p来打印数组名。

int arr[] = { 10 , 20 , 30 };
printf("arr[0]的内存地址 :%p\n",&arr[0]);
printf("  arr 的内存地址 :%p\n",&arr);
printf("  arr 中储存的值 :%d [%p]\n",arr,arr);

         

         输出结果:

         arr[0]的内存地址 :0x7ffeefbff74c
           arr 的内存地址 :0x7ffeefbff74c
           arr 中储存的值 :-272631988 [0x7ffeefbff74c]

      数组的地址==数组名==数组中低字节的地址==数组中下标为0的元素的地址==数组中下表为0的元素的低字节的地址

 P214 - 数组长度的计算

    1.数组的每一个元素的类型相同,所以数组的每一个元素占用的字节空间一样。

    2.使用sizeof运算符 可以计算数组总共占用的字节数。

        sizeof(数组名); //这样我们就可以得到这个数组占用总的字节数。

    3.得到数组占用的总字节数,然后除以每1个元素占用的字节数就可以得到数组的长度了。

int arr[] = {545,45,45,45,4,877,8,23,8,423,18,5,12,8,7,7,65,32,8789,6,1,4,4,21,4,89,78,45,3};
int len = sizeof(arr) / sizeof(int) ;
for(int i = 0 ; i < len ; i ++)
{
    printf("arr[%d]:%d\n",i,arr[i]);
}

         

    4.不建议将字节数写死。元素占用的字节数建议也是使用sizeof计算出来。因为不同的系统不同的编译器相同的变量可能占用的字节不一样。

         sizeof(arr) / sizeof(元素类型);

         sizeof(arr) / sizeof(arr[ø]) ;

 P215-P217 - 关于数组你必须学会的四种简单算法(找出最大,最小,求累加和) & 判断数组中是否包含指定的元素,找指定的元素在数组中第一次出现的下标)

    
    int arr[]={186,953,109,382,349,153,236,620,935,492,396,651,774,208,685,59,867,636,572,518,378,522,602,366,729,632,869,329,845,441,540,701,272,30,187,887,726,113,832,37,554,672,762,428,758,31,447,940,903,830};
    
    int max = INT32_MIN;
    int min = INT32_MAX;
    int len = sizeof(arr) / sizeof(arr[0]);
    int key = 50 ;
    int sum = 0 ;
    int flag = 0 ;
    
    for(int i = 0 ; i < len ; i++ )
    {
        sum += arr[i];
        if(arr[i] > max)
        {
            max = arr[i];
        }
        if(arr[i] < min)
        {
            min = arr[i];
        }
        if(arr[i] == key)
        {
            printf("找到了和KEY相同的数,跳出循环\n");
            printf("指定的KEY第一次出现的下标是%d\n",i);
        }
        flag = i + 1 ;
    }
    printf("最大数  : %d\n",max);
    printf("最小数  : %d\n",min);
    printf("累加和  : %d\n",sum);
    
    if (flag == len)
    {
        printf("没有找到了和KEY相同的数\n");
    }

 P218 - 参数的值传递

     1.函数的参数。

         为函数传参的过程就是1个赋值的过程。

         是将实参赋值给形参。

     2.当参数的类型是int、double、float、char类型的时候。

         调用者传入1个实参变量。

         函数执行完毕之后,对实参变量的值没有影响。

         像这样的传递我们叫做值传递。

         调用者将实参变量传递到给函数,不管函数内部是如何操作形参。

         对实参变量没有任何影响。

     3.当1个函数的参数是1个普通变量的时候。那么这个时候可以传递数组的元素(数组的元素的类型和参数的类型一致)。

  P219 - 数组作为函数的参数

     4.数组是否可以作为函数的参数呢?

        肯定可以。因为数组也是1个数据类型。

        1.声明:

             直接在函数的小括号中声明1个数组就可以了。

                void test(arr[3])

        2.调用:

            如果被调用的函数带了参数,并且参数的类型是1个数组。那么在调用的时候就必须要为其传递1个数组,并且传递的数组的类型要和参数的数组的类型一致。

        3.遇到的问题。

             在函数的内部,通过sizeof去计算[参数数组】占用的字节数的时候。

             我们发现1个奇怪的问题:无论参数数组的长度声明为多大,得到的永远都是8个字节。

             这个时候,通过sizeof去计算参数 数组的长度的时候,是算不出来的。

             为什么?

             当数组作为函数的参数的时候,那么在传递的时候,会丢失数组的长度。

             结论:当数组作为函数的参数的时候。在函数内部使用sizeof计算参数数组的字节数,得到的永远是8.

                  所以,在函数内部无法使用sizeof计算参数数组的长度。

       4.为什么?

            1.如果函数是1个数组,在声明这个参数的时候 并不会去真得创建这个数组。而是去申请一个存储数组地址的变量(指针变量),这个指针变量在内存中占用8个字节,所以用sizeof去计算这个参数数组的字节都是8.

            2.在传值的时候,是把实参数组名传递过去,数组名代表数组的地址。所以,这个时候传值,传的是数组地址。把数组的地址传递给函数的参数,所以函数的参数也指向了实参数组。

         5.如何解决。

             那么就让调用者将实参数组的长度传递给我。再写1个参数,让调用者将传递进来的数组的出长度告诉我,

             注意:

                如果我们的函数的参数是1个数组,这个时候还必须得加1个参数。让调用者将这个数组的长度传递进来。

         6.当数组作为函数的参数的时候。实际上他并不是1个数组.而是1个用来存储数组地址的个指针变量.所以,数组作为函数的参数的时候。那个长度就没有必要写了。

                void test(int arr[], int len){};//传数组参数的时候将数组长度作为另外一个参数传进去。

 P220 - 数组作为参数的地址传递

     5.当函数的参数是1个数组的时候。那么在传递的时候,传递的是实参数组的地址。

       所以,形参数组指针指向了实参数组。这个时候通过形参数组指针操作数组实际上操作的就是是实参数组。这种参数传递,我们叫做地址传递。

 P221 - 重要结论

    6.重要结论

        1.当数组作为函数的参数的时候,会丢失数组的长度,所以这个时候还需要1个参数,让调用者传入数组的长度进来。

        2.当数组作为函数的参数的时候,在函数内部去修改这个参数数组的元素,其实修改的就是实参数组的元素。

        3.强调:只有数组作为函数的参数的时候,通过sizeof才算不出来长度。

 P222 - 产生不重复的随机数

    1.随机的产生一个双色球的号码。

        1-33 随机产生6个不重复的数。

        1-16 随机产生1个随机数。

    2.如何产生不重复的随机数。

        将之前产生的随机数储存起来,没产生1个随机数,就判断和之前的随机数有没有重复的,如果有就重新产生,如果没有就下一个。

 P223 - 选择排序

     /**

     *  选择排序法

     *

     *  @param arr  要排序的数组

     *  @param len  数组长度

     *  @param desc 是否降序,0为升序,非0为降序

     */

    void SelectionSort(int arr[], int len ,int desc)

    {

        //数组中有len个数据,要比len-1轮。

        for(int i = 0; i < len - 1 ; i++) //外层循环控制轮数,每循环一次,完成1轮的比较

        {

            //每轮做的事情,就是拿下标位i的元素和后面所有的元素进行比较

            //arr[i] i+1 len-1

            //将后面所有的元素遍历出来。

            for (int j = i + 1 ; j < len ; j++)

            {

                

                if ( desc != 0 ) {

                    if(arr[i] < arr[j])

                    {

                        int temp = arr[i];

                        arr[i] = arr[j];

                        arr[j] = temp;

                    }

                }else

                {

                    if(arr[i] > arr[j])

                    {

                        int temp = arr[i];

                        arr[i] = arr[j];

                        arr[j] = temp;

                    }

                    

                }

            }

        }

    }

 P224 - 冒泡排序


     /**

     *  冒泡排序法(降序排序)

     *

     *  @param arr 要排序的数组

     *  @param len 数组的长度

     *  @param desc 是否降序,0为升序,非0为降序

     */

    void bubbleSort(int arr[],int len,int desc)

    {

        //冒泡排序要比len-1.

        for(int i = 0 ; i < len - 1 ; i++ )//外层循环控制轮数,每循环一次,要完成1轮的比较。

        {

            //每一轮比较多少次。 len - 1 - i

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

            {

                //j j+1

                if(desc != 0 )

                {

                    if(arr[j] < arr[j+1] )

                    {

                        int temp = arr[j] ;

                        arr[j] = arr[j+1] ;

                        arr[j+1] = temp ;

                    }

                }else

                {

                    if(arr[j] > arr[j+1] )

                    {

                        int temp = arr[j] ;

                        arr[j] = arr[j+1] ;

                        arr[j+1] = temp ;

                    }

                }

                

            }

            

        }

    }

 P225 - 二分查找法

    1.二分查找法/折半查找。

    在1个数组中查找指定的元素的下标。

        1.从头到尾挨个的遍历。这样的话,效率低下。

        2.使用折半查找,前提是:数组是有序的。

 /**

 *  二分查找法/折半查找法

 *

 *  @param arr 要查找数据的数组(必须是已升序排列过的)

 *  @param len 数组长度

 *  @param key 要查找的数字(必须是数组中存在的,否则会死循环)

 *

 *  @return 返回找到的数组下标
 */

int search_binary(int arr[],int len,int key)

{

    int min = 0 ;

    int max = len - 1 ;

    int mid = len / 2 ;

    

    //先判断key 跟中间数是否相等,如果不一样就判断大小。

    while(key != arr[mid])

    {

        //判断大小关系

        if(arr[mid] > key)

        {

            //说明要找的下标在左边,再去找左边的中间数

            max = mid  - 1 ;

        }else

        {

            min = mid + 1 ;

        }

        

        mid = ( min + max ) / 2;

    }

    

    return mid;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值