学C的第十二天【深入了解数组:一维和二维数组的创建和初始化;一维和二维数组的使用;一维和二维数组在内存中的存储;数组越界;数组作为函数参数;冒泡排序(对数组名的理解)】-2

简介: 5.二维数组的使用 操作符 [ ] :下标引用操作符,它其实就是数组访问的操作符,使用两个[ ],访问行和列 二维数组的行和列都是从0开始的

5.二维数组的使用

   

操作符 [ ]下标引用操作符,它其实就是数组访问的操作符,使用两个[ ],访问行和列

 

二维数组行和列都是从0开始

57766674144f497294d3c07e8bf96096.png

二维数组的使用实例

   

//二维数组的使用
#include <stdio.h>
int main()
{
  int arr[4][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7},{4,5,6,7}, };
  //      行 列
  //循环打印二维数组:
  //printf("%d\n", arr[2][3]);
  int i = 0;
  //行号
  for ( i = 0; i < 4; i++)
  {
    int j = 0;
    //列号
    for ( j = 0; j < 5; j++)
    {
      printf("%d ", arr[i][j]);
    }
    printf("\n"); //打印完一行后换行
  }
  return 0;
}

image.png

6.二维数组在内存中的存储(32位操作系统)

 

(演示代码:)

 

//二维数组在内存中的存储(32位操作系统)
#include <stdio.h>
int main()
{
  int arr[4][5] = { 0 };
  //      行 列
  //循环打印二维数组:
  //printf("%d\n", arr[2][3]);
  int i = 0;
  //行号
  for (i = 0; i < 4; i++)
  {
    int j = 0;
    //列号
    for (j = 0; j < 5; j++)
    {
      printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
    }
  }
  return 0;
}

 

int类型的数组中,相邻的两个元素相差4个字节,因为一个整形元素占4个字节

image.png

二维数组内存中连续存放的,所以当知道了数组的起始地址,就可以知道后面的其它元素

image.png

(行可以省略,列不能省略的原因决定了一行有几个元素,一行有几个元素知道了,下一行放在哪才确定了)

 

(把“第一行”理解成一个一维数组“第二行”理解成一个一维数组……所以可以把二维数组看作是一维数组的数组一个一维数组就是一个元素

7.数组越界

  • 数组的下标是有范围限制的。

数组的下标规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。

 


所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。

 


C语言本身不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的。

 


 所以程序员写代码时,最好自己做越界的检查。

  • 二维数组也可能存在越界

   

数组越界实例

 

//数组越界
#include <stdio.h>
int main()
{
  int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
  //下标:   0 1 2 3 4 5 6 7 8 9
  int i = 0;
  for ( i = 0; i <= 10; i++)
  {
    printf("%d\n", arr[i]);
    //当i等于10的时候,越界访问了
  }
  return 0;
}


33a4315b093f40ba84e9fb24349753da.png

8.数组作为函数参数

 

往往我们在写代码的时候,会将数组作为参数传给函数

例子:冒泡排序函数(算法思想)

 

未使用自定义函数:)

//输入10个整数,对这组整数进行排序:(未使用自定义函数)
//排序有很多种方法:
//1.  冒泡排序 
//2.  选择排序
//3.  插入排序
//4.  快速排序
//......
#include <stdio.h>
int main()
{
  int arr[10] = { 0 };
  int sz = sizeof(arr) / sizeof(arr[0]); //求元素个数
  //输入数组
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    scanf("%d", &arr[i]);
  }
//排序:冒泡排序,升序
  //趟数:总共要排多少次
  for (i = 0; i < sz - 1; i++) 
  //sz - 1:10个元素的话只用排9次
  { 
    //每趟排几次
    int j = 0;
    for (j = 0; j < sz - 1 - i; j++)
    //sz - 1 - i:第一次排9次,第二次只用排8次……
    {
      if (arr[j] > arr[j + 1])
      //前一个数大于后一个数,进行交换
      {
        //交换,交换两个值时,要有个中间变量
        int tmp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = tmp;
      } 
    }
  }
  //打印数组
  for (i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}

补充:对数组名的理解(重点)

 

//数组名的理解
#include <stdio.h>
int main()
{
  int arr[10] = { 1,2,3,4,5,6 };
  //数组名通常情况下就是数组首元素的地址
  printf("%p\n", arr);
  printf("%p\n", &arr[0]); //数组首元素地址
  //有2个例外:
    //1. sizeof(数组名),数组名单独放在sizeof()内部,
      //这里的数组名表示整个数组,计算的是整个数组的大小
    printf("%d\n", sizeof(arr)); //打印结果:40
    //按道理,如果 arr 是首元素地址,那打印结果应该是 4 或 8
    //2. &数组名,这里的数组名也表示整个数组,取出的是整个数组的地址
    printf("%d\n", &arr);
    //数组的地址也是从起始位置开始的
    printf("%d\n", &arr + 1);
    // &arr + 1:会跳过整个数组,这里是40
    // 而 &arr[0] + 1 或 arr + 1 只会跳过1个元素,即4个字节
  return 0;
}



 未使用自定义函数:注意数组名传参的本质)

//输入10个整数,对这组整数进行排序:(未使用自定义函数)
//排序有很多种方法:
//1.  冒泡排序 
//2.  选择排序
//3.  插入排序
//4.  快速排序
//......
#include <stdio.h>
//使用自定义函数
//void bubble_sort(int arr[10]) 
//虽然写成int arr[10],但这里arr的本质是指针,是个指针变量
void bubble_sort(int* arr, int sz)
{
  //直接把数组元素个数sz传进来
  //sizeof(arr):所以这里算的是指针变量的大小即4,不是想要的整个数组大小
  //所以  sz   =    4 / 4 =1
  //int sz = sizeof(arr) / sizeof(arr[0]); //sz=1
  int i = 0;
  for (i = 0; i < sz - 1; i++)
    //sz - 1:10个元素的话只用排9次
  {
    //每趟排几次
    int j = 0;
    for (j = 0; j < sz - 1 - i; j++)
      //sz - 1 - i:第一次排9次,第二次只用排8次……
    {
      if (arr[j] > arr[j + 1])
        //前一个数大于后一个数,进行交换
      {
        //交换,交换两个值时,要有个中间变量
        int tmp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = tmp;
      }
    }
  }
}
int main()
{
  int arr[10] = { 0 };
  int sz = sizeof(arr) / sizeof(arr[0]); //求元素个数
  //输入数组
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    scanf("%d", &arr[i]);
  }
  //排序:冒泡排序,升序
  bubble_sort(arr, sz); 
  //让这个函数来完成数组arr中数据的排序
  //整形数组传参只写地址名就可以了
  //arr作为数组进行了传参,传递的是地址
  //数组传参,传递的是地址,传递的是首元素的地址
  //打印数组
  for (i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}

5578ed39ab99432988c67ba78f427c51.png

(优化:发现有序之后就不一一排序了,在一趟冒泡排序发现两两排序后都没有对调时,说明已经可以停止排序了)

//输入10个整数,对这组整数进行排序:(未使用自定义函数)
//排序有很多种方法:
//1.  冒泡排序 
//2.  选择排序
//3.  插入排序
//4.  快速排序
//......
#include <stdio.h>
//使用自定义函数
//void bubble_sort(int arr[10]) 
//虽然写成int arr[10],但这里arr的本质是指针,是个指针变量
void bubble_sort(int* arr, int sz)
{
  //直接把数组元素个数sz传进来
  //sizeof(arr):所以这里算的是指针变量的大小即4,不是想要的整个数组大小
  //所以  sz   =    4 / 4 =1
  //int sz = sizeof(arr) / sizeof(arr[0]); //sz=1
  int i = 0;
  for (i = 0; i < sz - 1; i++)
    //sz - 1:10个元素的话只用排9次
  {
    //每趟排几次
    int j = 0; 
    // 每一趟开始前就假设已经有序了
    int flag = 1;
    for (j = 0; j < sz - 1 - i; j++)
      //sz - 1 - i:第一次排9次,第二次只用排8次……
    {
      if (arr[j] > arr[j + 1])
        //前一个数大于后一个数,进行交换
      {
        //交换,交换两个值时,要有个中间变量
        int tmp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = tmp;
        flag = 0; // 交换了就说明还是无序的
      }
    }
    //如果没有进入for循环进行交换,说明是有序的,就break停止循环
    if (flag == 1)
    {
      break;
    }
    //这样就不用数组有序了还进行排序
  }
}
int main()
{
  int arr[10] = { 0 };
  int sz = sizeof(arr) / sizeof(arr[0]); //求元素个数
  //输入数组
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    scanf("%d", &arr[i]);
  }
  //排序:冒泡排序,升序
  bubble_sort(arr, sz); 
  //让这个函数来完成数组arr中数据的排序
  //整形数组传参只写地址名就可以了
  //arr作为数组进行了传参,传递的是地址
  //数组传参,传递的是地址,传递的是首元素的地址
  //打印数组
  for (i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}

image.png

9.数组的应用实例1:三子棋

10.数组的应用实例2:扫雷游戏

相关文章
|
17天前
|
程序员 C语言
C语言库函数 — 内存函数(含模拟实现内存函数)
C语言库函数 — 内存函数(含模拟实现内存函数)
27 0
|
28天前
|
编译器 C语言 C++
【C语言】memset()函数(内存块初始化函数)
【C语言】memset()函数(内存块初始化函数)
26 0
|
28天前
|
编译器 C语言 C++
【C语言】memcpy()函数(内存块拷贝函数)
【C语言】memcpy()函数(内存块拷贝函数)
42 0
|
1月前
|
Shell Linux C语言
【Shell 命令集合 磁盘维护 】Linux 创建一个初始化内存盘 mkinitrd命令使用教程
【Shell 命令集合 磁盘维护 】Linux 创建一个初始化内存盘 mkinitrd命令使用教程
35 0
|
5天前
|
编译器 C语言
字符串与内存函数
字符串与内存函数
19 0
|
28天前
|
缓存 Java C#
【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍(一)
【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍
79 0
|
1天前
|
存储 算法
【三种方法】求一个整数存储在内存中二进制中的1的个数附两道课外练习题
【三种方法】求一个整数存储在内存中二进制中的1的个数附两道课外练习题
6 0
|
1天前
|
存储
数据在内存中的存储之整数存储
数据在内存中的存储之整数存储
7 0
|
2天前
|
C语言
C语言:内存函数(memcpy memmove memset memcmp使用)
C语言:内存函数(memcpy memmove memset memcmp使用)