乐趣区

关于c:C入门C语言中的数组

Summary

1)数组是 雷同数据类型变量 有序汇合

2)如果未给定数组元素大小,编译器会依据数组元素的个数主动推断数组的大小;数组中前面未被初始化的元素会被主动初始化为 0。

3)数组的 实质是一段间断的内存 ,用于存储数组元素; 数组的大小 能够通过 sizeof 获取,单位:字节;sizeof(arrName)。数组的元素个数:sizeof(arrName) / sizeof(arrName[0])

4)数组的类型由 元素类型 元素个数 决定,示意为type [N]

5)多维数组的 实质依然是一维数组 数组里的每一个元素是数组

6)字符串的实质是一个字符数组

7)C 语言中对字符串或者字符数组的操作,肯定要关注 0 元素('\0' 结束符);如果应用字符数组来模仿字符串变量,肯定记得在最初一个元素后 加上结束符 '\0'

8)字符串字面量的 长度 strLen:结束符 '\0' 之前的所有字符;字符串字面量占用的 内存大小 strSize包含 '\0' 的所有字符。即strSize = strLen + 1;

9)char strcpy(char dst, const char *src); 留神strcpy 的第二个参数必须是一个字符串

1、一维数组

1.1 数组的概念

数组是 雷同数据类型 变量的 有序汇合

  • 数组作为整体须要一个非法的命名(数组名
  • 数组中的 变量 没有独立命名,只有在数组中的编号
  • 数组中的变量数量是固定不变的(数组大小固定

1.2 数组的定义

语法:type Name[size];

int arr[10];  // 定义名为 arr 的数组
              // 数组中一共有 10 个元素(变量)// 每个元素的类型为 int

1.3 数组的拜访

  • 通过 数组名 [下标] 的形式拜访数组
  • 数组是一个有序的汇合,每个元素都有固定的下标
  • 数组元素下标固定从 0 开始(能够应用变量作为下标)
int arr1[3];

arr1[-1] = 0;  // error, 数组下标从 0 开始

arr1[0] = 1;   // ok

arr1[3] = 4;   // error, 数组中一共有 3 个元素,最初一个元素下标为 2, 下标 3 越界了 

留神

  • 只有 整型数 能力作为下标来拜访数组元素
  • 下标越界 是十分重大的谬误
  • 下标越界造成的 严重后果 可能不会立即体现进去

1.4 数组的初始化

语法:type Name[N] = {v0, v1, …, vN-1};
意义:将数组中的元素别离初始化为 v0, v1, …

int main()
{int arr[5] = {2, 4, 6, 8, 10};  // 定义数组 arr 并初始化
    int i = 0;
    
    for(i=0; i<5; i++)
    {printf("arr[%d] = %d\n", i, arr[i]);
    }
    
    return 0;
}

数组初始化技巧

  • 主动确定数组大小
    type Name[] = {v0, v1, ….}; // 编译器会依据初始值的个数主动确认数组的大小
  • 将局部数组元素初始化为 0
    / S<N,未指定初始值的元素默认为 0
    type Name[N] = {v0, v1, …, vS}; // 后面的元素给了初始值,前面没给的都是 0
  • 将所有数组元素初始化为 0
    type Name[N] = {0}; // 同上一点,第一个元素给了 0,前面每给的都是 0

1.5 数组的内存散布

数组再计算机底层是 一片间断的内存,用于存储数组元素

type Name[n] = {v0, v1, ….};
数组的大小:sizeof(Name)
数组的元素个数:sizeof(Name) / sizeof(Name[0])

  • 数组名是一个 右值 ,能够 看做一个常量指针
  • 只能用 整形常量 对数组进行定义,因为要在编译期分配内存
  • 只能用 整形值 作为下标来拜访数组元素

1.6 数组的类型

  • 数组类型由 元素类型 数组大小 独特决定
  • 数组类型的具体表现形式为 type [N]
    int a[10] = {0};    // arrType: int [10]
    float b[5] = {0};   // arrType: float [5]
    int c[10];          // arrType: int [10]

    int i = 0;
    for(i=0; i<10; i++)
        c[i] = a[i];    // 雷同类型数组的“赋值操作”

2、二维数组和多维数组

2.1 二维数组

数组中的元素能够是变量,也能够是其余数组元素(如数组、指针、函数等),当数组中的元素是另一个数组时,就形成了多维数组。
C 语言中的二维数组定义:type Name[N1][N2];二维数组能够看做数学中的矩阵(N1 行 N2 列的矩阵)。

留神:二维数组的 实质依然是一维数组 ,即: 数组中的每一个元素是数组

    int a[3][4];    // 定义一个数组,外面有 3 个元素
                    // 每个元素的类型是 int [4]

    (a[1])[2] = 2;  // 对第 1 个数组中的第 2 个变量赋值

    a[2][3] = 2;    // 对第 2 个数组中的第 3 个变量赋值

    a[3][0] = 0;    // error, index out of bound

二维数组的初始化

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

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

    // 0 0 0
    // 0 0 0
    int a[2][3] = {0};

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

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

留神

  • 二维数组能且仅能让编译器主动确定第一维的大小
  • 第二维大小必须显示给定 ,即: 数组元素的类型必须正确非法
    一个一维数组的类型为:type [size],一维数组的 size 编译器能够推断,但 type 必须确定。对于二维数组 type [size1][size2],大小为 size1,能够推断,但 type 必须明确,即 type [size2] 是必须明确的,所以第二维大小必须确定。
  • 第一维大小主动确定的办法:(初始值个数 除以 第二维大小) 向上取整

      int a[][3] = {1, 2, 3, 4};
      int s1 = sizeof(a) / sizeof(a[0]);   // s1 = 2
      int i = 0;
      int j = 0;
    
      for(i=0; i<s1; i++)
      {for(j=0; j<3; j++)
          {printf("a[%d][%d] = %d\n", i, j, a[i][j]);
          }
      }

练习题:输入矩阵的转置

    int a[3][3] = {1, 2, 3, 4};
    int i = 0;
    int j = 0;

    int arr[3][3] = {0};
    // 转置
    for(i=0; i<3; i++)
    {for(j=0; j<3; j++)
        {if(i == j)
                arr[i][j] = a[i][j];  // 对角线上的值不变
            else
            {arr[j][i] = a[i][j];  // 其余地位变换
            }

        }
    }

2.2 多维数组

三维数组定义:一个数组,每个元素为一个二维数组

  • 语法:type name[n1][n2][n3];

四维数组定义:一个数组,每个元素为一个三维数组

  • 语法:type name[n1][n2][n3][n4];

后续以此类推。

3、字符串和字符数组

3.1 字符数组

字符数组是 非凡的整数 有序汇合(字符的有序汇合),字符数组里的每个元素都是 char 类型的变量,可视化的字符

  • 每个整数占用 1 字节(-128 – 127)
  • 能够用 字符字面量 对数组元素进行初始化和赋值
  • 罕用来存储可浏览的文本信息
    char a[] = {97, 98, 99};          // 应用整数初始化字符数组
    char b[] = {'d', '.', 't', '.'};  // 应用字符字面量初始化字符数组
    int i = 0;

    for(i=0; i<sizeof(a); i++)
        printf("%c", a[i]);    // a b c
    
    printf("\n");

    for(i=0; i<sizeof(b); i++)
        printf("%c", b[i]);    // d . t .

3.2 字符串

字符串的定义:双引号括起来的有序字符集,如 ”hello”
C 语言中:

  1. 没有 专用的字符串类型
  2. 只能通过 字符数组 来模仿字符串变量
  3. 存在 字符串字面量 ,但仅能作为 常量 应用

因而:

  • 字符串变量:应用字符数组来模仿
  • 字符串常量:双引号括起来的有序字符集

字符串中的 0 元素:

  • 整数 0 即字符串中的 0 元素
  • 0 元素对应的字符为 '\0'(转义字符),本义指的是应用反斜杠 ’\’ 转变原来的字符意义,’0’ 字符原来对应的十进制整数值为 48,通过本义后,’\0’ 示意十进制整数 0
  • ‘0’ 与 ’\0’ 不同,字符 '0' 是一个非 0 值,对应十进制整数 48

    printf("%d\n", '0');   // 48
    printf("%d\n", '\0');  // 0

3.2.1“字符串变量”:字符数组

  • C 语言中通过字符数组来 模仿 字符串变量
  • 当字符数组中存在 0 元素时,可当做字符串 来应用
  • 字符数组中的 ’\0’ 示意一个字符串的完结
  • 字符数组中的元素,不肯定是字符串中的元素

    char ss[] = {'c', 'c', '\0', 'j'};  // ss 示意的字符串为 "cc",字符 'j' 在字符数组 ss 中,// 但并不是字符串中的内容
  • 字符数组 能够用字符串常量进行初始化
  • 一个字符数组 不肯定 是一个字符串(看是否蕴含 0 元素'\0');
  • 一个字符串 肯定 是一个字符数组

      char dt[] = "abcd";
      char name[] = {"efg"};  // 加不加 {} 都是等价的
      int ds = sizeof(dt);    // 5
      int ns = sizeof(name);  // 4
    
      printf("dt = %s\n", dt);    // abcd
      printf("ds = %d\n", ds);    // 5
      printf("name = %s\n", name);    // efg
      printf("ns = %d\n", ns);        // 4

3.2.2 字符串操作

C 语言中的“字符串变量”不存在运算操作!
但存在一个字符串“工具包”string.h,提供了一些字符串操作工具,这些工具的实质就是与字符串相干的运算操作。

  • strlen(s) -> 获取字符串的 长度
  • strcpt(s1, s2) -> 将 s2 中的字符复制到 s1,s1 = s2
  • strcat(s1, s2) -> 将 s2 追加到 s1 前面,s1 = s1 + s2
  • strcmp(s1, s2) -> 比拟 s1 和 s2 是否相等,相等时为 0

    #include <stdio.h>      // 申明工具包,要应用外面的输入工具
    #include <string.h>     // 申明工具包,要应用外面的字符串相干工具
    int main()
    {char s[10] = "abcd";
      int size = sizeof(s);
    
      int len  = strlen(s);
    
      printf("size = %d\n", size);    // 10
      printf("len = %d\n", len);      // 4
      
      char in[16] = {0};
      printf("Input a string:");
      scanf("%s", in);    // 输出字符串的时候,scanf 的参数不再须要取地址符 &
      printf("%s\n", in);
    }

应用字符串工具进行 字符串赋值 时:

  • 必须保障赋值后果的字符数组足够大(避免越界)
  • 必须保障参加赋值的字符串必须非法(字符数组存在 0 元素)

3.2.3 字符串练习

  • Demo1:

      char r1[1] = {1};
      int i=0, e=0;
      for(i=0; i<strlen("abcd"); i++)
      {e = "abcd"[i];      // 字符串实质是一个字符数组:char anonymous[5] = "abcd";
                              // "abcd"[i]就相当于 anonymous[i]
    
                              // 再到后续数组与指针的剖析中:数组名代表了数组首元素的地址,// "abcd" 代表了这段内存空间的首地址,能够看做一个常量指针
                              // 而后进行指针运算,*(p+i)<==>p[i],就失去了数组里的每个值
    
          printf("%d", e);  // 97 98 99 100
      }
    
      strcat(r1, "abcd");         // error,r1 中没有 0 元素,不是个字符串。此时后果未定义
      printf("r1 = %s\n", r1);    // undefined
      char r2[10] = "";           // r2 代表的字符串是""
      strcat(r2, "abcd");         // 将 "abcd" 追加到 r1 前面
      printf("r2 = %s\n", r2);    // abcd
  • Demo2:

    char r[2] = {'a', 'b', 0};   // too mant arguments 
                                 // 这样写在 gcc 编译器中能够编译的过,然而有 warning 的
    printf("sizeof(r) = %d\n", sizeof(r));  // 2
  • Demo3:

    // s 的长度是?char s[10] = "\n\\\r";
    
    // 答:题目用一个字符串字面量去初始化一个字符数组,而后问“字符串变量”s 的长度是多少,即
    printf("strlen(s) = %d\n", strlen(s));  // 3,\n 是一个换行符;\\ 是一个反斜杠符 '\';\r 是一个回车符
    
    // 如果问的是 s 的大小,则应该是 sizeof(s) = 10;
  • Demo4:

    // 上面的字符串赋值正确的是:char str1[] = {"string"};
    char str2[6] = {0};
    char str3[8];
    
    A. strcpy(str1, "Delphi");  // ok,字符串拷贝,也没有越界
    B. strcpy(str1, str3);  // error, undefined, str3 不是个字符串(没有蕴含 0 元素)C. strcpt(str2, str1);  // error, undefined, 越界,str2 只有 6 个字节大小,而 str1 须要 7 个字节大小
    D. strcpy(str3, str1);  // ok, 字符串赋值给字符数组
  • Demo5:

    // 写 demo 去掉字符串中的 '\0'
      char s[] = {"abcd\0ef\0gh"};
      int len = sizeof(s) / sizeof(s[0]);
      int i = 0;
      while(i < len)
      {if(s[i] == 0)
          {
              int j = 0;
              for(j=i+1; j<len; j++)
              {s[j-1] = s[j];
              }
              len--;
          }
          else
          {i++;}
      }
      printf("%s\n", s);

本文总结自“狄泰软件学院”唐佐林老师《C 语言入门课程》。
如有错漏之处,恳请斧正。

退出移动版