初学c课程笔记整理6-->>数组

是什么?有什么用?用在什么地方?(理解)
养成良好的编程习惯;
培养编程思想;
写代码之前应该先分析需求,分析完需求再开始写代码;(写注释)
 
1.数组的定义
数组的定义格式:
     数据类型 变量名称;
     数据类型 数组名称[数据的个数];
     元素类型 数组名称[元素个数];
     元素类型: 就是数组中需要存储的数据类型, 一旦指定, 数组中就只能存储该类型的数据
     元素个数: 就是数组中能够存储的数据(元素)的个数
 
      int scores[3];
// 定义了一个名称叫做scores的数组, 数组中可以存放3int类型的数据
   scores = 12; // 系统搞不清楚应该赋值给谁
 
只要定义一个C语言的数组,
系统就自动会给数组中的每一块小得存储空间一个编号
这个编号从0开始, 依次递增
数组中系统自动绑定的编号, 我们称之为 索引
 
3.数组的初始化
需求保持全班101个人的分数
  定义数组:
  元素类型 数组名称[元素个数];
    /*
    // 先定义再初始化
    int scores[5];
    scores[0] = 99;
    scores[1] = 88;
    scores[2] = 77;
    scores[3] = 66;
    scores[4] = 100;
     */
    // 依次将{}中的每一个值赋值给数组中的每一个元素
    // 并且从0开始赋值
    // 也称之为数组的初始化(完全初始化)
    int scores[5] = {99,88,77,66,100};
   
    // 部分初始化
    // 默认从0开始初始化, 依次赋值
    // 注意: 如果"在部分初始化中"对应的内存没有被初始化, 那么默认是0
    int scores1[3] = {11, 22};
    printf("0 = %i\n", scores1[0]);
    printf("1 = %i\n", scores1[1]);
    printf("2 = %i\n", scores1[2]);
   
⚠️数组注意事项
     在定义数组的时候[]里面只能写整型常量或者是返回整型常量的表达式
    ⚠️ 注意: 如果没有对数组进行初始化(完全和部分), 那么不要随便使用数组中的数据, 可能是一段垃圾数据(随机值)
    
 
    ⚠️ 注意: 定义数组的时候, 数组的元素个数不能使用变量, 如果使用变量, 那么数组中是一些随机值
   
    ⚠️注意: 不建议使用变量定义数组, 如果使用了变量定义数组, 作为数组的元素个数, 不初始化的情况下是随机值, 如果初始化会直接报错
   
    ⚠️注意: 如果定义的同时进行初始化, 那么元素的个数可以省略
       省略之后, 初始化赋值几个数据, 那么数组的长度就是几. 也就是说数组将来就能存储几个数据
    int scores5[] = {1, 3};
    printf("0 = %i\n", scores5[0]);
    printf("1 = %i\n", scores5[1]);
    printf("-------\n");
   
    ⚠️注意; 如果定义数组时没有进行初始化, 那么不能省略元素个数
     可以通过[索引] = 的方式, 给指定索引的元素赋值
    int socres7[101] = {[99] = 1, [100] = 3};
    printf("3 = %i\n", socres7[99]);
    printf("4 = %i\n", socres7[100]);

   
     ⚠️注意: 只能在定义的同时利用{}进行初始化, 如果是先定义那么就不能使用{}进行初始化
     如果先定义那么就不能再进行整体赋值, 只能单个赋值
 
4.数组的遍历
取出数组中所有的值, 称之为遍历
     
  ⚠️注意: 在遍历数组的时候, 尽量不要把遍历的次数写死
    遍历多少次应该由数组来决定, 也就是说遍历多少次应该通过数组计算得出
    
    printf("scores = %lu\n", sizeof(scores));
    // 计算出数组占用的总字节数
 
    printf("scores[0] = %lu\n", sizeof(scores[0]));
    // 计算出数组中某一个元素占用的字节数
 
    printf("一个有多少个元素 : %lu\n",
    sizeof(scores) / sizeof(scores[0]));
   
// 动态计算数组的元素个数
    int length = sizeof(scores) / sizeof(scores[0]);
 
 // 数组的遍历
    for (int i = 0; i < length; i++) {
        printf("scores[%i] = %i\n", i,scores[i]);
    }
    return 0;
 
5.数组的内存分配
1.数组内部存储细节
   存储方式:
    1)计算机会给数组分配一块连续的存储空间
    2)数组名代表数组的首地址,从首地址位置,依次存入数组的第1个、第2个....、第n个元素
    3)每个元素占用相同的字节数(取决于数组类型)
    4)并且数组中元素之间的地址是连续
⚠️注意:字符在内存中是以对应ASCII值的二进制形式存储的,而非上表的形式。
在这个例子中,数组x的地址为它的首元素的地址0x08,数组ca的地址为0x03
 
2.数组的地址
- 在内存中,内存从大到小进行寻址,为数组分配了存储空间后,数组的元素自然的从上往下排列 存储,整个数组的地址为首元素的地址。
    数组a的地址是ffc1,a[0]的地址是ffc1,a[1]的地址是ffc5
    因此a == &a[0],即第一个元素的地址就是整个数组的地址
 
3.数组的越界问题
  数组越界导致的问题
     约错对象
      程序崩溃
    char cs1[2] = {1, 2};
    char cs2[3] = {3, 4, 5};
    cs2[3] = 88; // 注意:这句访问到了不属于cs1的内存
    printf("cs1[0] = %d\n", cs1[0] );
输出结果: 88

 
6.数组与函数
基本数据类型作为函数的参数是值传递
   如果形参是基本数据类型, 在函数中修改形参的值不会影响到实参的值
 
 ⚠️注意1: 数组名作为函数的参数传递, 是传递的数组的地址
      因为数组名就是数组的地址 &number = &number[0] == number
 ⚠️注意2: 如果数组作为函数的形参, 元素的个数可以省略
      如果形参是数组, 那么在函数中修改形参的值, 会影响到实参的值
 
如果传递的数组的名称, 其实传递的是地址
如果传递的是地址, 其实传递的是指针
指针在64位编译环境占8个字节
 
  ⚠️注意: 如果数组作为形参, 那么在函数中就不能通过数组的名称计算出数组元素的个数
  因为系统会自动将数组形参转换为指针, 指针占用8个字节
 
 
数组的一些练习的函数封装:
选择排序、冒泡排序
// 遍历数组
void printArray(int nums[], int length)
{
    for (int i = 0; i < length; i++) {
        printf("排序后:nums[%i] = %i\n", i, nums[i]);
    }
}
//选择排序
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;
            }
        }
    }
    //    输出选择排序后的排列
    printArray(nums,length);
}
//冒泡排序
void bubbleSort(int nums[], int length)
{
    for (int i = 0; i < length - 1; i++) {
        for (int j = 0; j < length - 1; j++) {
            if (nums[j] > nums[j + 1]) {
                int temp = nums[j];
                nums[j] = nums[j + 1];
                nums[j + 1] = temp;
        }
        }
    }
        //    输出冒泡排序后的排列
   printArray(nums, length);
}
折半查找
//    遍历数组
int findKye(int nums[], int length, int value)
{
    for (int i = 0;  i < length; i++) {
        if (nums[i] == value) {
            return i;
    }
}
    return -1;
}
//折半查找
int findKey2(int nums[], int lengh, int value)
{
//    定义两个变量分别来记录下标最大和最小值
    int max = lengh - 1;
    int min = 0;
//    for循环遍历数组
    for (int i ; i < lengh; i++) {
//        定义一个变量来记录下标中间值
        int mid = (max + min) / 2;
//        判断要查找的值和中位值比较大小
//        要查找的值比中位值大,则中位变最大位并-1
        if (nums[min] > value) {
            max = mid - 1;
        }
//         要查找的值比中位值小,则中位变最小位并+1
        else if (nums[min] < value)
        {
            min = mid + 1;
        }
//        相等则返回下标
        else{
            return mid;
        }
    }
//    要查找的值不存在便返回-1
    return -1;
}
进制查表法
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("\n");
   
}
 
 
 
 
posted @ 2015-10-22 23:53  a滴答  阅读(163)  评论(0编辑  收藏  举报