关于数组的基本要点

简介: 关于数组的基本要点



一.一维数组的创建与初始化

1.1 数组的创建

数组是一组相同类型元素的集合。

数组的创建方式:

type_t(是指数组的元素类型 arr_name   [const_n]是一个常量表达式,用来指定数组的大小

#include<stdio.h>
//C99之前数组只能是常量指定大小
//C99之后引用了变长数组概念,数组大小是可以用变量指定的。
int main()
{
  int arr[5];
  int arr2[3 + 2];
  char arr3[8];
  int n = 0;
  scanf("%d", &n);
  int arr4[n];
  return 0;
}

不过vs是不支持用变量来指定大小的。

1.2 数组的初始化

这里面有不完全初始化(剩余元素默认为0) 也有通过ascll码值代替字母  也可以不输入大小,通过内容自动判定。

不过关于字符数组需要注意一点:字符型不会自动放‘\0’,而字符串会。

1.3 一维数组的使用

数组通过下标来访问:

int main()
{
  int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
  int sz = sizeof(arr) / sizeof(arr[0]);
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    printf("%2d ", arr[i]);
  }
  printf("\n");
  //如果想要倒序,也可以改变
  for (i = 0; i < sz; i++)
  {
    arr[i] = 10 - i;
    printf("%2d ", arr[i]);
  }
  return 0;
}

1.4 一维数组在内存中的存储

我们可以通过地址来说明:

int main()
{
  int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
  int sz = sizeof(arr) / sizeof(arr[0]);
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    printf("&arr[%d]=%p\n", i, &arr[i]);
  }
  printf("\n");
  //如果想要倒序,也可以改变
  /*for (i = 0; i < sz; i++)
  {
    arr[i] = 10 - i;
    printf("%2d ", arr[i]);
  }*/
  return 0;
}

可以得出相邻地址之间都相差4个字节(整型元素是4个字节)是连续存放的并随下标增长,地址是低到高的。

二.二维数组的创建与初始化

2.1 二维数组的创建

2.2 二维数组的初始化

//对于二维数组,如果初始化了,对于行数是可以省略的,但是列不能省略
int main()
{
  int arr[3][5] = {0};//不完全初始化
  int arr1[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
  int arr2[][10] = { {1,2},{2,3,4},{5,5,5} };
  return 0;
}

对于二维数组,如果初始化了,对于行数是可以省略的,但是列不能省略。

2.3 二维数组的使用

假想中的二维数组:

通过下标遍历简单访问二维数组

int main()
{
  int i = 0;
  int j = 0;
  int arr[3][5] = { {1,2},{4,5},{6,7,8} };
  for (i = 0; i < 3; i++)
  {
    for (j = 0; j < 5; j++)
    {
      printf("%d ", arr[i][j]);
    }
    printf("\n");
  }
  return 0;
}

我们还可以改变数组:打印1-15

int main()
{
  int i = 0;
  int j = 0;
  int arr[3][5] = { {1,2},{4,5},{6,7,8} };
    for (i = 0; i < 3; i++)
  {
    for (j = 0; j < 5; j++)
    {
      arr[i][j] = i * 5 + j+1;
    }
  }
  for (i = 0; i < 3; i++)
  {
    for (j = 0; j < 5; j++)
    {
      printf("%d ", arr[i][j]);
    }
    printf("\n");
  }
  return 0;
}

2.4 二维数组在内存中的储存

打印一下二维数组的地址:

int main()
{
  int arr[3][5] = { {1,2},{4,5},{6,7,8} };
  int i = 0;
  int j = 0;
  for (i = 0; i < 3; i++)
  {
    for (j = 0; j < 5; j++)
    {
      printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
    }
  }
  return 0;
}

我们会发现所有元素之间都差4个字节,这与我们想的行列图并不一样,而应该是这样:

二维数组在内存中也是连续存放的。

二维数组其实是一维数组的数组。

可以把第一行的数组名看作arr[0],后面的[j]就是一维数组的大小。

三.数组越界

四.数组作为函数参数

冒泡排序基本思想:

int main()
{
  int arr[] = { 10,9,8,7,6,5,4,3,2,1 };
  int sz = sizeof(arr) / sizeof(arr[0]);
  int i = 0;
  int j = 0;
  //趟数
  for (i = 0; i < sz - 1; i++)
  {
    for (j = 0; j < sz - 1 - i; j++)
    {
      if (arr[j] > arr[j + 1])
      {
        int temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }
      else
      {
        break;
      }
    }
  }
  for (i = 0; i < sz ; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}

10个数趟数是9趟,每一趟需要对比交换的次数都会减少,这里用sz-1-i来表示。

4.1 冒泡排序函数的错误设计

void sort(int arr[])
{
  int sz = sizeof(arr) / sizeof(arr[0]);
  int i = 0;
  int j = 0;
  //趟数
  for (i = 0; i < sz - 1; i++)
  {
    for (j = 0; j < sz - 1 - i; j++)
    {
      if (arr[j] > arr[j + 1])
      {
        int temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }
      else
      {
        break;
      }
    }
  }
}
int main()
{
  int arr[] = { 10,9,8,7,6,5,4,3,2,1 };
  sort(arr);
  int i = 0;
  for (i = 0; i < 10; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}

当我们把写好的代码封装到函数时发现出了问题。

没有排序了。

这里就涉及到了数组传参的问题了。

4.2 数组名是什么?

结论:数组名就是数组首元素的地址。

但是有两个意外:1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节。2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址。

通过地址可以发现,首个地址加1只是移动到下一个位,但&arr加1是直接跨越了整个数组的大小。

4.3 冒泡排序函数的正确设计

void sort(int arr[])
{
  int sz = sizeof(arr) / sizeof(arr[0]);
  int i = 0;
  int j = 0;
  //趟数
  for (i = 0; i < sz - 1; i++)
  {
    for (j = 0; j < sz - 1 - i; j++)
    {
      if (arr[j] > arr[j + 1])
      {
        int temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }
      else
      {
        break;
      }
    }
  }
}
int main()
{
  int arr[] = { 10,9,8,7,6,5,4,3,2,1 };
  sort(arr);
  int i = 0;
  for (i = 0; i < 10; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}

sort(arr)不是特殊的两种情况,就是数组的首元素地址,本质上形参用指针接受。所以上述形参中arr[]其实是个指针(当然形参也可以用int *arr),sizeof(arr)(等于4)/sizeof(arr[0])=1,sz=1.

在这种情况下我们可以把sz的求法放在main函数上,因为传的就是地址,接收的就只能是指针,不管怎么算大小都只能是4,所以只能在主函数求出,经过计算再传回去。

void sort(int arr[],int sz)
{
  int i = 0;
  int j = 0;
  //趟数
  for (i = 0; i < sz - 1; i++)
  {
    for (j = 0; j < sz - 1 - i; j++)
    {
      if (arr[j] > arr[j + 1])
      {
        int temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }
      else
      {
        break;
      }
    }
  }
}
int main()
{
  int arr[] = { 10,9,8,7,6,5,4,3,2,1 };
  int sz = sizeof(arr) / sizeof(arr[0]);
  sort(arr,sz);
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}

小疑惑:

也不用对首个元素地址感到奇怪,为什么不传整个数组呢?其实是因为后续有对数组进行遍历,只要知道首个元素的地址,就可以知道后面的地址了,进而遍历得到整个数组。

相关文章
|
7月前
|
C++
第五章:C++中的数组与指针关系
第五章:C++中的数组与指针关系
58 1
|
开发框架 .NET C#
c#数组补充
c#数组的几个简单的补充
42 0
|
5月前
|
存储 算法 搜索推荐
|
6月前
|
开发框架 .NET
技术好文共享:面试题:找出数组中只出现一次的2个数(异或的巧妙应用)(出现3次)
技术好文共享:面试题:找出数组中只出现一次的2个数(异或的巧妙应用)(出现3次)
|
7月前
|
算法 Java 程序员
Java数组全套深入探究——进阶知识阶段4、一维数组练习题
Java数组全套深入探究——进阶知识阶段4、一维数组练习题
61 0
Java数组全套深入探究——进阶知识阶段4、一维数组练习题
|
7月前
|
存储 编译器 C++
第四章:C++中的数组
第四章:C++中的数组
35 1
|
7月前
|
存储 Java 程序员
Java数组全套深入探究——基础知识阶段3、数组下标操作
Java数组全套深入探究——基础知识阶段3、数组下标操作
76 0
|
7月前
|
算法 Java 程序员
Java数组全套深入探究——基础知识阶段4、数组的遍历
Java数组全套深入探究——基础知识阶段4、数组的遍历
68 0
|
7月前
|
存储 传感器 机器学习/深度学习
Java数组全套深入探究——进阶知识阶段6、三维数组以及更多维度数组的概念和用法
Java数组全套深入探究——进阶知识阶段6、三维数组以及更多维度数组的概念和用法
114 0
|
7月前
|
Java 数据处理 计算机视觉
Java数组全套深入探究——进阶知识阶段5、二维数组
Java数组全套深入探究——进阶知识阶段5、二维数组
75 0