数组_C语言

定义

数组就是相同数据类型构成的一组数

数组名

  • 数组名的值是一个指针常量(你不能修改常量的值),它是数组第一个元素的地址,他的类型取决于数组元素的类型
  • 数组和指针是不一样的,数组具有确定数量的元素,而指针只是个标量值
  • 指针常量所指向的是内存中数组的起始位置,如果修改这个指针常量,唯一可行的方法就是把整个数组移动到内存的其他位置

只有在两种场合下,数组名并不用指针常量来表示

  1. 当数组名作为sizeof操作符,sizeof返回整个数组的长度,而不是指向数组的指针的长度
  2. 单目操作符&的操作数时,取一个数组名的地址所产生的是一个指向数组的指针,而不是指向某个指针常量值得指针

这两者是等价的

int a[10];

int *c;
c = &a[0];
c = a;

初始化

类型标识符 + 数组名 + 数组元素的个数(常量表达式) + 初始值

int arr[5] = {0};
  • excess element 超过 数组越界
    数组元素不要超过给定的,数组越界有可能导致程序崩溃
    中括号中数组的元素的个数
  • 不能放变量
int arr6[4] = {1,2,3,4,5};
int i = 10;

int arr1[i] = {0};

int arr1[8 + 2] = {0};

int arr2[] = {1,2,3};// 不建议

float arr3[3] = {1.0,2.0,3.0};

double arr4[3] = {2.0,3.0,4.023123};

long arr5[4] = {5345,64563,234};

指针 和 下标

下标

下标和数组名一起使用,用于标识该集合中某个特定的值

int b[10];
*(b+3);

b的值是一个指向整型的指针,*(b+3)所指向的是数组的第1个元素向后移3个整数长度的位置,然后间接访问这个新的位置

除了优先级之外,下标引用和间接访问完全相同

array[subscript];
*(array+(subscript));

关于下标和指针的理解

int array[10];
int *ap = array +2;
指针 转换 下标
ap array + 2 &array[2]
*ap *(array + 2) array[2]
ap[0] *(ap+(0)) = array + 2 &array[2]
ap+6 array + 2 + 6 = array + 8 &array[8]
*ap+6 *(array + 2) + 6 array[2]+6
*(ap+6) *(array 2 + 6) array[8]
ap[6] *(ap+(6)) &array[8]
&ap ap指针所在的地址
ap[-1] *(array+(-1)) array[1]

2[array]相当于*(2+(array))也就是说*(array+2)

  • 有些编译器会有下标检查,但这是一个不小的负担,不过对于如今的电脑而言,并不是个大的问题
  • 指针有时候会比下标更有效率,但不应因为效率而影响程序的可读性

一般有数组的地方就有循环

遍历一个数组 数组下标,从0开始到 数组元素个数-1 为止

    for (int i = 0 ; i < 3; i++) {
        printf("%d\n",arr2[i]);
    }

数组 和 指针

  • 声明一个数组时,编译器将根据声明所指定的元素数量为数组元素保留内存空间,然后在创建数组名,它的值是一个常量,指向这段空间的起始位置.
  • 声明一个指针变量时,编译器只为指针变量保存内存空间,如果它是一个自动变量,它甚至根本不会被初始化
int a[5];
int *b;

上述声明后

  • 表达式*a是完全合法的,但表达式*b是非法的
  • *b将访问内存中某个不确定的位置,或者导致程序终止
  • b++能通过编译,但a++却不能,因为a的值是一个常量

作为函数参数的数组名

当数组名作为参数传递给函数时是指向数组第一个元素指针的拷贝,函数如果执行了下标引用,实际上是对这个指针执行间接访问操作,函数可以访问和修改调用程序的数组元素

以下两个声明只是在当前这个上下文环境中相等

int fun(char *string);
int fun(char string[]);

字符数组 和 字符串

字符数组

char arr[4] = {'a','n','s','d'};
char arr[4] = "ansd";

以下声明,尽管第二个声明看像去是一个字符串常量,实际上并不是

char message[] = "Hello";
char *message2 = "Hello";

以上声明

  • 前者初始化一个字符数组的元素
  • 后者是一个真正的字符串常量,这个指针变量被初始化为指向这个字符串常量的存储位置

输出方法

for (int i = 0; i < 4; i++) {
    printf("%d\t",arr[i]);
    printf("%c\t\n",arr[i]);
}

多维数组

初始化

// 方法一
int matrix[2][3] = {100,101,102,110,111,112};
// 方法二
matric[0][2] = 102;
// 方法三
int matix2[3][5]={
    {00,01,02,03,04},
    {10,11,12,13,14},
    {20,21,22,23,24}
}

存储顺序

int a[12];
int b[3][4];
int c[2][2][3];
数值 int a[12]; int b[3][4]; int c[2][2][3];
0 a[0] b[0][0] c[0][0][0]
1 a[1] b[0][1] c[0][0][1]
2 a[2] b[0][2] c[0][0][2]
3 a[3] b[0][3] c[0][1][0]
4 a[4] b[1][0] c[0][1][1]
5 a[5] b[1][1] c[0][1][2]
6 a[6] b[1][2] c[1][0][0]
7 a[7] b[1][3] c[1][0][1]
8 a[8] b[2][0] c[1][0][2]
9 a[9] b[2][1] c[1][1][0]
10 a[10] b[2][2] c[1][1][1]
11 a[11] b[2][3] c[1][1][2]
// 给数组a赋值
    int *d = a;
    for (int i = 0; i < 12; i++)
    {
        *d = i;
        d++;
    }
// 给数组b赋值
    d = &b[0][0];
    for (int i = 0; i < 12; i++)
    {
        *d = i;
        d++;
    }
// 给数组c赋值
    d = **C;
    for (int i = 0; i < 12; i++)
    {
        *d = i;
        d++;
    }
    // 打印数组a
    for (int i = 0; i < 12; i++)
    {
        cout << "a"<<i<<"="<<a[i] << endl;
        // printf("a[%d] = %d \n", i,a[i]);
    }
    // 打印数组b
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            cout << "b" << i << j <<"=" << b[i][j] << endl;
        }   
    }
    // 打印数组c
    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 2; j++)
        {
            for (int k = 0; k < 3; k++)
            {
                cout << "c" <<i<<j<<k<<"=" <<c[i][j][k] << endl;
            }
        }
    }

数组名

  • 一维数组名得值是一个指针常量,类型:指向元素类型的指针,它指向数组的1个元素
  • 二维数组名的值是一个指向一个包含x个某类型元素的数组的指针
int matrix[2][3];
  • matrix; 类型:指向包含3个整形元素的数组的指针
  • *matrix; 类型:指向整形的指针

下标

array[s2][s1];
*(*(array+(s1))+(s2));

注意:

array[3,4];

相当于

array[4];

逗号操作符首先对第1个表达式求值,但随即丢弃这个值,最后的结果是第2个表达式的值

指向数组的指针

对于一维数组,以下声明是合法的

int vector[10],*vp = vector;

但对于多维数组,以下声明则是非法的

int matrix[3][10],*mp = matrix;

因为matrix并不是一个指向整形的指针,而是一个指向整形数组的指针,其指针声明如下

int (*)p[10];

下标的引用的优先级高于间接访问,但由于括号的存在,首先执行的还是间接访问,接下来执行的是下标引用,所以p指向的是某种类型的数组,对该数组进行下标引用操作得到的是一个整型值,所以p是一个指向整型数组的指针

int (*p)[10] = matrix;

它使p指向matrix的第一行,p是一个指向拥有10个整形元素的数组指针
如果需要一个指针逐个访问整型元素可以进行如下声明

int *pi = &matrix[0][0];
int *pi = matrix[0];

作为参数的多维数组

其实际传递的是指向数组第一个元素的指针,多维数组的每个元素本身是另外一个数组,编译器需要知道它的维数,以便为函数形参的下标表达式求值

int matrix[3][10];
fun(matrix);

参数matrix的类型是指向包含10个整形元素的数组的指针

fun的函数原型如下

void fun(int (*mat)[10]);
void fun(int mat[][10]);

数组长度自动计算

对于多维数组,只有第一维才能根据初始化列表缺省地提供,其他几个维度必须显式地写出

指针数组

int *api[10];
  • 下标引用高于间接访问,所以在这个表达式中,首先执行下标引用,因此api是某类型的数组,其元素个数为10
  • 随后进行间接访问操作,得到一个整形,所以其元素类型为指向整形的指针

例:

以下为一个指针数组

char const keyword[]={
    "do",
    "for",
    "if",
    "register",
    "return";
    "switch"
    "while"
};
#define N_KEYWORD (sizeof(keyword)/sizeof(keyword[0]))

以下则为一个矩阵

char const keyword[][9]={
    "do",
    "for",
    "if",
    "register",
    "return";
    "switch"
    "while"
};

sizeof用于对数组中的元素进行自动计数

  • 通过sizeof来得到数组中元素的个数
  • sizeof(keyword)的结果为整个数组所占用的字节数
  • sizeof(keyword[0])为数组每个元素所占用的字节数
  • 这两个数相除为整个数组的个数

sizeof是字符的大小

int a[] = {1,2,3,4,5};

sizeof(a) / sizeof(int) 数据大小 / 数据类型大小 = 多少个

数组:排序 冒泡排序

冒泡排序是一个双层的for循环 ,外层循环控制的是比较的趟数,内层循环控制的是每次比较的次数

   int arr6[5] = {6,5,4,3,1};
   for(int i = 0; i < 5 - 1; i++) {
       for(intj = 0; j < 5 - i - 1; j++) {
           if(arr6[j] > arr6[j+1]) {
                arr6[j] = arr6[j] ^ arr6[j+1];
                arr6[j+1] = arr6[j] ^ arr6[j+1];
                arr6[j] = arr6[j] ^ arr6[j+1];
            }
        }
    }
   for(int i = 0; i < 5; i++) {
       printf("arry5[%d] is %d\n",i,arr6[i]);
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 一、框架 1、Mac系统及常用工具、进制;C数据类型、常量变量、运算符、表达式、格式化输入输出 2、关系运算符、逻...
    师景福阅读 675评论 0 1
  • C语言大总结 一、基础: 1、进制、位权、1字节等于8位(位是计算机的最小储存单位,字节是计算机最小存储单元)、十...
    雾中探雪阅读 2,815评论 1 36
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 9,500评论 1 51
  • 不觉已近三月末,有多少人还在春困还在沉溺于春日暖阳。然而从开学来,这座南方城市鲜有阳光,同学们戏称自从追了太阳的后...
    炸鸡小公举阅读 149评论 0 0
  • 每一個人 都像是一棵樹 沒有一樣的 每一處森林 散發的氣息 就如同我們居落的村莊 構成千姿百態的生活方式 只是有大...
    蔡振源阅读 530评论 0 5