第五章 数组

  • 数组是一组有序数据的集合。数组中各数据的排列是有一定规律的,下标代表数据在数组中的序号。
  • 用过一个数组名(如s)和下标(如15)来唯一的确定数组中的元素,如s[15]就代表第15个学生的成绩。
  • 数组中的每一个元素都属于同一个数据类型。不能把不同类型的数据(如学生的成绩和学生的性别)放在同一个数组中。
  • 由于计算机键盘只能输入有限的单个字符而无法表示上下标,C语言规定用方括号[]中的数字来表示下标,如用s[15]来表示第15个学会的成绩。

第一节 怎样定义和引用一维数组

  • 一维数组是数组中最简单的,它的元素只需要用数组名加一个下标,就能唯一的确定。

  • 定义一个整型数组,数组名为stud,此数组包含10个整型元素。(使用Visual C++ 会开辟4 * 10 = 40 字节的空间)int stud[10]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bx7EZKM6-1586440159994)(E:\workspace\TyporaProjects\C笔记\网易-C程序设计第四版\images\第五章\5-1-1-内存分配.png)]

  • 定义一维数组的一般形式为类型说明符 数组名[常量表达式]

  • 说明:

      1. 数组名的命名规则和变量名相同,遵循标识符命名规则。
      2. 在定义数组时,需要指定数组中元素的个数,方括号中的常量表达式用来表示元素的个数,即数组的长度。例如,指定stud[10],表示stud数组有10个元素。注意下标是从0开始的,这10个元素是stud[0], stud[1], stud[2], stud[3], stud[4], stud[5], stud[6], stud[7], stud[8], stud[9]。特别注意:按上面的定义,不存在数组元素stud[10]。
      3. 常量表达式中可以包括常量和符号常量,如int stud[3+5];但不能包含变量,如int stud[n]是不合法的。也就是说,C语言不允许对数组的大小做动态定义,即数组的大小不依赖于程序运行过程中变量的值。
  • 练习:对10个数组元素依次赋值为0,1,2,3,4,5,6,7,8,9,要求按逆序输出。

    • #include <stdio.h>
      int main() {
          int a[10], i;
          for (i = 0; i<= 9; i++)
              a[i] = i;
          for (i = 9; i>= 0; i--)
              printf("%d ", a[i]);
          printf("\n");
          return 0;
      }
  • 在定义数组的同时,给各数组元素赋值,称为数组的初始化

    • (1) 在定义数组时,对全部数组元素赋予初值:

        ```c 
      

      int stud [10]={98,99,97,96,95,97,93,90,91,99}
      ```

      ​ 初始化之后,相当于stud[0] =98, stud[1] =99, stud[2] =97, stud[3] =96, stud[4] =95,stud[5] =97, stud[6] =93, stud[7] =90, stud[8] =91, stud[9] =99。

      (2)可以只给数组中的一部分元素赋值:

       int stud[10] ={98,99,97,96}

      定义stud数组有10个元素,但{ }内只提供了4个初值,表示只给前面4个元素赋初始值,系统 自动给后6个元素赋初值为0;相当于stud[0] =98, stud[1] =99, stud[2] =97, stud[3] =96, stud[4] =0,stud[5] =0, stud[6] =0, stud[7] =0, stud[8] =0, stud[9] =0。数值型未被赋值的初始化为0,如果是字符型数组,则初始化为’\0’,如果是指针型数组,则初始化为NULL,即空指针。

      (3) 如果想使一个数组中全部元素值为0,可以写成

       int stud[10] = {0,0,0,0,0,0,0,0,0,0}int stud[10] = {0}

      (4) 在对全部数组元素赋初始值时,由于数据的个数已经确定,因此可以不指定数组长度。例如:

      int stud[10] = {98,99,97,96,95,97,93,90,91,99}int stud[] ={98,99,97,96,95,97,93,90,91,99}

      虽然没有在[ ]指定数组的长度,但是系统会根据花括号中数据的个数确定stud数组有10个元素。

  • 引用数组元素的方法为:数组名[下标]。下标可以是整型常量或整型表达式。

    • 注意:定义数组时用到的数组名[常量表达式]和引用数组元素时用的数组名[下标]形式相同,但是含义不同,例如:
    int a[10]; //前面有int,这是定义数组,指定数组元素包含10个元素
    t = a[6];//这里的a[6]表示引用a数组中序号为6的元素
  • 练习1:对10个数依次赋值为5,6,7,8,9,10,11,12,13,14,逆序打印到屏幕中。

    • #include <stdio.h>
      int main() {
          int i, a[10] = {5,6,7,8,9,10,11,12,13,14};
          for (i = 9; i >= 0; i--)
              printf("%d ", a[i]);
          return 0;
      }
  • 练习2:用数组来处理Fibonacci数列问题。

    #include <stdio.h>
    int main() {
    	int fib[40] = { 1,1 }, i;
    	for (i = 2; i < 40; i++) {
    		fib[i] = fib[i - 1] + fib[i - 2];
    	}
    	for (i = 0; i < 40; i++)
    		printf("%d\t", fib[i]);
    	return 0;
    }
  • 练习3:输入10个地区的面积,要求对它们按由小到大的顺序排列。

    #include <stdio.h>
    int main() {
    	int area[10], i, j, t;
    	printf("输入10个地区的面积:\n");
    	for (i = 0; i <10; i++)
    		scanf("%d", &area[i]);
    	printf("\n");
    	for (j = 0; j < 9; j++)				//进行9次循环,实现9趟比较
    		for (i = 0; i < 9 - j; i++)		//在每一趟中进行9-j次比较
    			if (area[i] > area[i + 1]) {
    				t = area[i];
    				area[i] = area[i + 1];
    				area[i + 1] = t;
    			}
    	printf("排好的顺序为:\n");
    	for (i = 0; i < 10; i++)
    		printf("%d ", area[i]);
    	printf("\n");
    	return 0;
    }

第二节 怎样定义和引用二维数组

  • 二维数组常称为矩阵。把二维数组写成行和列的排列形式,可以有助于形象化地理解二维数组的逻辑结构。

  • 二维数组定义的一般形式为:类型说明符 数组名[常量表达式][常量表达式];

    • 一维学生成绩平均值: int stud[10];

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CsXB2ngu-1586440159995)(E:\workspace\TyporaProjects\C笔记\网易-C程序设计第四版\images\第五章\5-2-1-平均值.png)]

    • 二维学生成绩:

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hjgHftmQ-1586440159995)(E:\workspace\TyporaProjects\C笔记\网易-C程序设计第四版\images\第五章\5-2-2-成绩.png)]

    • 用矩阵形式(如3行4列)表示二维数组,是逻辑上的概念,能形象的表示出行列关系。而在内存中,各元素是连续存放的,不是二维的,是线性的。如:

      int stud[10][3];:10行3列的数组,包含30个int类型的空间

      float a[3][3];:3行4列的数组,包含12个float类型的空间

      float b[5][10];:5行10列的数组,包含50个float类型的空间

  • C语言还允许使用多维数组,例如:

    int a[3][4][5];		//三维数组a,有3页,4列,5行,共包含60个int类型的空间
    • 多维数组元素在内存中的排列顺序为:第1维的下标变化最慢,最右边的下标变化最快。
  • 二维数组的初始化:可以用“初始化列表”对二维数组初始化

      1. 分行给二维数组赋初值,如:

        int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12} };

        这种赋初值方法比较直观,把第1个花括号内的数据赋给第1行的元素,第2个花括号内的数据赋给第2行的元素······即按行赋初值。

      2. 将所有数据写在一个花括号内,按数组元素在内存中的排列顺序对各元素赋初值,如:

         int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};

        缺点:数据多时,则会写成一大片,难以检查,书写容易遗漏。

      3. 可以对部分元素赋初值,例如:

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

        只对各行第1列(序号为0的列)的元素赋初值,其余元素值自动补0。

      4. 如果对全部元素都赋值(即提供全部初始数据),则定义数组时对第1维的长度可以不指定,但第2维的长度不能省,例如:

         int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
        
         int a[ ][4] = {1,2,3,4,5,6,7,8,9,10,11,12};

        系统会根据数据总个数和第2维的长度算出第1维的长度。

  • 二维数组元素的表示形式为:数组名[下标][下标]。在引用数组元素时,下标值应在已定义的数组大小的范围内,例如:

    int a[3][4];	//定义a为3×4的二维数组
    
    a[3][4] = 3;	//不存在a[3][4]元素,a可用的行下标范围为0~2,列下标的范围为0~3
    • 注意:应严格区分在定义数组时用的a[3][4]和引用元素时的a[3][4]的区别。
  • 练习:将一个二维数组行和列的元素互换,存到另一个二维数组中

    #include <stdio.h>
    int main() {
    	int a[2][3] = { {1,2,3},{4,5,6} };
    	int b[3][2], i, j;
    	printf("aray a:\n");
    	for (i = 0; i <= 1; i++) {
    		for (j = 0; j <= 2; j++) {
    			printf("%d ", a[i][j]);
    			b[j][i] = a[i][j];
    		}
    		printf("\n");
    	}
    	printf("array b:\n");
    	for (i = 0; i <= 2; i++) {
    		for (j = 0; j <= 1; j++) {
    			printf("%d ", b[i][j]);
    		}
    		printf("\n");
    	}
    	return 0;
    }

第三节 字符数组

  • 字符型数据是以字符的ASCII代码存储在存储单元中的,一般占一个字节。由于ASCII代码也属于整数形式,因此在C99标准中,把字符类型归纳为整型类型中的一种。

  • C语言中没有字符串类型,也没有字符串变量,字符串是存放在字符型数组中的。

  • 用来存放字符型数据的数组是字符数组,在字符数组中的一个元素内存放一个字符,如:

    char c[10];
    c[0] = 'I'; c[1] = ' '; c[2] = 'a'; c[3] = 'm'; c[4] = ' '; c[5] = 'h'; c[6] = 'a'; c[7] = 'p';c[8] = 'p'; c[9] = 'y'; 

    由于字符型数据是以整数形式(ASCII代码)存放的,因此也可以用整型数组来存放字符数据,例如:

    int c[10] = {'H', 'e', 'l', 'l', 'o'};			//合法,但浪费存储空间
  • 对字符数组初始化,最容易理解的方式是用“初始化列表”,把各个字符依次赋给数组中各元素,例如:

    char c[10] = {'I', ' ', 'a', 'm', ' ', 'h', 'a', 'p', 'p, 'y'};

    把10个数组依次赋给c[0]~c[9]这10个元素。

  • 如果在定义字符数组时步进行初始化,则数组中各元素的值是不可预料的。如果{}中提供的初值个数(即字符个数)大于数组长度,则出现语法错误。如果初值个数小于数组长度,则只将这些字符赋给数组中前面那些元素,其余元素自动定为空字符(即’\0’),例如:

    char c[10] = {'c', ' ', 'p', 'r', 'o', 'g', 'r', 'a', 'm'};
  • 如果提供的初值个数与预定的数组长度相同,在定义时可以省略数组长度,系统会自动根据初值个数确定数组长度,如:

    char c[] = {'I', ' ', 'a', 'm', ' ', 'h', 'a', 'p', 'p, 'y'};

    数组c的长度自动定为10。用这种方式可以不必人工去数字符的个数,尤其在赋初值的字符个数较多时,比较方便。

  • 也可以定义和初始化一个二维字符数组,例如菱形的平面图:

    char diamond[5][5] = {{' ', ' ', '*'},{' ', '*', ' ', '*'},{'*', ' ', ' ', ' ', '*'},{' ', '*', ' ', '*'},{' ', ' ', '*'}};
    • 代码练习:输出一个已知的字符串
    #include <stdio.h>
    int main() {
    	char c[] = { 'I', ' ', 'a', 'm', ' ', 'a', ' ', 's', 't', 'u', 'd', 'e', 'n', 't', '.' };
    	int i;
    	for (i = 0; i < 15; i++)
    		printf("%c", c[i]);
    	printf("\n");
    	return 0;
    }
    • 代码练习:输出一个菱形:
    #include <stdio.h>
    int main() {
    	char diamond[5][5] = { {' ', ' ', '*'},
    	{' ', '*', ' ', '*'},
    	{'*', ' ', ' ', ' ', '*'},
    	{' ', '*', ' ', '*'},
    	{' ', ' ', '*'} };
    	int i, j;
    	for (i = 0; i < 5; i++) {
    		for (j = 0; j < 5; j++) {
    			printf("%c", diamond[i][j]);
    		}
    		printf("\n");
    	}
    	return 0;
    }
  • 字符串和字符串结束标志:在C语言中,是将字符串作为字符数组来处理的,字符串中的字符是逐个存放到数组元素中的,字符串的实际长度与数组长度相等。

  • C语言规定了一个“字符串结束标志”,以字符'\0'作为结束标志。如果字符数组中存有若干字符,前面9个字符都不是空字符('\0'),而第10个字符是'\0',则认为数组中有一个字符串,其有效字符为9个。也就是说,在遇到字符'\0'时,表示字符串结束,把它前面的字符组成一个字符串。

  • 注意:C系统在用字符数组存储字符串常量时会自动加一个'\0'作为结束符。例如"C program"共有9个字符。字符串是存放在一维数组中的,在数组中它占10个字节,最后一个字节'\0'是由系统自动加上的。

  • 在程序中往往依靠检测'\0'的位置来判定字符串是否结束,在定义字符数组时应估计实际字符串长度,保证数组长度始终大于字符串实际长度,如果在一个字符数组中先后存放多个不同长度的字符串,则应使数组长度大于最长的字符串的长度。

    • 说明:'\0'代表ASCII码为0的字符,而且不是一个可以显示的字符,而是一个“空操作符”,即它什么也不做。用它来作为字符串结束标志不会产生附加的操作或增加有效字符,只是起一个供辨别的标志。
    printf("Hello World\n");

    执行此语句,在向内存中存储时,系统自动在最后一个字符'\n'的后面加了一个'\0',作为字符串结束标志。在执行printf函数时,每输出一个字符检查一次,看下一个字符是否为'\0',遇到'\0'就停止输出。

  • 使用字符串常量来使字符数组初始化,如:

    char c[10] = {"good time."}
    char c[] = {"good time."}
    char str[] = "I am happy";//用字符串作为初值

    注意,此时数组str的长度不是10,而是11。因为字符串常量的最后由系统加上一个'\0'

    char str[] = "I am happy";	<==>	char str[] = {'I', ' ', 'a', 'm', ' ', 'h', 'a', 'p', 'p', 'y', '\0'};//长度为11
    char str[] = {'I', ' ', 'a', 'm', ' ', 'h', 'a', 'p', 'p', 'y'};//长度为10
    char c[10] = {"China"};

    数组c的前5个元素为:‘C’, ‘h’, ‘i’, ‘n’, ‘a’,第6个元素为'\0',后4个元素也自动设定为空字符,如:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uta1N0Wb-1586440159996)(E:\workspace\TyporaProjects\C笔记\网易-C程序设计第四版\images\第五章\5-3-1-字符串长度.png)]

    • 字符数组并不要求它的最后一个字符为'\0',甚至可以不包括'\0'。是否需要加'\0',完全根据需要决定。
  • 字符数组的输入和输出有两种方法:

      1. 逐个字符输入输出。用格式符"%c"输入或输出一个字符。
      2. 将整个字符串一次输入或输出。用"%s"格式符,意思是对字符串的输入输出。
    • 注:遇到'\0'就停止输出。

    • 说明:

      • (1)输出的字符中不包含结束符'\0'

        (2)用"%s"格式符输出字符串时,printf函数输出项是字符数组名,而不是数组元素名。

        printf("%s", c[0]);//错误,c[0]不是字符数组名,而是一个数组元素
        prntf("%s", c);

        (3)如果数组长度大于字符串的实际长度,也只输出'\0'前面的数据,例如:

        char c[10] = {"China"};		//字符串长度为5,连'\0'共占6个字节
        printf("%s", c);

        只输出字符串的有效字符"China",而不是输出10个字符。

        (4)如果一个字符数组中包含一个以上'\0',则遇第一个'\0'时输出就结束。

        (5)可以使用scanf函数输入一个字符串,例如:

        scanf("%s", c);//C语言中数组名代表该数组第一个元素的地址,不需要再加地址符。

        scanf函数中的输入项c是已定义的字符数组名,输入的字符串应短于已定义的字符数组的长度。如果利用一个scanf函数输入多个字符串,则应在输入时以空格分隔。

        (6)printf("%s", c);实际上是这样执行的:按字符数组名c找到其数组第一个元素的地址,然后逐个输出其中的字符,直到遇到'\0'为止。

        #include <stdio.h>
        int main() {
            char a[5] = {'h', 'e', 'l', 'l', 'o'};
            printf("%s", a);  //输出结果:hello烫烫烫台溶^狕S
            return 0;
        }

        ​ 采用%s输出,会出现异常的结尾信息,原因是系统找不到'\0'

  • 使用字符串处理函数:C语言提供了一些用来专门处理字符串的函数,使用方便:

      1. puts 函数--输出字符串的函数

        一般形式为:puts(字符数组);。其作用是将一个字符串(以'\0'结束的字符序列)输出到终端,用puts函数输出的字符串中可以包含转义字符,例如:

        char str[] = {"China\nBeijing"};
        puts(str);

        在用puts输出时将字符串结束标志'\0'转换成'\n',即输出完字符串后换行。

      2. gets 函数--输入字符串的函数

        一般形式为:gets(字符数组);。其作用是从终端输入一个字符串到字符数组,并且得到一个函数值。该函数值是字符数组的起始地址,如执行gets(str);,从键盘输入Computer回车,将输入的“Computer”送给字符数组str。注意:送给数组共有9个字符(Computer\0),而不是8个字符,返回的函数值是字符数组str的第一个元素的地址。一般利用gets函数的目的是向字符数组输入一个字符串,而不大关心其函数值。

        注:用puts和gets函数只能输出或输入一个字符串

      3. strcat 函数--字符串连接函数

        一般形式为:strcat(字符数组1, 字符数组2);。其作用是把两个字符数组中的字符串连接起来,把字符串2连接到字符串1的后面,结果放在字符数组1中,函数调用后得到一个函数值----字符数组1的地址,如:

        char str1[30] = {"People's Republic of"};
        char str2[] = {"China"};
        printf("%s", strcat(str1, str2));//输出People's Republic of China

        注意:字符数组1必须足够大,以便容纳连接后面的新字符串;连接前两个字符串的后面都有'\0',连接时将字符串1后面的'\0'取消,只在新字符串最后保留'\0'

      4. strcpy 和 strncpy 函数--字符串复制函数

        一般形式为:strcpy(字符数组1, 字符串2);。它表示“字符串复制函数”,作用是将字符串2复制到字符数组1中去,如:

        char str1[10], str2[] = "China";
        strcpy(str1, str2);

        执行后,str1的状态如下:

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wG8zCMxw-1586440159996)(E:\workspace\TyporaProjects\C笔记\网易-C程序设计第四版\images\第五章\5-3-2-strcpy.png)]

        说明:(1). “字符数组1”必须足够大,以便容纳“字符串2” 。

        (2). “字符数组1”必须写成数组名形式(如str1),“字符串2”可以是字符数组名,也可以是一个字符串常量。

        (3). 如果在赋值前未对str1数组初始化或赋值,则str1中各字节中的内容是无法预知的,复制时将str2中的字符串和其后的'\0'一起复制到字符数组1中,取代字符数组1中的前面6个字符,最后4个字符并不一定是'\0',而是str1中原有的最后4个字节的内容。

        (4). 不能用赋值语句将一个字符串常量或字符数组直接给一个字符数组。字符数组名是一个地址常量,是不能被改变的值。

        (5). 可以用strncpy函数将字符串2中前面n个字符复制到字符数组1中,如:

        strncpy(str1, str2, 2);

        作用是将str2中最前面2个字符复制到str1中,取代str1中原有的最前面的2个字符。但复制的字符个数n不应多于str1中原有的字符(不包括'\0')。

      5. strcmp 函数--字符串比较函数

        一般形式为:strcmp(字符串1, 字符串2);。其作用是比较字符串1和字符串2,如:

        strcmp(str1, str2);
        strcmp("China", "America");
        strcmp(str1, "Beijing");

        说明:字符串比较的规则是:将两个字符串自左至右逐个字符相比(按ASCII码值大小比较),直到出现不同的字符或遇到'\0'为止。如全部字符相同,则认为两个字符串相等;若出现不相同的字符,则以第1个对不相同的字符的比较结果为准,在英文字典中位置在后面的为”大“,应注意小写字母比大写字母大(“A” < “B”, “a” > “A”, “Dog” < “cat”)。

        比较的结果由函数值带回:

        (1)如果字符串1与字符串2相同,则函数值为0。

        (2)如果字符串1>字符串2,则函数值为一个正整数。

        (3)如果字符串1<字符串2,则函数值为一个负整数。

      6. strlen 函数--测字符串长度的函数

        一般形式为:strlen(字符数组);。是测试字符串长度的函数,函数的值为字符串中的实际长度('\0'不包括在内),例如:

        char str[10] = "China";
        printf("%d", strlen(str));	//5

        输出结果不是10,也不是6,而是5。也可以直接测试字符串常量的长度,如:

        strlen("China");
      7. strlwr 函数--转换为小写的函数

        一般形式为:strlwr(字符串);。作用是将字符串中大写字母转换成小写字母。

      8. strupr 函数--转换为大写的函数

        一般形式为:strupr(字符串);。作用是将字符串中的小写字母转换成大写字母。

    • 在使用字符串处理函数时,应当在程序文件的开头用 #include <string.h> 将string.h文件包含到本文件中。

    • 练习:输入一行字符,统计其中有多少个单词,单词之间用空格分开

      #include <stdio.h>
      #include <string.h>
      int main() {
      	char word[100];
      	int i, num = 0;
      	gets(word);
      	for (i = 0; word[i] != '\0'; i++) {
      		if (word[i] == ' ')
      			num++;
      	}
      	printf("输入的字符%s有%d个单词", word, num+1);
      	return 0;
      }
    • 编写代码实现strcpy函数,将s2中的字符全部复制到s1中。

      #include <stdio.h>
      #include <string.h>
      int main() {
      	char str1[100], str2[50];
      	unsigned int i;
      	printf("str1中的原始字符为:%s\n", str1);//乱码
      	printf("请输入要复制的字符:\n");
      	gets(str2);
      	for (i = 0; i <= strlen(str2); i++)
      		str1[i] = str2[i];
      	printf("复制后str1中的字符为%s\n", str2);
      	return 0;
      }
      #include <stdio.h>
      #include <string.h>
      int main() {
      	char str1[100], str2[50];
      	printf("str1中的原始字符为:%s\n", str1);//乱码
      	printf("请输入要复制的字符:\n");
      	gets(str2);
      	printf("复制后str1中的字符为%s\n", strcpy(str1, str2));
      	return 0;
      }
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值