你想知道的数组易错知识都在这了-C

简介: 你想知道的数组易错知识都在这了-C

image.png


最近,想复习一下C语言,所以笔者将会在掘金每天更新一篇关于C语言的文章! 各位初学C语言的大一新生,以及想要复习C语言/C++知识的不要错过哦! 夯实基础,慢下来就是快!


1.数组基本概念


01:数组未给定大小时,是以初始化的个数 确定 数组的大小


int arr[] = {1,2,3};    //数组大小为3
复制代码

image.png

02.数组不完全初始化,剩余的元素初始化为0
int arr[5] = {1,2,3};
复制代码

image.png

03.字符数组是否存放\0的问题
写法1:char arr[] = "abcde"; //数组arr的大小为6 字符串长度为5 含\0
复制代码

image.png


写法2:char arr[] = { 'a','b','c','d','e' };//数组arr的大小为5 并没有放\0进去
复制代码

image.png

04.数组创建不可以即不初始化也不指定大小
int arr[];  //err
复制代码

05:一维数组和指针
int arr[5] = {0};
int *p = arr;
int**pp = &arr;   //数组名是首元素地址,首元素为int类型,&数组名类型为int**类型
*(p+i) == arr[i] == p[i]
复制代码

06:数组越界时的报错--Stack around the variable 'arr' was corrupter

image.png

int main()
{
  int arr[10] = {0};
  printf("%d\n", arr[10]);//这样不会报错,因为只是得到越界的空间的值
  arr[10] = 0;//这样会报错,因为是对越界空间的值的修改
}
复制代码

2.局部变量不初始化和全局变量不初始化

全局变量:放在存放在静态存储区,在程序开始执行时给全局变量分配存储区,程序行完毕就释放。  
    不初始化:默认为0
局部变量:存放在栈区
    不初始化:默认为随机值
复制代码
在数组中的体现

image.png


3.二维数组


01:二维数组的行可以省略,列不可以省略



02:在初始化的情况下才可以省略行,在未初始化时,不可以省略


int arr[][5]; //err
复制代码

03:二维整形数组


int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };  //3行3列
//相当于
//int arr[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
复制代码

image.png



image.png

//二维数组当成一位数组理解
int main()
{
  int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
  int* p = &arr[0][0];
  int i = 0;
  for (i = 0; i < 9; i++)
  {
    printf("%d ",*p);
    p++;
  }
  return 0;
}
复制代码


04:二维字符数组

char arr[3][5] = { "Mango","Lemon","shuai"};
复制代码

image.png


原因:每一个字符串后面都没有放\0

image.png

//正解:
char arr[3][6] = { "Mango","Lemon","shuai"};
复制代码

image.png

image.png

image.png


对于二维字符数组**,列的大小应该取决于存放的最长的字符串的长度+1,不然就放不下\0,造成越界访问!**
如:char arr[3][10] ={"a","abcdefdwo","b"};
复制代码

4.冒泡排序

image.png

10个数字只需要进行 9次冒泡排序即可 
 原因:每一次冒泡排序可以让1个元素来到应该出现的位置,排了9次,搞定9个数字,则剩下的1个必然在应该在的位置上
 每一趟可以少比较一个元素
  10个元素,第一趟比较9对数字,第二趟比较8对.......
复制代码

代码


//交换两个值->传址
void Swap(int* pa, int* pb)
{
  int tmp = *pa;
  *pa = *pb;
  *pb = tmp;
}
void BubbleSort(int* arr, int sz)
{
  int i = 0, j = 0;
    //排序n—1趟
  for (i = 0; i < sz-1; i++)
  {
        //每次排序可以少比较一个元素
    for (j = 0; j < sz - 1 - i; j++)
    {
            //排成升序  即前一个比就一个大
      if (arr[j] > arr[j + 1])
      {
        Swap(&arr[j], &arr[j + 1]);
      }
    }
  }
}
int main()
{
  int arr[10] = { 9,5,6,3,6,7,9,0,3 ,2};
  int sz = sizeof(arr) / sizeof(arr[0]);
  BubbleSort(arr, sz);
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}
复制代码

优化版


优化版冒泡排序:


当第某一趟冒泡排序没有进行交换时,说明已经时有序的了


//交换两个值->传址
void Swap(int* pa, int* pb)
{
  int tmp = *pa;
  *pa = *pb;
  *pb = tmp;
}
void BubbleSort(int* arr, int sz)
{
  int i = 0, j = 0;
    //排序n—1趟
  for (i = 0; i < sz-1; i++)
  {
        int flag = 1;//假设已经有序--
        //要放在for循环内部---每一趟进去都假设有序
        //每次排序可以少比较一个元素
    for (j = 0; j < sz - 1 - i; j++)
    {
            //排成升序  即前一个比就一个大
      if (arr[j] > arr[j + 1])
      {
        Swap(&arr[j], &arr[j + 1]);
                flag = 0;//无序
      }
    }
        //若恒为1,说明已经有序了
        if(flag == 1)
        {
            break;
        }
  }
}
    int main()
    {
        int arr[10] = { 9,5,6,3,6,7,9,0,3 ,2};
        int sz = sizeof(arr) / sizeof(arr[0]);
        BubbleSort(arr, sz);
        int i = 0;
        for (i = 0; i < sz; i++)
        {
            printf("%d ", arr[i]);
        }
        return 0;
    }
复制代码

定义一个标志变量


若此次冒泡排序要进行交换,则说明无序,令flag = 0,


再次进行下一趟冒泡排序时,再令flag=1,继续判断是否要交换,若此次不需要交换了(flag 恒为1),说明已经有序了,break跳出



5.关于数组名的理解


数组名表示整个数组的情况
 1.数组名单独放在sizeof内部,sizeof(数组名)-> 此时数组名表示的是整个数组,此时sizeof(数组名)-计算的是整个数组的大小
 2.&数组名  ->此时数组名表示的是整个数组
复制代码

其余情况下,数组名代表的是数组首元素地址


arr 和 &arr[0] :代表的都是首元素地址

image.png

&arr:代表的是整个数组的地址


指针+1的步长:取决于指针指向数据的类型


&arr+1 :跳过整个数组


&arr[0] + 1 :跳过一个元素,第二个元素地址


arr + 1 :跳过一个元素,第二个元素地址


image.png

数组名再传递给参数的时候,会降级变成首元素地址


数组传参-实际上传过去的是数组首元素地址


void Print(int* arr, int sz)
{
  int i = 0;
  for(i = 0; i < sz; i++)
  {
    //方法1
    //printf("%d ", arr[i]);
    //方法2
    //printf("%d ", *(arr + i));
    //方法3
    printf("%d ", *arr++);
    //等价于-> *arr++ -> 相当于先解引用,再++  *arr; arr++;
        //++的优先级比*高  但由于是后置++,所以*p++可以
  }
}
int main()
{
  int arr[10] = { 9,8,7,6,5,4,3,2,1,0};
  int sz = sizeof(arr) / sizeof(arr[0]);
  Print(arr, sz);
  return 0;
}


相关文章
|
机器学习/深度学习 传感器 人工智能
【仪酷LabVIEW目标检测插件】手把手教你在LabVIEW中使用深度学习实现产品检测(上)
【仪酷LabVIEW目标检测插件】手把手教你在LabVIEW中使用深度学习实现产品检测(上)
726 1
|
计算机视觉 数据格式
使用opencv在Qt控件上播放mp4文件
使用opencv在Qt控件上播放mp4文件
373 2
|
供应链 前端开发
阿里成立数据智能新公司,瓴羊的独立始末
(转载报道媒体:晚点LatePost)推动瓴羊形成的过程中,阿里管理层选择了更激进、整合度更高的方案,选择了多平台、多云的定位。中国互联网发展二十多年,从开放走向封闭,或主动或被动,现在它正重新走向开放,这是大势所趋。
阿里成立数据智能新公司,瓴羊的独立始末
|
10月前
|
JavaScript 开发工具 git
VanBlog:真的太丝滑啦,简洁实用优雅的个人博客系统,支持文章、评论、分类、标签一站式管理,赶紧上车
嗨,大家好,我是小华同学。VanBlog是一个基于Vue3、Vite、NaiveUI和TypeScript的开源博客系统,支持Markdown编辑,具备文章发布、评论、分类、标签、搜索等功能。界面简洁美观,响应式设计适用于各种设备。
263 6
VanBlog:真的太丝滑啦,简洁实用优雅的个人博客系统,支持文章、评论、分类、标签一站式管理,赶紧上车
|
安全 Java 数据安全/隐私保护
有哪些场景不适合使用Java反射机制
Java反射机制虽强大,但并非万能。在性能要求极高、安全性严格控制、类结构复杂多变或对象创建频繁的场景下,使用反射可能带来性能下降、安全风险增加等问题,应谨慎选择。
328 11
|
Cloud Native 持续交付 Docker
云原生技术入门与实践:Docker容器化部署示例
【9月更文挑战第25天】在数字化转型的浪潮下,云原生技术成为推动企业创新的重要力量。本文旨在通过浅显易懂的语言,为初学者揭示云原生技术的核心概念及其应用价值。我们将以Docker容器为例,逐步引导读者了解如何将应用程序容器化,并在云端高效运行。这不仅是对技术趋势的跟随,更是对资源利用和开发效率提升的探索。
210 4
|
设计模式 C# 图形学
Unity 游戏引擎 C# 编程:一分钟浅谈
本文介绍了在 Unity 游戏开发中使用 C# 的基础知识和常见问题。从 `MonoBehavior` 类的基础用法,到变量和属性的管理,再到空引用异常、资源管理和性能优化等常见问题的解决方法。文章还探讨了单例模式、事件系统和数据持久化等高级话题,旨在帮助开发者避免常见错误,提升游戏开发效率。
512 4
|
JavaScript 前端开发
vue全局公共组件自动引入并注册,开发效率直接起飞!
【10月更文挑战第14天】vue全局公共组件自动引入并注册,开发效率直接起飞!
347 1
|
存储 关系型数据库 MySQL
MySQL8 中文参考(二十五)(4)
MySQL8 中文参考(二十五)
244 0
|
Python
在Python中,pandas库的`get_dummies`函数
在Python中,pandas库的`get_dummies`函数
1576 2