C语言DAY09 - 数组

格式控制符总结

字符数据在内存中是如何存储的?
char ch = 'a';
存储的是97的二进制的补码
char ch = 97;
直接为 char 变量赋值一个整数是可以的.
char 变量 有没有正负符号?
有符号的.最高位表示符号位
printf("%d",ch);
也可以使用%d 输出 char 变量的值,本来存储的就是整数.
格式控制符的作用
  1. 不同类型的数据在变量中存储的形式是不一样的
  2. 读数据的时候,类型不同,读取的方式也不一样的.
  3. int num = 100;
    printf("%f\n",num);
    输出0.00000
    以 float 形式读取,前面两个字节是0.
    为了保证可以正确的读取存储在变量中的数据,就要使用正确的格式控制符.
    
  4. %c 的读取方式,从给定的变量的地址开始,读取1个字节.然后将这个字节的整数读出来,还原成 ASCII 码对应的字符.

  5. %d 从给定的变量的地址开始,连读4个字节.
  6. 为了保证可以正确的读取存储在变量中的数据,就要使用正确的格式控制符.怎么存怎么读.
格式控制符的总结

int 整形

%d .读取 int ***** 
整形数据,以十进制的星海输出
%o . 以八进制形式输出
%x. 以十六进制的形式输出

%hd . short
%ld . long
%lld. long long
%u . unsigned int 
%hu unsigned short
%lu unsigned long *****
%llu unsigned long long

实型:

float: %f
double: %lf

字符型

char %c

地址

%p
垃圾值的由来

声明一个变量,如果没有初始化,就会有一个垃圾值

  1. 大括弧结束后,变量是如何回收的
  2. 并不是把以前字节删除.是告诉系统,变量不再使用 ,可以分配给别的变量了.
  3. 里面的数据不会清空.
  4. 再声明一个变量,就可能把之前的字节分配给下一个字节.
  5. 那么这个新的变量的垃圾值就是之前的变量的值
  6. 全局变量声明系统会自动清零

数组

数组的概述
  1. 数组的作用

    1. 是存储多个数据,并且多个数据之前和谐的共处.
    2. 普通变量只能存1个数据
    3. 而数组可以存多个数据,新数据进去,旧数据还在
  2. 数组的特点.

    1. 可以存储多个数据
    2. 1个数组中只能存储类型相同的多个数据,在我们创建的时候指定.
    3. 存储的个数是固定的,在我们创建数组的时候指定的.
    4. 存储在数组中的数据太方便管理了.
如何声明1个数组
  1. 确定存储的这组数据的类型
  2. 这个数据最多可以存多少数据
  3. 声明数组的语法

    数据类型 数组名称[最多存多少个数据];
    int arr[5];//array
    创建了一个最多可以存储5个 int 类型的数组

数组在内存中是如何创建的—>形象理解版本
int arr[3];

1. 内存中声明1个数组变量 arr
2. 平均的划分成 3 个等份
3. 每份都是 int 类型.
4. 真正存储数据的是数组里面的3个小空间.

几个专业术语
  1. 元素: int arr[3],就有三个元素.
  2. 下标(索引): 为了区分每一个元素,给其编号,从0开始依次递增.
  3. 长度: 指的是数组当中元素的个数.N 个元素,下标最多到 N - 1.
如何往数组当中存储数据
数组当中存储数据的是元素而不是整个数组.
数组名[元素的下标] = 数据;
arr[0] = 100;
将100赋值给 arr 数组中下标位0的那个元素
需要注意的几个问题
  1. 数组的元素本质就是一个普通类型的量
  2. 数组中的数据和谐共处是多个元素和谐共处
  3. 当为同一个下标变量赋值,新的值会干掉旧值
为元素赋值的时候要注意的几点
  1. 赋值的时候类型要相同
  2. 下标不要越界,其实可以赋值,只是赋值给数组屁股后面的空间了.会出现危险
  3. 下边的范围0~长度-1.
取出数组中的数据
  1. 我们要取的是数组当中元素的数据.
  2. 如果要取出元素的值,就要确定取出哪一个元素的值

    printf("%d\n",arr[1]);
    就可以取出数组当中下标为1的元素的值
    下标越界取值就是别人的值了.
    
遍历数组
要将数组中的每一个元素的值打印出来,就遍历0—>数组长度-1 范围之间的整数 作为下标
for(int i = 0; i<3;i++)
{
    printf("%d\n",arr[i]);
}
数组的长度

关于数组的长度:

  1. 在声明数组的时候,必须要声明数组的长度
  2. 长度可以是变量,常量,表达式,’字符’(长度就是其 ASCII 码.
  3. 不能是一个小数.也不能是负数
  4. 可以是1,也可以是0,不过侬脑子秀逗啦?
  5. 也可以是宏!宏值必须是整数
#define LEN 10
int main()
{
    int arr[LEN];
}

关于数组元素的默认值
默认值没有初始化就是垃圾值,初始化了其中一个,其他的就是0
关于数组元素的初始化
1. 最傻的方式

int arr[3];
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;

2. 在声明的同时就初始化

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

- 使用这种方式初始化数组的长度就不能使用变量了,为什么?

int arr[3] = {10,20,30};
编译器编译的时候还是会把他们还原成最根本的方式.
int arr[3];
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
如果这个时候用变量?
int arr[len] = {10,20,30};
1.在编译器编译的时候不知道数组的长度.
2.变量的值要在执行起来赋值以后才知道.
3.为了保证一定不会越界,出错,就不允许使用变量来表达长度.
4.使用宏是可以的,宏是预处理指令,编译的时候就已经确定了.
  1. 数组的长度超过定义的长度

    int arr[5] = {21,21,23,23,21,321,32,32,32,321,24,41,321,42}

    1. 这个时候取数一下这个长度显然不现实,就直接省略长度
    2. 省略后长度就是由大括弧中的数据来决定的,有多少数据就有多长.
    3. 如果指定了5个长度,5个元素后面的数据会直接丢弃!
  2. 部分初始化

    int arr[3] = {10};
    1.只为数组的前面的元素赋值,数组的其他的元素就初始化为0;
    2.如果要将数组中所有的元素初始化为0,就把第一个元素初始化为0;
    3.一定要使用大括号的方式才行

  3. 指定下标的初始化

    int arr[3] = {[1] = 10,[2] = 20};
    其他的元素的值就自动的初始化为0;

数组在内存中的存储形式
int arr[3];
  1. 声明一个数组,在内存中是从高地址向低地址连续的申请(数组长度*元素字节数)长度的空间.
  2. 下标为0的元素在低字节地址.
  3. 元素的值还是按照之前那样,存储的是数据的二进制补码.
  4. 数组的地址是数组中下标为0的地址
  5. 数组明就代表数组的地址
  6. C 语言的数组名中存储的就是数组的地址

    数组的地址 == 数组名 == 数组中的低字节的地址 == 数组中下标为0的元素的地址 == 数组中下标为0的元素的的低字节的地址
    printf(%p\n",arr);
    printf(%p\n",arr[0]);
    
数组的长度的计算
sizeof(arr);

- 使用 sizeof 运算符,得到数组总共占用的字节数

int len = sizeof(arr);

- 得到占用的总的字节数,除以每一个元素占用的字节,就可以得到长度

int len = sizeof(arr)/sizeof(arr[0]);
//每个系统或者编译器不同的话,同一个类型的变量占用的字节数也可能是不一样的,所以不要把元素的大小写死.

- 数组的每一个元素的类型相同,所以数组的每个元素占用的空间也相同

什么时候使用数组
多个类型相同的数据,并且数据的意义相同的时候,才使用数组来存储.

数组的算法

  1. 找出一个整形数组的最大值.

    int arr[] = {32,2,32,321,42,15,36,54,765,865,65,35,427,46}
    int max = INT32_MIN,min = INT32_MAX;
    for(int i = 0;i < sizeof(arr)/sizeof(arr[0]);i++)
    //sizeof 表达式会造成性能困扰,每次都要计算,可以换成一个变量保存在里面.
    {
    if(arr[i] > max)
    {
    max = arr[i];
    }
    if(arr[i] < min)
    {
    min = arr[i];
    }
    }

  2. 求数组的平均值和累加和.(遍历每一个元素加到变量中保存.)
  3. 判断1个数组中是否包含指定的元素(遍历每一个元素进行比较.全部都不相等就是没有)旗帜变量

    int flag = 0;
    for(int i = 0;i

数组与函数
  1. 为函数传参的过程就是一个赋值的过程,将实参赋给形参
  2. 当参数的类型是 int,double,float,char, 类型,函数执行完毕之后对实参变量的值没有影响.
  3. 像这样的传递我们叫做值传递.
  4. 或者上面这些类型的数组的某一个元素的时候
数组作为函数的参数

声明

int arr[3] = {1,2,3};
void test(int arr[]);
//声明一个无返回值函数参数是一个int 类型数组

调用

test(arr);
//传递一个类型相同的数组
  • 数组作为函数的参数的时候,在函数内部计算数组的长度,永远都是8个字节.

    1. 如果函数的参数是一个数组,在声明这个参数的时候,并不会创建一个数组.而是去声明一个储存数组地址的指针变量.
    2. 这个指针变量就是8个字节,所以计算永远是8.
    3. 所以在传递数组给函数的时候还要传递一个数组的真实长度.
    4. 因为数组作为函数的参数时是一个指针变量,所以才不用写长度.
  • 当函数的参数是数组的时候传递的是实参数组的地址

    1. 形参数组指向的地址和实参数组的地址重合了,都是指向的同一段内存地址
    2. 当形参数组去更改实参数组下标范围内的值的时候,内存中存储的数据就发生了改变
    3. 当函数结束,实参数组再去调用内存数据的时候,就已经被改变过了.
随机数
  1. 随机的产生1个双色球号码

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


1~16 产生1个随机数
  1. 如何产生不重复的随机数?

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

    //使用一个数组存储之前已经产生的随机数
    int arr[6] = {0};
    for(int i = 0;i < 6; )
    {
    int nun = arc4random_uniform(33)+1;
    //函数的参数1数组的地址,参数2长度,参数3要对比的数.返回值0代表没有重复,1代表重复.
    int res = isContain(arr,6,num);
    if(res == 0)
    {
    arr[i] = num;
    i++;
    //巧妙的将i++更换到没有重复的数的时候才执行.
    }
    }

选择排序
  1. 有 N 个数,把第i个到最后一个一个一个的比,若比第一个数大,就把其换到第i个位置.
  2. 第i轮结束可以找到最高的人.
  3. 第i+1轮开始从第i+1个人开始和后面的人比
  4. j 就是跟 i 去比较的人
  5. 有 N 个人就比 N - 1 轮

    int arr[N];
    //有 N 个数,把第i个到最后一个一个一个的比
    for(int i = 0; i < N-1;i++)
    //第i轮结束可以找到最高的人.有 N 个人就比 N - 1 轮
    {
    //j 就是跟 i 去比较的人
    for(int j = i+1 ;j < N ;j++)
    {
    //若 j 比第i个数大,就把其换到第i个位置.
    if(arr[j] > arr[i])
    {
    int temp = arr[j];
    arr[j] = arr[i];
    arr[i] = temp;
    }
    //第i轮结束可以找到最高的人.
    //剩下的最后一个人已经是最小的了,就不用比了.
    }

冒泡排序
int arr[] = {1,2,3,4,5,6,7,8,9}
int len = sizeof(arr)/sizeof(arr[0]);
for(int i = 0;i < len-1;i++)//通常外层循环都是控制轮数
{
    for(int j = 0;j < len -1 -i;j++)//每轮比较数组长度-1-已经比较过几个数
    {
        if(arr[j] < arr[j+1])    //j 每次都和 j 的下一个数比较
        {
            int temp = arr[j];
            arr[j] = arr[j+1];
            arr[j+1] = temp;
        }
    }
}
二分查找法
找到一个数据如果挨个挨个找,效率就会低下.所以我们就折半查找.

大前提,是个有序的数组
1. 找中间那个数,判断大了还是小了
2. 如果大了说明再左边,小了就在右边,如果等于那还说个屁
3. 最左边的下标是0,右边的是 len -1;
4. mid 是 max/2
5. 如果在左边,max = mid -1,右边 mid +1;

         int len =sizeof(arr)/sizeof(arr[0]);
         int max = len -1;
         int min = 0;
         int mid = len/2;
         int key = 1321;

         while(key != arr[mid])
         {
             if(arr[mid] > key)
             {
                 min = mid + 1;
             }
             else if(arr[mid] < key)
             {
                 max = mid - 1;
             }
             mid = (min + max)/2;
             //如果 key 不在数组内会造成死循环,可以加一个判断来结束循环
         }
         printf("%d\n",mid);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值