• C语言基础--数组及相关


    概念:

      一堆相同类型的数据的有序集合

    格式:

      元素类型  数组名称[ 元素个数 ]

    定义数组: 

        // 定义了一个名称叫做scores的数组, 数组中可以存放3个int类型的数据
        int scores[3];
        // 只要定义一个C语言的数组, 系统就自动会给数组中的每一块小得存储空间一个编号
        // 这个编号从0开始, 一次递增
        // 数组中系统自动绑定的编号, 我们称之为 索引
        scores[0] = 12;
        scores[1] = 66;
        scores[2] = 59;

    数组初始化:

      完全初始化:

        // 依次将{}中的每一个值赋值给数组中的每一个元素
        // 并且从0开始赋值
        int scores[5] = {99,88,77,66,100};

    部分初始化:  

         // 默认从0开始初始化, 依次赋值
         // 注意: 如果"在部分初始化中"对应的内存没有被初始化, 那么默认是0
         int scores1[3] = {11, 22}; 

    注意点:

      1.如果没有对数组进行初始化(完全和部门), 那么不要随便使用数组中的数据, 可能是一段垃圾数据(随机值)

      2.定义数组的时候, 数组的元素个数不能使用变量  变量作为数组的元素个数, 不初始化的情况下是随机值, 如果初始化会直接报错

      3.如果定义的同时进行初始化, 那么元素的个数可以省略, 省略之后, 初始化赋值几个数据, 数组就能存储几个数据,如果定义数组时没有进行初始化, 那么不能省略元素个数

      4.可以通过[索引] = 的方式, 给指定索引的元素赋值  

        int socres7[101] = {[99] = 1, [100] = 3}; 

      5.只能在定义的同时利用{}进行初始化, 如果是先定义那么就不能使用{}进行初始化

        int scores8[3];
        //scores8 = {1 , 4, 19};
        // 如果先定义那么就不能再进行整体赋值, 只能单个赋值
        scores8[0] = 1; 

    数组遍历:

        int scores[6] = {1, 23, 44, 66, 71, 88, 99 , 2};
        // 动态计算数组的元素个数
        int length = sizeof(scores) / sizeof(scores[0]);
        //length 不要写 6 这样的魔鬼数字
        for (int i = 0; i < length; i++) {
            printf("scores[%i] = %i
    ", i,scores[i]);
        } 

    数组内存分配:

      存储方式:

        1)计算机会给数组分配一块连续的存储空间

        2)数组名代表数组的首地址,从首地址位置,依次存入数组的第1个、第2个....、第n个元素

        3)每个元素占用相同的字节数(取决于数组类型)

        4)并且数组中元素之间的地址是连续。        

        // 变量在内存中的存储
        // 由于变量的内存寻址是从大到小, 所以存储数据时会从高字节开始存储
        int num = 10; // 0000 0000 0000 0000 0000 0000 0000 1010
        /*
        00001010     0x7fff5fbff7cc
        00000000     0x7fff5fbff7cd
        00000000     0x7fff5fbff7ce
        00000000     0x7fff5fbff7cf
        */       
        // 注意: 数组的存储和变量有点不一样, 数组存储元素, 是从所占用的低字节开始存储
        //     数组的元素自然的从上往下排列存储,整个数组的地址为首元素的地址。
        char charValues[4] = {'l', 'u', 'c', 'k'};
        /*
         charValues[0] = 0x7fff5fbff7c8
         charValues[1] = 0x7fff5fbff7c9
         charValues[2] = 0x7fff5fbff7ca
         charValues[3] = 0x7fff5fbff7cb
         */ 
    
        //&charValues == charValue == &charValue[0]     

    数组越界问题:    

    #include <stdio.h>
    
    int main(int argc, const char * argv[]) {
        int nums[2] = {1, 5};
        int values[3] = {7, 8, 9};
        // 注意点: 在使用数组的时候, 一定不要访问不属于字节的存储空间, 这样会导致数据混乱
        // 有时候如果访问了不属于自己的存储空间, 程序会报错
        values[3] = 44;
        printf("values[3] = %i
    ", values[3]);
        printf("nums[0] = %i
    ", nums[0]);    
        nums[-1] = 88;
        printf("values[2] = %i
    ", values[2]);
        return 0;
    }
    /*
     输出结果:
         values[3] = 44
         nums[0] = 44
         values[2] = 88
     */

    下图分析  values[3]访问到了nums[0]的空间    nums[-1] 访问到了 values[2] 的空间

           

    数组练习:

           

        // 从键盘录入当天出售BTC的价格并计算出售的BTC的总价和平均价(比如说一天出售了4个比特币)
        // 1.1定义数组保存每个比特币的价格
        int values[4] = {-1};
        // 1.2动态计算数组的元素个数
        int length = sizeof(values) / sizeof(values[0]);
        // 1.3定义变量保存总和
        int sum = 0;
        for (int i = 0; i < length; i++) {
            printf("请输入第%i个比特币的价格
    ", i + 1);
            scanf("%i", &values[i]);
            //2.0 计算总和
            sum += values[i];
        }
        /*
        // 2.计算总和
        int sum = 0;
        for (int i = 0; i < length; i++) {
            sum += values[i];
        }
         */
        // 3.计算平局值
        int average = sum / length;
        // 4.输出结果
        printf("sum = %i, average = %i
    ", sum, average); 

    数组与函数:

       1 数组名作为函数的参数传递, 是传递的数组的地址

         因为数组名就是数组的地址 &number = &number[0] == number

       2 如果数组作为函数的形参, 元素的个数可以省略

       3 如果形参是数组, 那么在函数中修改形参的值, 会影响到实参的值  

        void change(int values[])
        {
            values[1] = 99;
        } 
    
        int main(int argc, const char * argv[]) {
             int nums[2] = {1, 5};
            change(nums);
            printf("nums[1] = %i
    ", nums[1]);
            return 0;
        }
        输出结果: 99 

    注意点:

       如果传递的数组的名称, 其实传递的是地址 如果传递的是地址, 其实传递的是指针  指针在64位编译环境占8个字节

       如果数组作为形参, 那么在函数中就不能通过数组的名称计算出数组元素的个数  因为系统会自动将数组形参转换为指针, 指针占用8个字节  所以只能读取到8个字节的数据

      举例:

        要求定义一个函数, 实现遍历数组. (只要别人传递数组给函数, 就要求输出数组中所有元素的值)      

            #include <stdio.h>
            void printArray(int values[5]); 
    
            int main(int argc, const char * argv[]) {  
                int nums[3] = {1 , 3 , 5};
                printf("size = %i
    ", sizeof(nums));  //  size = 12    
                printArray(nums); // 数组名称就是数组的地址
                return 0;    
            } 
    
            void printArray(int values[5])
            {
                printf("size = %i
    ", sizeof(values));  //  size = 8    
                // 1.动态计算数组的元素个数
                int length = sizeof(values) / sizeof(values[0]);
                // 2.遍历数组
                for (int i = 0; i < length; i++) {
                    printf("values[%i] = %i
    ", i,values[i]);  // 输出: values[0] = 0  values[1] = 3
                }
            }                         

      改正后(能正确输出数组的所有元素):    

            #include <stdio.h>
            void printArray(int values[5], int length); 
    
            int main(int argc, const char * argv[]) {  
                int nums[3] = {1 , 3 , 5};
                printf("size = %lu
    ", sizeof(nums));  //  size = 12   
                int length = sizeof(nums) / sizeof(nums[0]);    
                printArray(nums, length);
                return 0;
            } 
    
            void printArray(int values[5], int length)
            {
                printf("size = %lu
    ", sizeof(values));  //  size = 8 
                // 遍历数组
                for (int i = 0; i < length; i++) {
                    printf("values[%i] = %i
    ", i,values[i]);  // values[0] = 0  values[1] = 3    
                }
            } 

    数组练习:    

    #include <stdio.h> 
    
    int main(int argc, const char * argv[]) {
        // 要求从键盘输入6个0~9的数字,排序后输出
        // 1.定义数组保存用户输入的数据
        int nums[10] = {0};
        // 2.接收用户的数据
        int value = -1;
        for (int i = 0; i < 6; i++) {
            printf("请输入第%i个数据
    ", i + 1);
            scanf("%i", &value);
            nums[value] = nums[value] + 1;
        }
        
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < nums[i]; j++) {
                printf("%i
    ", i); // 1, 1, 2, 3, 3, 6
            }
        }   
        return 0;
    }
    /*
     1. nums[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
     2. 用户输入的数组当做数组索引
     3. 输入一次  索引对应的值 + 1
     输入 1, 1, 2, 3, 3, 6之后
     数组对应值 : nums[10] = {0, 2, 1, 2, 0, 0, 1, 0, 0, 0};
     下标:                   0  1  2  3  4  5  6  7  8  9
     4. 然后对数组排序输出
     */ 

    数组排序:

      冒泡排序

         

        int nums[6] = {99, 12, 88, 34, 5, 7};
        int length = sizeof(nums) / sizeof(nums[0]);
        for (int i = 0; i < length - 1; i++) {
            for (int j = 0; j < length - 1 - i; j++) {
                if (nums[j] > nums[j + 1]) {
                    int temp = nums[j];
                    nums[j] = nums[j + 1];
                    nums[j + 1] = temp;
                }
            }
        } 

      选择排序:

         

            int nums[8] = {99, 12, 88, 34, 5, 44, 12, 100};
            int length = sizeof(nums) / sizeof(nums[0]);
            for (int i = 0; i < length - 1; i++) {
                for (int j = i+1; j < length; j++) {
                    if (nums[i] > nums[j]) {
                        int temp = nums[i];
                        nums[i] = nums[j];
                        nums[j] = temp;
                    }
                }
            }    

      选择--冒泡排序优化(提取函数)

        #include <stdio.h>
        void selectSort(int nums[], int length);
        void printArray(int nums[], int length);
        //void swap(int v1, int v2);
        void swap(int nums[], int i, int j);
        void bubbleSort(int nums[], int length); 
    
        int main(int argc, const char * argv[])
        {
            // 已知一个无序的数组, 里面有5个元素, 要求对数组进行排序
            int nums[8] = {99, 12, 88, 34, 5, 44, 12, 100};
            int length = sizeof(nums) / sizeof(nums[0]);    
            printArray(nums, length);    
            bubbleSort(nums, length);
            printf("----------------
    ");    
            printArray(nums, length);
            return 0;
        }
        // 遍历数组
        void printArray(int nums[], int length)    
        {
            for (int i = 0; i < length; i++) {
                printf("nums[%i] = %i
    ", i, nums[i]);
            }
        }
        void bubbleSort(int nums[], int length)
        {
            for (int i = 0; i < length - 1; i++) {
                for (int j = 0; j < length - 1 - i; j++) {
                    if (nums[j] > nums[j + 1]) {
                        swap(nums, j, j+1);
                    }
                }
            }
        }
         // 选择排序
        void selectSort(int nums[], int length)
        {
            for (int i = 0; i < length - 1; i++) {
                for (int j = i+1; j < length; j++) {
                    if (nums[i] > nums[j]) {
                        /*
                        int temp = nums[i];
                        nums[i] = nums[j];
                        nums[j] = temp;
                         */
        //                swap(nums[i], nums[j]);
                        swap(nums, i, j);
                    }    
                }
            }
        } 
        // 基本数据类型作为函数的参数, 是值传递, 在函数中修改形参不会影响实参的值
        /*
        void swap(int v1, int v2)
        {
            int temp = v1;
            v1 = v2;
            v2 = temp;
        }
         */
        // 交换两个数的值
        void swap(int nums[], int i, int j)
        {
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;    
        } 

    折半查找:

      思路:

        在有序表中,取中间元素作为比较对象,若给定值与中间元素的要查找的数相等,则查找成功;

        若给定值小于中间元素的要查找的数,则在中间元素的左半区继续查找;

        若给定值大于中间元素的要查找的数,则在中间元素的右半区继续查找。

        不断重复上述查找过 程,直到查找成功,或所查找的区域无数据元素,查找失败。

           

          

      #include <stdio.h>
      #include <time.h>
      int findKey(int nums[], int key, int length);
      int findKey2(int nums[], int length, int key);
      int findKey3(int nums[], int length, int key); 
    
      int main(int argc, const char * argv[]) {
          // 现在已知一个有序的数组, 和一个key. 要求从数组中找到key对应的索引的位置
          // 对该方法进行封装, 要求找到就返回对应的索引, 找不到就返回-1
          int nums[500000] = {1, 3, 5, 7, 9, [499999] = 99};
          int key = 99;
          int length = sizeof(nums) / sizeof(nums[0]);  
    
           // 消耗了1640毫秒
          clock_t startTime = clock();
          int index =  findKey(nums, key, length);
          clock_t endTime = clock();
          printf("消耗了%lu毫秒
    ", endTime - startTime);
          printf("index = %i
    ", index);  
          
          // 消耗了3毫秒
          clock_t startTime = clock();
          int index = findKey2(nums, length, key);
      
          // 消耗了2毫秒
          int index = findKey2(nums, length, key);
          clock_t endTime = clock();
          printf("消耗了%lu毫秒
    ", endTime - startTime);
          printf("index = %i
    ", index);   
          return 0;
      }  
     
      int findKey3(int nums[], int length, int key)
      {
          int min, max, mid;
          min = 0;
          max = length - 1;   
          // 只要还在我们的范围内就需要查找
          while (min <= max) {
              // 计算中间值
              mid = (min  + max) / 2;
              if (key > nums[mid]) {
                  min = mid + 1;
              }else if (key < nums[mid])
              {
                  max = mid - 1;
              }else
              {
                  return mid;
              }        
          }
          return -1;
      }
     
      int findKey2(int nums[], int length, int key)
      {
          int min, max, mid;
          min = 0;
          max = length - 1;
          mid = (min + max) / 2;    
          while (key != nums[mid]) {
              // 判断如果要找的值, 大于取出的值, 那么min要改变
              if (key > nums[mid]) {
                  min = mid + 1;
              // 判断如果要找的值, 小于取出的值, 那么max要改变
              }else if (key < nums[mid])
              {
                  max = mid - 1;
              }
              // 超出范围, 数组中没有需要查找的值
              if (min > max) {
                  return -1;
              }
              // 每次改变完min和max都需要重新计算mid
              mid = (min + max) / 2;
          }
          return mid; 
      }  
    
      //循环遍历查找
      int findKey(int nums[], int key, int length)
      {
          for (int i = 0; i < length; i++) {
              if (nums[i] == key) {
                  return i;
              }
          }
          return -1;
      }   

    进制转换查表法:

    #include <stdio.h>
    void total(int value, int base, int offset);
    void ptintBinary(int num);
    void printfOct(int num);
    void printfHex(int num); 
    
    int main(int argc, const char * argv[]) {
    // ptintBinary(10); // printfOct(10); printfHex(10); return 0; } //转十六进制 void printfHex(int num) { total(num, 15, 4); } //转八进制 void printfOct(int num) { total(num, 7, 3); } //转二进制 void ptintBinary(int num) { total(num, 1, 1); } // 转换所有的进制 // value就是需要转换的数值 // base就是需要&上的数 // offset就是需要右移的位数 void total(int value, int base, int offset) { // 1.定义一个数组, 用于保存十六进制中所有的取值 char charValues[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; // 2.定义一个数组, 用于保存查询后的结果 char results[32] = {'0'}; // 3.定义一个变量, 用于记录当前需要存储到查询结果数组的索引 int pos = sizeof(results)/ sizeof(results[0]); while (value != 0) { // 1.取出1位的值 int res = value & base;// 1 7 15 // 2.利用取出来得值到表中查询对应的结果 char c = charValues[res]; // 3.存储查询的结果 results[--pos] = c; // 4.移除二进制被取过的1位 value = value >> offset;// 1 3 4 } // 4.打印结果 for (int i = pos; i < 32; i++) { printf("%c", results[i]); } printf(" "); }

     

  • 相关阅读:
    jQuery.validator.unobtrusive.adapters.addMinMax round trips, doesn't work in MVC3
    Debug a script that sits in a partial view
    OneTrust Cookies
    What's the technical reason for "lookbehind assertion MUST be fixed length" in regex?
    How to specify data attributes in razor, e.g., dataexternalid="23151" on @this.Html.CheckBoxFor(...)
    Google Colab Tips for Power Users
    跟李沐学Ai 04 数据操作 + 数据预处理【动手学深度学习v2】
    使用ActiveReports for .net 进行报表开发(十一)迁移到3.0
    在sqlserver中如何根据字段名查找字段所在的表
    FastCount停止服务,再提供两个免费网站浏览计数器
  • 原文地址:https://www.cnblogs.com/dx-230/p/4756236.html
Copyright © 2020-2023  润新知