C语言中数组的总结

#目录 #

  1. 一维数组的创建和初始化
  2. 一维数组的使用
  3. 一维数组在内存中的存储
  4. 指针的初步介绍
  5. 一维数组的指针访问
  6. 二维数组的创建和初始化
  7. 二维数组的使用
  8. 二维数组在内存中的存储
  9. 二维数组的指针访问
  10. 有关数组的运算
  11. 数组作为函数参数

1.一维数组的创建和初始化

数组的创建:在创建数组时,我们必须定义数组的类型和大小,数组的大小不能为0,数组中的元素类型都是相同的。
eg:

int arr[10];//[]内必须是常量/常量表达式(3+8),不能是一个变量(x...)

数组的初始化:在数组创建时,我们也要必须为数组初始化。
eg:

int arr1[3] = {1, 2, 3};int arr2[] = {1, 2, 3};//在这里,我们arr[3]里边的数字可以不用写;int arr3[3] = {1, 2};//也是可以的,只是把最后一个数初始化为0了而已int arr4[3] = {1, 2, 3, 4};//是不可以的,不能超过数组长度  char arr5[3] = {'a', 98, 'c'};//因为是字符类型,所以98其实就是字符'b'char arr6[] = "abcdef";
#include<stdio.h>int main(){char arr1[] = { 'a', 'b', 'c' };char arr2[4] = "abc";char *p = "abc";//这里只是把a的地址放进了p里边return 0; }

在内存中的存储:

2.一维数组的使用

eg:

#include<stdio.h>int main(){int arr[10] = { 0 };int i = 0;for (i = 0; i < 10; i++)//i<11是不可以的,不可以越界访问{arr[i] = i;}return 0; }

数组是使用下标来访问的,下标是从0开始。
数组的大小可以通过计算得到。(sz = sizeof(arr)/sizeof(arr[0]));

3.一维数组在内存中的存储

eg:

#include<stdio.h>int main(){int arr[10] = { 0 };int i = 0;for (i = 0; i < sizeof(arr)/sizeof(arr[0]); i++){printf("&arr[%d] = %p\n", i, &arr[i]);}return 0; }

从输出结果我们可以看出数组元素在内存中的存储是:地址是由低到高并且是连续存储的。

4. 指针的初步介绍

指针可以理解为一个变量,是一个专门用来存放地址的一个变量。
eg:

int *ptr = NULL;//定义一个整型的指针变量,初始化为NULLchar *ptr = NULL;//定义一个字符的指针变量,初始化为NULL

5. 一维数组的指针访问

eg:

#include<stdio.h>int main(){int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };printf("%p\n", arr);printf("%d\n", *arr);return 0; }

从输出结果我们可以看出数组名其实存放的就是首元素的地址

eg:

int main(){int arr[10] = { 0 };int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);int *p = arr;for (i = 0; i < sz; i++){    //arr[i] = i; (1)*(p + i) = i; (2)}for (i = 0; i < sz; i++){printf("%d\n", arr[i]);//(1)和(2)的输出结果一样}return 0; }

从输出结果我们可以看出,我们定义了一个指针p,指向arr,然后我们通过指针来访问数组。

6. 二维数组的创建和初始化

eg:

#include<stdio.h>int main(){int arr[3][4] = { 1, 2, 3, 4, 5, 6 };//int arr[][4] = {{1, 2},{3, 4, 5},{6}};可以//arr[3][] = {{1, 2},{3, 4, 5},{6}};是不可以的return 0; }

从监视窗口我们可以看到,一行有四个元素,总共有三行,当后边元素没有初始化的时候,全默认为0。

7. 二维数组的使用

二维数组的使用也是通过下标方式
eg:

#include<stdio.h>int main(){int arr[3][5] = { 0 };int i = 0;int j = 0;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; }

8. 二维数组在内存中的存储

我们可以通过打印它的地址来观察它是如何存储的。
eg:

#include<stdio.h>int main(){int arr[3][5] = { 0 };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]);}}return 0; }

我们可以看出数组元素的地址是连续的,并没有进行换行,我们只是把它假想成了三行。

9. 二维数组的指针访问

我们知道了一维数组的内存存储模式之后,我们尝试使用指针对一维数组进行访问,那在这里,我们尝试使用指针来访问我们的二维数组。
eg:

#include<stdio.h>int main(){int arr[3][5] = { 0 };int *p = &arr[0][0];int i = 0;int j = 0;for (i = 0; i < 15; i++){*(p + i) = i + 1;}for (i = 0; i < 3; i++){for (j = 0; j < 5; j++){printf("%d ", arr[i][j]);}}return 0;}

指针也存在类型:
eg:

#include<stdio.h>int main(){int num = 0x11223344;int *p = &num;*p = 0;return 0;}

这里的指针p是int型,所以我们对它的改变,是改变4个字节的大小,同样的,如果我们对p进行加1操作,指针向后跳4个字节。
eg:

#include<stdio.h>int main(){int num = 0x11223344;//int *p = &num;//*p = 0;char *pc = &num;*pc = 0;return 0;}

我们可以从内存中观察到,只改变了1个字节的大小,因为pc指针的类型是char。如果我们对pc进行加1操作,指针向后跳1个字节。
eg:

#include<stdio.h>int main(){int arr[10] = { 0 };printf("%p\n", &arr[0]);printf("%p\n", &arr[0] + 1);printf("---------------\n");printf("%p\n", arr);printf("%p\n", arr + 1);printf("---------------\n");printf("%p\n", &arr);printf("%p\n", &arr + 1);return 0;}

我们可以从输出结果看出&arr[0],arr,&arr它们的地址虽然相同,但它们的意义是不同的,&arr,取的是数组的地址,对它进行加1,就相当于跳过整个数组,又因为数组是int型,总共有10个元素,所以跳过的字节大小是40。

10. 有关数组的运算##

关于数组我们必须要学会有关数组的一些运算。
eg:

#include<stdio.h>int main(){//一维数组int a[] = { 1, 2, 3, 4 };printf("%d\n", sizeof(a));//16  //1.数组名单独放在sizeof内部,数组名表示整个数组,所以sizeof(数组名)计算的是是数组总大小,单位是字节//2.&数组名,数组名表示整个数组,所以&数组名取出的是整个数组的地址//3.除此之外,所有的数组名都表示首元素的地址printf("%d\n", sizeof(a + 0));//4    a代表首元素地址,a+i代表第i个元素的地址,在32位平台下所有的地址的大小都是4个字节printf("%d\n", sizeof(*a));//4       a是首元素地址,*a是首元素--1,int型占4个字节大小printf("%d\n", sizeof(a + 1));//4    a是首元素地址,a+1是第二个元素的地址,它还是一个地址printf("%d\n", sizeof(a[1]));//4     a[1]--第二个元素printf("%d\n", sizeof(&a));//4       &a虽然取出的是整个数组的地址,但它还是一个地址printf("%d\n", sizeof(*&a));//16     &a取出的是整个数组的地址,对它进行解引用,就是这个数组,这个数字的大小就是16printf("%d\n", sizeof(&a + 1));//4   &a取出的是整个数组的地址,加1跳过了整个数组(16个字节),但它还是一个地址printf("%d\n", sizeof(&a[0]));//4    &a[0]取的是第一个元素的地址printf("%d\n", sizeof(&a[0] + 1));//4   &a[0] + 1取的是第二个元素的地址return 0;}
#include<stdio.h>int main(){//字符数组char arr[] = { 'a', 'b', 'c', 'd', 'e', 'f' };printf("%d\n", sizeof(arr));//6printf("%d\n", sizeof(arr + 0));//4        首元素地址printf("%d\n", sizeof(*arr));//1           首元素地址解引用是首元素(a),char类型占1个字节printf("%d\n", sizeof(arr[1]));//1         首元素printf("%d\n", sizeof(&arr));//4           数组的地址printf("%d\n", sizeof(&arr + 1));//4       下一个数组的地址,跳过了fprintf("%d\n", sizeof(&arr[0] + 1));//4    第二个元素的地址    printf("%d\n", strlen(arr));//随机值       strlen()求的是字符串长度,以'\0'为结束标志,这里并没有'\0',所以会一直往后数printf("%d\n", strlen(arr + 0));//随机值   还是从'a'开始数,但没有'\0',所以停不下来printf("%d\n", strlen(*arr));//程序会崩掉  strlen()接收的是一个地址,*arr是字符'a',这里把'a'的ASCII码值(97)作为一个地址访问,这一块的地址是不能被访问的printf("%d\n", strlen(arr[1]));//错误      传的是'b',和传的是'a'效果一样printf("%d\n", strlen(&arr));//随机值      &arr虽然取的是数组的地址,但数组的地址和数组首元素的地址是一样的,也是从‘a'开始数,但并没有'\0'printf("%d\n", strlen(&arr + 1));//随机值  但这个随机值和前边的随机值意义不同,它是把'a','b','c','d','e','f'跳过去了,从f后边开始数printf("%d\n", strlen(&arr[0] +1));//随机值   这个是从'b'开始往后数的return 0;}
#include<stdio.h>int main(){    char arr[] = "abcdef";printf("%d\n", sizeof(arr));//7   里边还有'\0',只不过我们看不到而已printf("%d\n", sizeof(arr + 0));//4     arr+0---首元素地址printf("%d\n", sizeof(*arr));//1   对首元素地址解引用是首元素printf("%d\n", sizeof(arr[1]));//1 第二个元素printf("%d\n", sizeof(&arr));//4    数组的地址也是地址printf("%d\n", sizeof(&arr + 1));//4  也是一个地址,不过这个地址在'\0'后边,跳过了整个数组printf("%d\n", sizeof(&arr[0] + 1));//4   从b开始的一个地址printf("%d\n", strlen(arr));//6   strlen()以'\0'为结束标志,但不算'\0'printf("%d\n", strlen(arr + 0));//6  arr+0与arr都代表首元素地址printf("%d\n", strlen(*arr));//错误   这传进来的不是一个地址,而是一个字符printf("%d\n", strlen(arr[1]));//错误printf("%d\n", strlen(&arr));//6    数组的地址也是首元素地址,地址的位置是一样的printf("%d\n", strlen(&arr + 1));//随机值   跳过了'\0',从'\0'往后数,不知道会数到哪里去printf("%d\n", strlen(&arr[0] + 1));//5    从第二个元素(b)开始往后数,遇到'\0'结束return 0;}
#include<stdio.h>int main(){    char *p = "abcdef";printf("%d\n", sizeof(p));//4   p是指针变量,里边存的是a的地址printf("%d\n", sizeof(p + 1));//4   还是一个地址,不过是指向了b的地址printf("%d\n", sizeof(*p));//1      对a的地址解引用就是aprintf("%d\n", sizeof(p[0]));//1    第一个元素(a)printf("%d\n", sizeof(&p));//4      &p取的是p的地址,p是一个指针,指向a的地址,但p的地址是什么并不知道printf("%d\n", sizeof(&p + 1));//4  &p+1--跳过了p的一个地址printf("%d\n", sizeof(&p[0] + 1));//4   还是一个地址,这个地址指向了b的地址    printf("%d\n", strlen(p));//6        从a开始向后数printf("%d\n", strlen(p + 1));//5    从b开始向后数printf("%d\n", strlen(*p));//错误    *p就是a,strlen()要的是一个地址,而不是a的ASCII码值(97)printf("%d\n", strlen(p[0]));//错误printf("%d\n", strlen(&p));//随机值printf("%d\n", strlen(&p + 1));//随机值printf("%d\n", strlen(&p[0] + 1));//5    从b开始往后数return 0;}
#include<stdio.h>//二维数组int main(){    int a[3][4] = { 0 };printf("%d\n", sizeof(a));//48    整个数组有12个元素,每个元素都是int型printf("%d\n", sizeof(a[0][0]));//4   代表的是第一行第一列那个元素printf("%d\n", sizeof(a[0]));//16   a[0]--第一行数组名,第一行总共有4个元素printf("%d\n", sizeof(a[0] + 1));//4   a[0]降级变为a[0][0]的地址,a[0]+1是a[0][1]的地址printf("%d\n", sizeof(a + 1));//4    a--首元素(第一行)地址,a+1--第二行地址printf("%d\n", sizeof(&a[0] + 1));//4    第二行地址printf("%d\n", sizeof(*a));//16   对第一行地址解引用就是第一行元素printf("%d\n", sizeof(a[3]));//16    这里有好多人会出错,认为这个数组并没有这么大,只有3行,不能访问第4行,其实这里并没有访问第4行,它只是一个类型(1行的大小)return 0;}

11.数组作为函数参数

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

void bubble(int arr[]){    int sz = sizeof(arr)/sizeof(arr[0]);//这是错误的    ...}

数组作为函数参数时,不会把整个数组传递过去,实际上只是把数组的首元素地址传递过去了。

(0)

相关推荐

  • C/C++知识教程:数组

      1. 一维数组的定义及引用 定义 类型说明符 数组名[常量表达式]:复制代码 注意事项 常量表达式的值必须是正整数 数组的起始元素下标为0 一维数组在内存中是如何存放的 存储方式同样从低地址到高地 ...

  • 【C语言笔记】关于数组的一个陷阱!

    问题 两个数组元素的地址相减得到什么? 我们先看一段代码: #include <stdio.h> int main(void) { int a[]={0,1,2,3,4,5}; print ...

  • C语言丨指针和数组的用法,不要再傻傻分不清了

    指针是 C 语言中的一个特点,也是内存地址,是内存单元的编号,指针变量是用来存放内存地址的变量,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也 ...

  • Go 与 C 的指针

    C 和 Go 都是有指针概念的语言,这篇文章主要借这两者之间的异同来加深对 Go 指针的理解和使用. 运算符 C 和 Go 都相同: & 运算符取出变量所在的内存地址 * 运算符取出指针变量所 ...

  • C语言0数组/柔性数组使用介绍

    前言: 我自己在这篇文章下面做了一些回复. 现在我想结合我自己的理解,解释一下这个 char[0] C语言柔性数组的问题. 作者:良知犹存 转载授权以及围观:欢迎关注微信公众号:羽林君 或者添加作者个 ...

  • 初学编程,如何玩转C语言?C语言中最重要的知识献上!

    一.C语言的指针 1.指针说明 指针是包含另一变量的地址变量. (1)int *p p是一个指针,指向一个整形数. (2)int *p() p是一个函数,该函数返回一个指向整数的指针. (3)int ...

  • c语言中结构体成员变量使用“.”符号赋值方法

    在C语言中定义结构体类型的变量时,其内部的成员变量赋值除常规的方法外,也可以通过点号"."进行赋值,如下图所示: 备注:在Linux系统上使用gcc / g++编译器调试通过,其它 ...

  • 注意:你语言中的能量将改变你的命运

    注意:你语言中的能量将改变你的命运 语言中有一种无形的力量,它无时无刻地都在影响着我们自己的生活.大部分人都没有意识到这点. 我们说出来的话是建设生命的基础,我们一直在说话却很少思考自己说话的方式:或 ...

  • R语言中的偏最小二乘回归PLS-DA

    原文链接:http://tecdat.cn/?p=8890 主成分回归(PCR)的方法 本质上是使用第一个方法的普通最小二乘(OLS)拟合来自预测变量的主成分(PC).这带来许多优点: 预测变量的数量 ...

  • 五种爱的语言测试,测试你的爱的语言中哪一种是你在爱情中的弱点

    你首先在这个性格测试中看到的,揭示了五种爱的语言中哪一种是你在爱情中的弱点 如果你有任何约会.爱情和人际关系方面的经验,你就会知道有无数关于自助和心理学的书籍可以在事情没有像你希望的那样顺利进行时指导 ...

  • 逻辑普及:日常语言中的谬误(连载10)

    刘新文老师.万千教育授权发布 哲学园鸣谢 选自<逻辑学基础> 著者:(美)帕特里克·J. 赫尔利(Patrick J. Hurley) 译者:郑伟平,刘新文 出品:万千教育 非形式谬误   ...

  • R语言中进行期权定价的Heston随机波动率模型

    原文链接:http://tecdat.cn/?p=12111 在本文中,我将向您展示如何模拟股票价格的Heston随机波动率模型. Heston模型是一种期权估值方法,它考虑到同一资产在给定时间交易的 ...

  • 0基础学建网站,手把手教会你:网站中数组传递应用,原来如此简单?

    0基础学建网站,手把手教会你:网站中数组传递应用,原来如此简单?