精华内容
下载资源
问答
  • C语言数组

    2020-10-10 14:36:33
    第 11 章数组 11.1 为什么需要数组 一个养鸡场有 6 只鸡,它们的体重分别是 3kg,5kg,1kg, 3.4kg,2kg,50kg 。请问这六只鸡的总体重是多少?平均体重是多少? 请你编一个程序。 传统方案 定义 6 个 double 变量 统计...

    第 11 章数组

    11.1 为什么需要数组

    一个养鸡场有 6 只鸡,它们的体重分别是 3kg,5kg,1kg, 3.4kg,2kg,50kg 。请问这六只鸡的总体重是多少?平均体重是多少? 请你编一个程序。

    传统方案

    1. 定义 6 个 double 变量

    2. 统计他们和,并求出平均值

    3. 传统的方案,不灵活,不能够完成数量大的需求

    4. 引出我们讲解 数组

    11.2 数组介绍

    数组可以存放多个同一类型数据。数组也是一种数据类型,是构造类型。传递是以引用的方式传递(即传递的是地址)

    11.3 数组快速入门

    #include <stdio.h>
    int main() {
    	/*
    	一个养鸡场有 6 只鸡,它们的体重分别是 3kg,5kg,1kg, 3.4kg,2kg,50kg 。请问这六只鸡的总体重是多少?平
    	均体重是多少? 请你编一个程序。
    	*/
    	//1 定义数组
    	double hens[6];
    	double totalWeight = 0.0; 
    	double avgWeight = 0.0; 
    	int i, arrLen;
    	//2. 初始化数组的每个元素
    	//[下标]
    	hens[0] = 3; //第一个元素hens[1] = 5; //第 2 个元素
    	hens[2] = 1;
    	hens[3] = 3.4;
    	hens[4] = 2;
    	hens[5] = 50;
    	
    	//3. 遍历数组
    	//如何得到数组大小
    	//	sizeof(hens)	数组的总的大小
    	//	6 * 8 = 48
    	 
    	//	sizeof(double) 返回 一个 double 占用的字节数
    	//printf("sizeof(hens)=%d", sizeof(hens)); 
    	arrLen = sizeof(hens) /	sizeof(double);
    	for(i = 0; i < arrLen; i++) {
    		totalWeight += hens[i]; // 累计每只鸡体重
    	}
    	avgWeight = totalWeight / 6;
    	printf("总体重 totalWeight=%.2f	平均体重 avgWeight=%.2f", totalWeight, avgWeight); 		getchar();
    
    }
    

    比如,我们可以用数组来解决上一个问题

    11.4 数组定义和内存布局

    11.4.1 数组的定义

    数据类型 数组名 [数组大小];

    int a [5]; // a 数组名,类型 int , [5] 大小, 即 a 数组最多存放 5 个 int 数据赋初值 a[0] = 1; a[1] = 30; …

    说明:

    1. 数组名 就代表 该数组的首地址 ,即 a[0]地址

    2. 数组的各个元素是 连续分布的, 假如 a[0] 地址 0x1122 a[1] 地址= a[0]的地址+int 字节数(4) = 0x1122 + 4 =

    0x1126,后面 a[2] 地址 = a[1]地址 + int 字节数(4) = 0x1126 + 4 = 0x112A, 依次类推

    11.4.3 访问数组元素

    数组名[下标] 比如:你要使用 a 数组的第三个元素 a[2], 下标是从 0 开始计算

    11.4.4 快速入门案例

    从终端循环输入 5 个成绩,保存到 double 数组,并输出

    代码:
        
    #include <stdio.h> 
    int main() {
    	/*
    	从终端循环输入 5 个成绩,保存到 double 数组,并输出
    	*/
    	
    	//定义数组和初始化数组的方式
    	int arr2[3] = {10, 20, 80};
    	//如果在定义时,直接就指定值,可以省略数组大小
    	int arr3[] = {110, 220, 800};
    	//定义一个数组
    	double arr[5];
    	int arrLen = sizeof(arr) / sizeof(double); 
    	int i;
    	for(i = 0; i < arrLen; i++) { 
    		printf("\n 请输入一个小数"); 
    		scanf("%lf", &arr[i]);
    	}
    	
    	//输出整个数组printf("\n======================\n");
    	for(i = 0; i < arrLen; i++) { 
    		printf("arr[%d]=%.2f ", i, arr[i]);
    	}
    	getchar(); //过滤回车getchar();
    
    }
    
    
    输出结果:
         请输入一个小数1.1
    
         请输入一个小数1.2
    
         请输入一个小数1.3
    
         请输入一个小数1.4
    
         请输入一个小数1.5
        arr[0]=1.10 arr[1]=1.20 arr[2]=1.30 arr[3]=1.40 arr[4]=1.50
        --------------------------------
        Process exited after 22.94 seconds with return value 0
        请按任意键继续. . .
    

    11.4.5 3 种初始化数组的方式:

    int arr[10]; //定义长度为10的int类型数组
    
    //定义并初始化数组
    int a[5]={1,2,3,4,5};
    等价于:a[0]=1;  a[1]=2; a[2]=3; a[3]=4; a[4]=5;
    
    //只给一部分元素赋值:int a[5]={6,2,3};
    等价于:  a[0]=6; a[1]=2;a[2]=3; a[3]=0; a[4]=0;int a[3]={6,2,3,5,1};     
    
    //数组元素值全部为0
    int a[5]={0,0,0,0,0};int a[5]={0}; 
    
    
    //对整个数组元素赋初值时,可以不指定长度。
    //编译系统根据初值个数确定数组大小
    int arr[] = {1,2,3,4,5,6,7}; //定义并初始化数组
    

    11.5 数组使用注意事项和细节

    1. 数组是多个相同类型数据的组合,一个数组一旦声明/定义了,其长度是固定的, 不能动态变化。

    2. 数组创建后,如果没有赋值,则遵守如下规则全局数组默认值 0

    非全局数组初值是机器垃圾值(即:原来系统分配给这块空间的值)

    1. 使用数组的步骤 1. 定义数组 2 给数组各个元素赋值 3 使用数组, 也可以一步到位

    2. 数组的下标是从 0 开始的, 不是从 1 开始。

    3. 数组下标必须在指定范围内使用,编译通过,在运行时会因为数组越界而异常中断: 比如 int arr [5] 有效下标为 0-4

    4. C 的数组属构造类型, 是引用传递(传递的是地址),因此当把一个数组传递给一个函数时/或者变量,函数/变量操作数组会影响到原数组. [内存图!!!]

    #include <stdio.h>
    
    
    void f1(int arr[]) {
    	printf("f1 函数中 的 arr 的地址 = %p\n", arr); 
    	arr[0] = arr[0] + 1;
    }
    int main() {
    
    	
    	int arr[3] = {3,4,5}; int i;
    	printf("main 函数中 的 arr 的地址 = %p\n", arr);
    	
    	
    	//数组默认是以 地址传递(传递指针)
    	f1(arr);
    	
    	
    	//遍历 main 函数中的 arr 
    	for(i = 0; i < 3; i++) {
    		printf("arr[%d]=%d \n", i , arr[i]);	// 4,4,5
    	}
    	getchar();
    }
    
    

    内存图:

    在这里插入图片描述

    11.6 数组应用案例

    1. 创建一个 char 类型的 26 个元素的数组,分别 放置’A’-'Z‘。使用 for 循环访问所有元素并打印出来。提示:字符数据运算 ‘A’+1 -> ‘B’
    #include <stdio.h>
    int main(){
    	/*
    	创建一个 char 类型的 26 个元素的数组,分别 放置'A'-'Z'。
    	使用 for 循环访问所有元素并打印出来。提示:字符数据运算 'A'+1 -> 'B'
    	*/
    	char arr[26]; int i;
    	for (i =0; i < 26; i++) { 
    		arr[i] = 'A' + i;
    	}
    	
    	//输出
    	for(i = 0; i < 26; i++ ){ 
    		printf("%c ", arr[i]);
    	}
    	getchar();
    }
    
    1. 请求出一个数组的最大值,并得到对应的下标。
    #include <stdio.h>
    int main(){
    	/*
    	请求出一个数组的最大值,并得到对应的下标分析
    	1. 定义数组 大小 5
    	2. 假定 max = arr[0] 就是最大值,然后我们依次和数组后面的数进行比较,如果发现比 有比 max
    	更大数,就相应的变化(把更大数赋给 max),当我们遍历完整个数组,max 就是最大数
    	*/
    	
    	int arr[] = {0,-1,89, 99, 4,0,23,876, 9876,3,4,6};
    	int arrLen = sizeof(arr) / sizeof(int); int max = arr[0];
    	int maxIndex = 0; int i ;
    	for(i = 1; i <	arrLen; i++) {
    		//如果发现比 有比 max 更大数,就相应的变化(把更大数赋给 max) 
    		if( arr[i] > max) {
    			max = arr[i]; maxIndex = i;
    		}
    	}
    	printf("max=%d maxIndex=%d", max, maxIndex); 
    	getchar();
    }
    

    一维数组程序举例

    例:读10个整数存入数组,找出其中的最大值和最小值

    步骤

    1. 输入:使用for循环输入10个整数

    2. 处理

    (a) 先令max=min=x[0]

    (b) 依次用x[i]和max,min比较(循环)

    若max<x[i],令max=x[i]

    若min>x[i],令min=x[i]

    3. **输出:**max和min

    #include <stdio.h>
    #define SIZE 10
    int main()
    { 
    	int x[SIZE],i,max,min;
        printf("Enter 10 integers:\n");
        for(i=0;i<SIZE;i++){
            printf("%d:",i+1);
        	scanf("%d",&x[i]);
        }
        max=min=x[0];
        for(i=1;i<SIZE;i++){  
       		if(max<x[i])  max=x[i];
         	if(min>x[i])  min=x[i];
        }
        printf("Maximum value is %d\n",max);
        printf("Minimum value is %d\n",min);
    }
    

    5:数组.顺序集合

    假如我们定义了一个长度为 10 的数据,操作系统就会为其分配连续的十个内存地址。
    这些地址用来存放地址,每一个地址所占的字节是数组的数据类型所决定的。
    如int类型的每一个地址占据着4个字节,double类型的8个。

    代码:

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

    输出结果:

    &arr[0] = 6487536
    &arr[1] = 6487540
    &arr[2] = 6487544
    &arr[3] = 6487548
    &arr[4] = 6487552
    &arr[5] = 6487556
    &arr[6] = 6487560
    &arr[7] = 6487564
    &arr[8] = 6487568
    &arr[9] = 6487572
    
    --------------------------------
    
    Process exited after 0.01689 seconds with return value 0
    请按任意键继续. . .
    

    可以注意到各个元素之间的地址相差了4,为啥是4而不是别的呢?这是因为一个我一开始定义的数据类型是int类型的。
    这里补充下内存地址的理解:

    1:内存地址只是一个编号,代表一个内存空间。
    2:内存地址也是内存当中存储数据的一个标识,并不是数据本身,通过内存地址可以找到内存当中存储的数据。<相当于通过你身份证上的地址信息,可以找到你的家乡一样.>
    3:你也可以把计算机内存想象成一条长街上一间间房子,每间房子上面都有且只有一个唯一的编号,房子可以存放数据。

    如这里的首元素的内存编号是 6487536,第二个元素的内存编号是 6487540,
    这里也需要知道一点,这里的编号,只是该数据存放的首地址,只需要知道首地址就可以获取整个地址的值。

    6、数组的越界

    这里讲的数组长度存在一个上界,一旦超过了这个界限会如何?
    前面讲述到了,一旦数组定义完毕,系统就会为其分配它长度大小的空间地址。
    而一旦超过了这个大小,就会发生一些未知的错误,也就是所谓的越界
    这里用一个例子来说明下越界后数组内部的值的情况:

    代码:

    #include<stdio.h>
    int main(){
    	
    	int arr[5] = {1,2,3,4,5};//定义一个长度为5 的数组,并赋初始值
    	for(int i = 0; i < 10; i++) {
    		printf("arr[%d] = %d\n",i,arr[i]);
    	}
    	 
    }
    

    输出结果:

    arr[0] = 1
    arr[1] = 2
    arr[2] = 3
    arr[3] = 4
    arr[4] = 5
    arr[5] = 0
    arr[6] = 1
    arr[7] = 7
    arr[8] = 7410592
    arr[9] = 0
    
    --------------------------------
    Process exited after 0.01397 seconds with return value 0
    请按任意键继续. . .
    

    由运行结果可以知道,当数组的下标超过了上界后,其后面的值都是不确定的。

    11.7 字符数组与字符串

    11.7.1 字符数组基本介绍

    用来存放字符的数组称为字符数组, 看几个案例

    1. char a[10]; //一维字符数组, 长度为 10

    2. char b[5][10]; //二维字符数组, 后面我们详细介绍二维数组

    3. char c[20]={‘c’, ’ ', ‘p’, ‘r’, ‘o’, ‘g’, ‘r’, ‘a’,‘m’}; // 给部分数组元素赋值

    字符数组实际上是一系列字符的集合,也就是字符串(String)。在 C 语言中,没有专门的字符串变量,没有

    string 类型,通常就用一个字符数组来存放一个字符串

    11.7.2 字符串注意事项

    1.   在 C 语言中,字符串实际上是使用 null 字符 ('\0') 终止的一维字符数组。因此,一个以 null 结尾的字符串, 包含了组成字符串的字符。
      
    2.   '\0'是 ASCII 码表中的第 0 个字符,用 NUL 表示,称为空字符。该字符既不能显示,也不是控制字符,输出该字符不会有任何效果,它在 C 语言中仅作为字符串的结束标志。
      

    3) 字符数组(字符串)在内存中的布局分析 [案例]

    在这里插入图片描述

    
    
    1. 思考 char str[3] = {‘a’,‘b’,‘c’} 输出什么? 为什么?

    **结论:**如果在给某个字符数组赋值时,(1)赋给的元素的个数小于该数组的长度,则会自动在后面加 ‘\0’, 表示字符串结束,(2)赋给的元素的个数等于该数组的长度,则不会自动添加 ‘\0’

    char str2[] = {‘t’,‘m’,‘o’} 输出什么? 输出的是 tmo 乱码

    1. 案例演示
    #include <stdio.h>
    int main() {
    	//c 是一个一维字符数组,给部分元素赋值
    	char c[7]={'t','o','m'};
    	char str[5] = {'a','b','c','\0','d'};
    	char str2[] = {'j','a','c','k'}; //  这个后面系统也不会自动添加 '\0'
    	//输出 c ,  系统会这样处理
    	//1. 从第一个字符开始输出,直到遇到 \0 ,  表示该字符串结束
    	printf("\nc=%s", c);
    	printf("\nstr=%s", str); // abc? 
    	printf("\nstr2=%s", str2); // jack 乱码
    	getchar();
    }
    

    11.7.3 字符串的访问和遍历

    因为字符串的本质就是字符数组,因此可以按照数组的方式遍历和访问某个元素即可, 案例如下

    #include <stdio.h>
    #include <string.h> 
    #include <stdlib.h> 
    int main() {
    
    	char greeting[] = "Hello"; 
    	int i;
    	int len	= strlen(greeting); // len = 5 
    	printf("greeting=%s\n", greeting); 
    	printf("len=%d\n", len); //5
    	printf("字符串第 3 个字符是=%c\n", greeting[2]); //l
    	for(i = 0; i < len; i++) {//遍历
    		printf("%c ", greeting[i]); //H e l l o
    	}
    	printf("\n");
    	system("pause");
    }
    

    Ø 对应的内存分析

    在这里插入图片描述

    11.8 字符串的表示形式

    11.8.1 用字符数组存放一个字符串:

    用字符数组存放一个字符串,

    1. char str[]=“hello tom”;

    2. char str2[] = {‘h’, ‘e’};

    11.8.2 用字符指针指向一个字符串

    比如: char * pStr=" hello tom";

    1. C 语言对字符串常量" hello tom"是按字符数组处理的,在内存中开辟了一个字符数组用来存放字符串常量,程序在定义字符串指针变量 str 时只是把字符串首地址(即存放字符串的字符数组的首地址)赋给 pStr

    2. printf("%s\n",str); 可以输出 str 指向的字符串

    3. 对应的内存布局图(!!)

    在这里插入图片描述

    11.8.3 使用字符指针变量和字符数组两种方法表示字符串的讨论

    1. 字符数组由若干个元素组成,每个元素放一个字符;而字符指针变量中存放的是地址(字符串/字符数组的首地

    址),绝不是将字符串放到字符指针变量中(是字符串首地址) [图]

    1. 对字符数组只能对各个元素赋值,不能用以下方法对字符数组赋值
    char str[14];
    str=" hello tom";	//错误
    str[0] = 'i'; //ok
    
    1. 对字符指针变量,采用下面方法赋值, 是可以的
    char* a="yes"; 
    a=" hello tom";
    
    1. 分析上面的结论
      在这里插入图片描述

    2. 如果定义了一个字符数组,那么它有确定的内存地址(即字符数组名是一个常量);而定义一个字符指针变量时, 它并未指向某个确定的字符数据,并且可以多次赋值 [代码+图解]

    11.9 字符串相关函数

    11.9.1 常用字符串函数一览

    在这里插入图片描述

    字符串函数应用案例

    #include <stdio.h> 
    #include <string.h> 
    int main() {
    	char str1[12] = "Hello"; 
    	char str2[12] = "World"; 
    	char str3[12];
    	int len ;
    	/* 复制 str1  到 str3 */
    	strcpy(str3, str1); // str3 内 容 "Hello" 
    	printf("strcpy( str3, str1) :	%s\n", str3 ); //"Hello"
    	/* 连接 str1 和 str2 */ 
    	strcat( str1, str2);
    	printf("strcat( str1, str2):	%s\n", str1 ); //"HelloWorld"
    	/* 连接后,str1 的总长度 */ 
    	len = strlen(str1);//
    	printf("strlen(str1) :	%d\n", len );//10 
    	getchar();
    }
    

    11.10 字符串(字符数组)使用注意事项和细节

    1.   程序中往往依靠检测 '\0' 的位置来判定字符串是否结束,而不是根据数组的长度来决定字符串长度。因此,字符串长度不会统计 '\0', 字符数组长度会统计 [案例]
      
    2.   在定义字符数组时应估计实际字符串长度,保证数组长度始终大于字符串实际长度, 否则,在输出字符数组时可能出现未知字符.
      
    3.   系统对字符串常量也自动加一个'\0'作为结束符。例如"C Program”共有 9 个字符,但在内存中占 10 个字节, 最后一个字节'\0'是系统自动加上的。(通过 sizeof()函数可验证)
      
    4.   定义字符数组时,如果 给的字符个数 比 数组的长度小,则系统会默认将剩余的元素空间,全部设置为 '\0', 比如 char str[6] = "ab" , str 内存布局就是
      
    [a][b][\0][\0][\0][\0]
    
    1. 字符数组定义和初始化的方式比较多,比如
    #include <stdio.h>
    int main() {
    	char str1[ ]={"I am happy"};	//  默认后面加 '\0'
    	char str2[ ]="I am happy"; // 省略{}号 ,默认后面加 '\0'
    	char str3[ ]={'I',' ','a','m',' ','h','a','p','p','y'}; // 字符数组后面不会加 '\0', 可能有乱码
    	char str4[5]={'C','h','i','n','a'}; //字符数组后面不会加 '\0', 可能有乱码
    	char * pStr = "hello";//ok
    	
    	printf("\n str1=%s", str1); 
    	printf("\n str2=%s", str2);//ok 
    	printf("\n str3=%s", str3);//
    	printf("\n str4=%s", str4);//
    	printf("\n");
    	printf("* pStr=%s",pStr);
    	getchar();
    }
    

    12.1 排序算法的介绍

    排序也称排序算法(Sort Algorithm),排序是将一组数据,依指定的顺序进行排列的过程。

    排序的分类:

    1. 内部排序:

    指将需要处理的所有数据都加载到内部存储器(内存)中进行排序。

    1. 外部排序法:

    数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。

    12.2 冒泡排序

    12.2.1 基本介绍

    冒泡排序(Bubble Sorting)的基本思想是:通过对待排序序列从前向后(从下标较小的元素开始),依次比较相邻元素的值,若发现逆序则交换,使值较大

    的元素逐渐从前移向后部,就象水底下的气泡一样逐渐向上冒。

    因为排序的过程中,各元素不断接近自己的位置,如果一趟比较下来没有进行过交换,就说明序列有序,因此要在排序过程中设置 一个标志 flag 判断元素是否进行过交换。从而减少不必要的比较。

    理解:数组中两个数进行比较,较大数放在后面

    优化:

    因为排序的过程中,各元素不断接近自己的位置,如果一趟比较下来没有进行过交换,就说明序列有序,因此要在排序中设置一个标志flag判断元素是否进行过交换。从而减少不必要的比较。

    原始数组:3,9,-1,10,20
    
    第一趟排序
        [1] 3,9,-1,10,20	//如果相邻的元素逆序就交换
        [2] 3,-1,9,10,20
        [3] 3,-1,9,10,20
        [4] 3,-1,9,10,20
    
    第二趟排序
        [1] -1,3,9,10,20
        [2] -1,3,9,10,20
        [3] -1,3,9,10,20
    
    第三趟排序
        [1] -1,3,9,10,20
        [2] -1,3,9,10,20
    
    第四趟排序
        [1] -1,3,9,10,20
        
        
    小结冒泡排序规则:
        (1)一共进行数组的大小-1次大的循环
        (2)每一趟排序的次数在逐渐的减少
        (3)如果我们发现在某趟排序中,没有发生一次交换,就可以提前结束冒泡排序。
    

    12.2.3 分析冒泡的过程+代码

    #include<stdio.h>
    int main(){
    	int arr[10];
    	
    	for(int i = 0; i < 10; i++){
    		scanf("%d",&arr[i]);
    	}
    	
    	printf("排序之前:"); 
    	for(int i = 0; i < 10; i++){
    		printf("%d ",arr[i]);
    	}
    
    	printf("\n"); 
    	
    	for(int i = 0; i < 10; i++){
    		for(int j = 0; j < 10-1;j++){
    			if(arr[j] > arr[j+1]){//如果前面的值大于后面的值,就让这两个数交换在数组中的位置
    				int temp = arr[j];//temp是临时变量
    				arr[j] = arr[j+1];
    				arr[j+1] = arr[j];
    			}
    		}
    	}
    	
    	printf("排序之后:"); 
    	
    	for(int i = 0; i < 10; i++){
    		printf("%d ",arr[i]);
    	}
    }
    

    12.3 查找

    12.3.1 介绍:

    在 C 中,我们常用的查找有两种:

    1. 顺序查找

    2. 二分查找

    12.3.2 案例演示:

    1. 有一个数列:{23, 1, 34,89, 101}

    猜数游戏:从键盘中任意输入一个数,判断数列中是否包含该数【顺序查找】 要求: 如果找到了,就提示找到, 并给出下标值, 找不到提示 没有。

    #include <stdio.h>
    int main() {
    	
    	//分析思路
    	//1. 安装数组进行遍历,一个一个的比较,如果相等,则找到
    	int arr[] = {23, 1, 34,89,101};
    	int arrLen = sizeof(arr) / sizeof(int);
    	int value;
    	scanf("%d",&value);
    	int index = -1;
    	for(int i = 0; i < arrLen; i++) { 
    		if(arr[i] == value) {
    			index = i;
    		}	
    	}
    	if (index != -1) { //找到
    		printf("找到 下标为 %d", index);
    	} else {
    		printf("没有找到");
    	}
    	getchar();
    }
    
    
    1. 请对一个有序数组进行二分查找 {1,8, 10, 89, 1000, 1234} ,输入一个数看看该数组是否存在此数,并且求出下标,如果没有就提示"没有这个数"。二分查找的前提是,该数组是一个有序数组
    #include <stdio.h>
    //二分查找
    int binarySearch(int arr[], int leftIndex, int rightIndex, int findVal) {
       //先找到数组中间这个数 midVal
       int midIndex = (leftIndex + rightIndex) / 2; 
       int midVal = arr[midIndex];
       //如果 leftIndex > rightIndex,  说明这个数组都比较过,但是没有找到
       if( leftIndex > rightIndex) { 
       	return -1;//!!!!
       }
       //如果 midVal >	findVal 说明, 应该在 midVal 的左边查找
       if(midVal > findVal) {
       	binarySearch(arr, leftIndex, midIndex-1, findVal);//!!!
       } else if(midVal < findVal){//如果 midVal <	findVal 说明, 应该在 midVal 的右边查找
       	binarySearch(arr, midIndex+1, rightIndex, findVal);//!!!
       } else {
       	return midIndex; //返回该数的下标
       }
    }
    
    
    int main() {
    //思路分析
    // 比如我们要查找的数是 findVal
    //1. 先找到数组中间这个数 midVal,和 findVal 比较
    //2. 如果 midVal >	findVal 说明, 应该在 midVal 的左边查找
    //3. 如果 midVal <	findVal 说明, 应该在 midVal 的右边查找
    //4. 如果 midVal ==	findVal, 说明找到
    //5. 这里还有一个问题,没有考虑找不到情况
    
    
       int arr[] =	{1,8, 10, 89, 1000, 1234};
       int arrLen = sizeof(arr) / sizeof(int);
       int value;
       scanf("%d",&value);
       int index = binarySearch(arr, 0, arrLen-1, value); 
       
       if(index != -1) {
       	printf("找到 index = %d", index);
       } else {
       	printf("没有找到");
       }
       getchar();
    }
    

    12.4 多维数组-二维数组

    多维数组我们介绍二维数组

    12.5 二维数组的应用场景

    比如我们开发一个五子棋游戏,棋盘就是需要二维数组来表示。

    12.6 二维数组的使用

    12.6.1 快速入门案例:

    请用二维数组输出如下图形

    0 0 0 0 0 0

    0 0 1 0 0 0

    0 2 0 3 0 0

    0 0 0 0 0 0

    12.6.2 使用方式 1: 先定义在初始化

    语法: 类型 数组名[size][size];
    
    比如: int a[2][3];
    

    12.6.3 使用演示

    二维数组在内存的存在形式,各个元素的地址是连续分布的,即在前一个元素基础上+4

    #include <stdio.h>
    int main(){
    	//a[4][6] :  表示一个 4 行 6 列的二维数组
    	int a[4][6]; // 没有初始化,则是分配的内存垃圾值
    	
    	int i, j;
    	//全部初始化 0
    	for(i = 0; i < 4; i++) { //先遍历行
    		for(j = 0; j < 6; j++) {//遍历列
    			a[i][j] = 0;
    		}
    	}
    	
    	
    	a[1][2] = 1;
    	a[2][1] = 2;
    	a[2][3] = 3;
    	//输出二维数组 
    	for(i = 0; i < 4; i++) {
    		for(j = 0; j < 6; j++) { 
    			printf("%d ",	a[i][j]);
    		}
    		printf("\n");
    	}
    	
    	看看二维数组的内存布局
    	printf("\n 二维数组 a 的首地址=%p", a); 
    	printf("\n 二维数组 a[0]的地址=%p", a[0]);
    	printf("\n 二维数组 a[0][0]的地址=%p", &a[0][0]);
    	printf("\n 二维数组 a[0][1]的地址=%p", &a[0][1]);
    	//将二维数组的各个元素得地址输出printf("\n");
    //	for(i = 0; i < 4; i++) {
    //		printf("a[%d]的地址=%p	", i, a[i]); 
    //		for(j=0; j < 6; j++) {
    //			printf("a[%d][%d]的地址=%p	", i, j , &a[i][j]);
    //		}
    //		printf("\n");
    //	}
    	getchar();
    }
    
    
    

    二维数组布局图:

    在这里插入图片描述

    12.6.4 使用方式 2: 直接初始化

    1. 定义 类型 数组名[大小][大小] = {{值 1,值 2…},{值 1,值 2…},{值 1,值 2…}};

    2. 或者 类型 数组名[大小][大小] = { 值 1,值 2,值 3,值 4,值 5,值 6 …};

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

    12.7 二维数组的应用案例

    12.7.1 案例 1

    int arr[3][2]={{4,6},{1,4},{-2,8}};

    遍历该二维数组,并得到和?

    #include <stdio.h>
    int main(){
    int map[3][3] = {
    	{0,0,1},
    	{1,1,1},
    	{1,1,3}
    };
    	//遍历
    	//先得到行
    	//1. sizeof(map)	得到这个 map 数组的大小 9 * 4 = 36
    	//2. sizeof(map[0]) 得到 map 中,第一行有多大 3 * 4 = 12 
    	int rows = sizeof(map) / sizeof(map[0]); // 3
    	/*printf("rows=%d", rows);*/
    	
    	//得到列
    	int cols =	sizeof(map[0]) / sizeof(int); // 12 / 4 = 3 
    	int i,j, sum=0;
    	for(i = 0; i < rows; i++) { 
    		for(j = 0; j < cols; j++) {
    			printf("%d ",map[i][j]);
    			sum += map[i][j];//累计到 sum
    		}
    		printf("\n");
    	}
    	printf("\nsum=%d", sum);
    	getchar();
    }
    

    12.7.4 定义二维数组,用于保存三个班,每个班五名同学成绩,并求出每个班级平均分、以及所有班级平均分

    #include <stdio.h>
    int main(){
    		/*
    	定义二维数组,用于保存三个班,
    	每个班五名同学成绩,并求出每个班级平均分、以及所有班级平均分分析
    	1.	创建一个 scores[3][5]
    	2.	遍历,给赋值
    	3.	再次遍历,统计总分和平均分
    	4.	输出
    	*/
    	
    	double score[3][5]; //
    	int rows = sizeof(score) / sizeof(score[0]), cols = sizeof(score[0])/sizeof(double), i, j; //
    	//classTotalScore 各个班级总成绩 totalScore 所有学生成绩
    	double totalScore = 0.0, classTotalScore = 0.0; 
    	for (i = 0; i < rows; i++ ) {
    		for (j = 0; j < cols ; j++ ) { 
    			score[i][j] = 0.0; //初始化
    		}
    	}
    	
    	//遍历,给每个学生输入成绩
    	for (i = 0; i < rows; i++ ) {
    		for (j = 0; j < cols ; j++ ) {
    			printf("请输入第 %d 个班的	第 %d  个 学生的成绩:", i + 1, j + 1); 
    			scanf("%lf", &score[i][j]);
    		}
    		
    	}
    	
    	getchar();
    	//显示下成绩情况
    	for (i = 0; i < rows; i++ ) {
    		for (j = 0; j < cols ; j++ ) { 
    			printf("%.2f ",score[i][j]);
    		}
    		printf("\n");
    	}
    	//统计各个班的总成绩,和所有学生的总成绩
    	for (i = 0; i < rows; i++ ) {
    		classTotalScore = 0.0; // 每次清 0 
    		for (j = 0; j < cols ; j++ ) {
    			classTotalScore += score[i][j]; //累计每个班的总成绩
    		}
    		printf("\n 第 %d 个班的平均成绩是 %.2f" , i+1,	classTotalScore/cols ); 
    		totalScore += classTotalScore; //将该班级的总分,累计到 totalScore
    	}
    	printf("\n 所有学生总成绩是	%.2f 平均成绩 %.2f" ,totalScore, totalScore/(rows * cols)); 
    	getchar();
    }
    

    12.8 二维数组使用细节和注意事项

    1. 可以只对部分元素赋值,未赋值的元素自动取“零”值【案例】
    #include <stdio.h>
    int main(){
    
    	int a[4][5] = {{1}, {2}, {3},{1}};
    	int i,j;
    	for (i = 0; i < 4; i++ ) {
    		for (j = 0; j < 5 ; j++ ) { 
    			printf("%d ",a[i][j]);
    		}
    		printf("\n");
    	}
    	getchar();
    }
    
    1. 如果对全部元素赋值,那么第一维的长度可以不给出。比如:
    int a[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    可以写为:
    int a[][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    
    1. 二维数组可以看作是由一维数组嵌套而成的;如果一个数组的每个元素又是一个数组,那么它就是二维数组。
    二维数组 a[3][4]可看成三个一维数组,它们的数组名分别为 a[0]、a[1]、a[2]。
    
    
    这三个一维数组都有 4  个元素,如,一维数组 a[0] 的元素为 a[0][0]、a[0][1]、a[0][2]、a[0][3]
    
    展开全文
  • C语言数组与字符串

    2019-04-18 00:15:35
    一、c语言数组 1.C 语言支持数组数据结构,它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。数组可以用一些基本的数据类型来定义,int,double...

    一、c语言数组

    1.C 语言支持数组数据结构,它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。数组可以用一些基本的数据类型来定义,int,double,float...,比如,定义一个整形数组  int a[10],a为数组名,a数组成员共有10个,访问数组可以运用下标访问,数组成员依次为a[0]........a[9]。

    2.数组的初始化

    比如int a[5]={1,2,3,4,5};大括号 { } 之间的值的数目不能大于我们在数组声明时在方括号 [ ] 中指定的元素数目。如果您省略掉了数组的大小,数组的大小则为初始化时元素的个数。int a[]={1,2,3,4,5};这时候计算机会计算出[]里的数值。

     

    3.数组的所有数据都是由连续的内存位置组成,每个数组成员都有一块内存,它们的大小取决于数组类型,比如,开始定义的int型数组每个数组成员所占内存的大小都为4个Byte,即整形数组a[10]所占的内存的大小为40Byte。

    4.数组在处理一些同种数据类型是就比较方便,比如处理一个班所有学生的一项成绩,这时候用数组就比较方便,下面是对一组数据的排序

    5.c语言存在多维数组,上面说的都是一维数组,多维数组可以这样定义,比如定义二维整形数组a[3][3],初始化:{{1,2,3},{4,5,6},{7,8,9}};基本上数组通过循环来进行定义比较方便。多维数组的访问也是用过下标来进行。比如下面:

    二、字符串

    1.在 C 语言中,由但撇号括起来的单个字符叫字符常量,例如'a','b','+','%'...,由双撇号括起来的叫字符串常量,例如"abc","你好",而字符串实际上是使用 null 字符 '\0' 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。下面声明和初始化一个"Hello"的字符串,由于在数组的末尾储存了空字符,所以字符数组的大小比字符"Hello"的字符数多一个。

    char a[6]={'H','e','l','l','o','\0'};

    也可以这样初始化:c编译器会在字符串初始化时自动把'\0'放在字符串的末尾。

    char a[6]="Hello";

    一个字符在内存中占一个字节,字符串里的内存也是连续的,由于字符串末尾会有'\0',所以计算字符串的内存大小时会多一个字节,即上面的字符串a占6个字节。

    2.c语言中有一些操作字符串的函数

    这些函数都包含在string.h的头文件中

    1. strcpy(s1,s2)//复制字符串s2到字符串s1
    2. strcat(s1,s2)//连接字符串s2到字符串s1的末尾,注意字符串s1的长度要足够大来连接字符串s2
    3. strcmp(s1,s2)//用于比较两个字符串,若s1=s2,则返回0,若s1>s2,则返回>0,若s1<s2,则返回<0
    4. strlen(s1)//返回字符串s1的长度

    具体例子如下:

    3.sizeof()与strlen()的区别

    strlen是一个函数,它计算的是字符串的长度,以'\0'作为长度判断的标志,而sizeof是一个运算操作符,计算的是变量的大小,不受'\0'的影响。

    4.'a'与"a"的区别在于' '里只能放单个字符,而" "表示一个字符串即'a'+'\0'。字符串在如下的方式初始化时需要注意结尾必须加'\0',不然就会程序就会出现错误,而用第二种方式不需要加'\0'。

    char a[]={'h','e','l','l','o','\0'};
    char a[]={"hello"};

     

    展开全文
  • 一、什么叫数组数组:顾名思义就是很多数的组合。 特点是:1、这些数的类型都是相同的;2、在数组里面,这些数在内存里是连续储存的,是一组有序数据的集合;3、用一个数组名和下标来唯一地确定数组中的元素。二、...

    一、什么叫数组?

    数组:顾名思义就是很多数的组合。 特点是:1、这些数的类型都是相同的;2、在数组里面,这些数在内存里是连续储存的,是一组有序数据的集合;3、用一个数组名和下标来唯一地确定数组中的元素。

    二、一维数组

    1、一维数组的定义

    一般形式:数据类型 数组名 [ 常量表达式] 例如:定义一个有10个整型元素,名叫a的数组

    int a[10];

    它表示定义了一个整型数组,数组名为 a,定义的数组称为数组a,

    数组名 “a” 除了表示该数组之外,还表示该数组的首地址(关于地址以后讲指针的时候再说)。

    数组长度为10(即:数组a中有10个元素,这里的元素就是变量的意思,在数组上习惯称为元素),

    数组大小是40,因为int型是4个字节,那么10个就4*10=40字节,所以所占的内存空间是40字节,

    而且它们的地址是连续分配的。

    说明:

    (1)数组名的命名规则和变量名的命名规则一致,都是要遵循标识符命名规则。

    (2)在定义数组的时候,需要指定数组的长度(即:元素个数),"[ ]"方括号中的常量表达式

    就是要来表示元素的个数。

    (3)数组下标是从0开始。

    区分:int a[5] 与 a[5]

    第一个是定义一个数组,一个名字叫a的5位的数组,此时该数组中下标最大的是a[4],

    包含的5位分别是:a[0]、a[1]、a[2]、a[3]、a[4] 。

    第二个是一个元素(一个值),数组a中下标为5的元素。

    (4)常量表达式中可以包括 常量 和 符号常量,不能是变量。

    如:int a[5]、int a[5+4]这些是合法的,但int a[n],n是变量,这是不合法的。

    特例:如果数组是在被调用的函数中(不包括主函数),其长度可以是变量或非常量表达式,

    这情况称为“可变长数组”。

    如:调用func函数时,形参n从实参得到值,但在执行时形参的n的值是不变的,

    数组长度是固定的。

    void func(int n)

    {

    int a[2*n];

    }

    (5)若指定数组为静态(static)存储方式,则不能用“可变长数组”。

    如:static int a[2*n]; 这是不合法的。

    2、一维数组的初始化

    初始化: 给各数组元素赋值。 初始化的方法: (1) 对所有元素赋初值(“完全初始化”): 如:int a[5]={1,2,3,4,5}; 初始化过后的效果:a[0]=1,a[1]=2,a[2]=3,a[3]=4,a[4]=5 数组依次将花括号里面的数,从左到右赋值给数组中的每一位元素。

    注意:

    (1)初始化时,花括号里每个值用逗号“,” 隔开。

    (2)若是采用“完全初始化”的方式(即:初始化的个数与数组长度大小是一致的),此时在

    定    义数组的时候可以省略数组长度,    如: int a[]={1,2,3};   因为此时元素的个数

    是已经确定了的,此时数组长度为3.

    特别注意:

    必须定义跟初始化一起写才可以,若是分开,则是不合法的。

    如:int a[];

    a[]={1,2,3};

    这样写是错误的,会提示你没有给数组指定长度。

    (2)只给部分元素赋初值(“不完全初始化”): 如:int a[5]={1,2}; 初始化过后的效果:数组定义了有5个元素,但进行了初始化只有两个,a[0]=1、a[1]=2,后面的三个元素都没有被初始化。

    注意:没有被初始化的元素系统默认给 0 ,若是字符型数组,则系统会默认给“ \0 ”,

    若是指针,则系统会默认给NULL,设置为空指针。

    “完全不初始化”:即只定义“int a[5];” ,没有进行任何的赋值行为。此时要与“不完全初始化”区别开,此时的各元素值并不是0,而是一些无意义的值。

    注意:

    (1) “ int a[5]={}; ”这样写是不合法的,是极其严重的语法错误,大括号中至少需要

    写一个,比如: int a[5]={0}; 这时是让数组中的元素全部置零。

    (2)“  int a[3]={1,2,3,4,5}; ” 赋初值的数量大于数组的长度,这也会产生语法错误,

    是不合法的。

    3、一维数组的引用

    引用格式: 数组名[下标] [下标]: 可以是 常量表达式 或 整形表达式 如:引用数组a给变量sum赋值 sum=a[5]+a[2*3];

    **注意:**  定义数组时用到的格式是:“ 数组名[常量表达式] ”,

    引用数组元素时用到的格式是:“ 数组名[下标] ”,

    两者的区别:

    定义:int a[5];    //这a[5]表示的是定义一个整形数组,数组长度为5个元素

    引用:t=a[6];    //这a[6]表示的是引用数组a下标为6的元素

    三、二维数组(多维数组)

    二维数组:常称为矩阵,可以看成是一种特殊的一维数组,在学习二维数组的时候可以把一个二维数组想象成一个表格,在一维数组的行形式上多加列维度,形成行列的排列形式(先行后列)。 多维数组就在二维数组的基础上延申即可。

    1、二维数组的定义

    定义的形式: 类型说明符 数组名[常量表达式][常量表达式]

    例如:int a[3][4];

    定义了一个名字为a的3x4(3行4列)二维数组

    可以看成是:

    a[0]  ------  a[0][0]     a[0][1]     a[0][2]     a[0][3]

    a[1]  ------  a[1][0]     a[1][1]     a[1][2]     a[1][3]

    a[2]  ------  a[2][0]     a[2][1]     a[2][2]     a[2][3]

    *注意*:

    二维数组的储存方式:

    在c语言中,二维数组中的元素排列的顺序是按行存放的,是线性的,即在内存中先存放完

    第一行所有元素,接着存第二行元素。

    2、二维数组的初始化

    完全初始化:

    方法1: 分行给二维数组赋值。例如:int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};(里面一对花括号代表一行)方法2: 一对花括号过。例如:int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};(按数组元素在内存中的排序顺序对各元素赋值) 以上两种方式的效果都是一样,但个人推荐使用第一种,一一对应,界限清晰,可以避免遗漏。  不完全初始化:

    方法3: 对部分元素赋初值。例如:int a[3][4]={{1},{0,5},{0,2,9}};赋值后的结果:1 0 0 00 5 0 00 2 9 0

    注意:省略第1维的表达方式 (1)当定义的同时采用完全初始化的时候,系统可以根据第2维推算出第1维。 例如:int a[ ][4]={1,2,3,4,5,6,7,8,9,10,11,12};等价于int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; (2)当定义的同时采用分行初始化的时候,系统可以根据花括号推算出第1维。 例如:int a[ ][4]={{0,0,3},{ },{0,10}}

    3、二维数组的引用

    引用格式: 数组名 [下标][下标]

    注意:跟一维数组的方式相同。

    四、字符数组

    1、字符数组的定义

    字符数组的定义与数值型数组的定义方式方法类似,区别在于类型而已 定义格式:char 数组名[常量表达式] 或 char 数组名[常量表达式][常量表达式]

    注意:字符数组也一样存在着二维字符数组的概念,方式方法都一样。

    2、字符数组的初始化

    初始化的方式也是与普通的数值数组没什么大的区别。 数组的一个下标元素位只能存一个字符 例如:用数组a存放" I am happy " char a[10]={‘I’,’ ‘,‘a’,‘m’,’ ',‘h’,‘a’,‘p’,‘p’,‘y’};

    注意:(1)每一个字符都用单引号(' ')来括着;

    (2)没有赋初值的元素的元素系统自动定为空字符(即'\0')。

    3、字符数组的引用

    字符数组的引用格式也是与普通的数值数组没啥两样 引用格式: 数组名[下标] 或 数组名[下标][下标]

    4、字符串

    字符数组实际上是一系列字符的集合,也就是字符串(String)。在C语言中,没有专门的字符串变量,没有string类型,通常就用一个字符数组来存放一个字符串。 在c语言中,可以将字符串直接赋值给字符数组,例如:

    char str[15]={"I am happy."};

    char str[15]="I am happy.";   //可以有花括号{},也可以没有,两者都合法。

    同时,为了方便也可以不指定数组长度,例如:

    char str[]={"I am happy."};

    char str[]="I am happy.";

    所以,通常给字符数组赋值时,我们通常都是使用字符串一次性赋值的方式,而不用单个单个字符来赋值。

    但要注意: (1)字符数组只有在定义的时候进行初始化时才可以利用字符串一次性赋值,一旦定义完,那就只能一个一个字符地赋值。 例如:

    示范1:

    char str[7];

    str = "abc123";  //错误

    //下面是正确

    str[0] = 'a'; str[1] = 'b'; str[2] = 'c';

    str[3] = '1'; str[4] = '2'; str[5] = '3';

    示范2:正确的字符串赋值使用:

    char str[7]="abc123";

    (2)当有效长度相同时,不指定长度的字符串数组与指定长度的字符串数组所占的内存可能会不一致。 如下图,当指定长度的时候所占的字节数就是指定的长度大小,没有指定长度的则是有效长度+1(这1是给“\0”的位置,“\0”的原因下面会讲)。 但要注意的是,虽说没有指定长度可以任意进行初始化,但初始化过后的长度就成了该字符串数组的长度上限。

    注意:

    (1) 单个的字符用单引号'',字符串用双引号" ";

    (2) 字符串的有效长度不一定等于字符数组的长度。

    字符串结束的标志 为了测定字符串的实际长度,C语言规定了“ \0 ”作为“字符串结束标志”。

    '\0'是 ASCII 码表中的第 0 个字符,英文称为 NUL,中文称为“空字符”。该字符既

    不能显示,也没有控制功能,输出该字符不会有任何效果,它在C语言中唯一的作用就是

    作为字符串结束标志。

    C系统在用字符数组存储字符常量时,会自动在最后加一个" \0 "作为结束符。所以才会导致上面所提及到的“有效长度+1”的说法。

    也正因为该结束标志的存在,所以在字符串进行初始化的时候可以省略花括号 “{ }”,不需要借助花括号来表示结束的位置。

    注意: 在输出的时候,但遇到了’\0’时,无论后面还有多少字符都直接结束。 例如:假设下面的表格情况是一个字符串

    Hello\0ram\0

    输出的情况是:Hello

    5、字符数组的 格式化输入输出

    字符数组的输入输出有两种: (1)逐个字符输入输出, 用格式符“ %c ”。 scanf 输入格式:scanf("%c",&数组名[下标]); printf 输出格式:printf("%c",数组名[下标]); (2)整串字符串输入输出, 用格式符“ %s ”。 scanf 输入格式:scanf("%s",数组名); printf 输出格式:printf("%s",数组名);  注意: (1)当采用单个字符数组的方式来输入输出时,系统不会自动在字符串背后加 ’ \0 ‘,当采用字符串的形式时,系统会在末尾结束处加结束标志符’ \0 '。 例: (2)当采用“%s”字符串的形式来输出时,printf函数中的输出项是字符数组名,而不是数组元素名(即:数组名[下标] 的格式)。

    例:正确形式:printf("%s",c);       错误形式:printf("%s",c[0]);

    (3) 如果数组长度大于字符串的实际长度,也是只输出到遇到’\0’结束。

    (4)使用scanf函数进行多个字符串输入时,在输入的时候以空格分隔。如下: 但要注意的是:无法直接读取含有空格的字符串。 由于系统把空格字符作为输入的字符串之间的分隔符,因此当输入一句话的时候,句中有空格,则在输出的时候空格以后的部分不能存到同一个字符串当中。如下:  若想能用scanf函数读取到空格,则需要在格式控制符上下功夫,自己规定格式控制符的内容,具体操作如下: 备注:[ ]内是匹配的字符,^表示求反集,fflush(stdin)

    例一:  例二:  (5)采用输入函数scanf函数时,它的输入项如果是字符数组名,不要再加取地址符&,因为数组名代表的是该数组的起始地址。

    (6)输出函数printf函数的输出原理:按变量名找到其起始地址,然后逐个输出,直到遇到 ’ \0 ’ 为止。

    6、去掉多余的回车方法

    (1)压缩输入法: 在格式码前加上星号“ * ”,则用户就可以告诉scanf()读这个域,但不把它赋予任何变量。 用法: 在格式符的最后处多加%*c,如:scanf("%c%*c, &ch); 使用此方法可以在字符处理时吃掉多余的回车。

    (2)清空缓冲区法: fflush(stdin); 用法:在scanf函数结束后使用,如下:

    char str[10];

    scanf("%s",str);

    fflush(stdin); //清空缓冲区

    1. fflush函数包含在stdio.h头文件中,用来强制将缓冲区中的内容写入文件。 2. 函数原型:int fflush(FILE *stream) ; 3. 函数功能:清除一个流,即清除文件缓冲区,当文件以写方式打开时,将缓冲区内容写入文件。 4. 函数返回值:如果成功刷新,fflush返回0。指定的流没有缓冲区或者只读打开时也返回0值。返回EOF指出一个错误。

    fflush(stdin)刷新标准输入缓冲区,把输入缓冲区里的东西丢弃 (去掉输入时的回车时用这个) fflush(stdout)刷新标注输出缓冲区,把输出缓冲区里的东西打印到标准输出设备上

    std即standard(标准),in即input(输入),out即output(输出)

    (3)将缓冲区东西读出来 1) getchar() 用法:在scanf函数结束后使用,如下:

    char str[10];

    scanf("%s",str);

    getchar(); //将缓冲区东西读出来

    2)gets() 用法:先定义一个字符数组,然后使用gets()函数去把多余的缓冲区内容读出来。

    char str[10],a[5];

    scanf("%s",str);

    gets(a); //将缓冲区东西读出来

    7、字符串处理函数

    1、gets 函数——输入字符串的函数

    格式:gets(字符数组名)

    作用:从终端(如:键盘)输入一串字符串到定义好了的数组中,并得到一个函数值,该函数值是字符数组的起始地址。

    与scanf()函数的区别: (1)对空格的不同处理方式。 scanf() 读取字符串时以空格为分隔,遇到空格就认为当前字符串结束了,所以无法读取含有空格的字符串。 gets() 认为空格也是字符串的一部分,只有遇到回车键时才认为字符串输入结束,所以,不管输入了多少个空格,只要不按下回车键,对 gets() 来说就是一个完整的字符串。换句话说,gets() 用来读取一整行字符串。 (2)输入的数据类型 **scanf():**通过格式控制符来控制输入的数据类型。 **gets():**只能输入字符串,获取回来的数据都是字符类型。 (3)输入变量的个数 scanf(): 可以一次性输入多个变量,且类型可以不一样。 gets(): 每次只能输入一个字符串。 (4)获取了输入后的回车遗留问题 scanf(): 有遗留回车。 gets(): 全部读出,没有遗留回车。

    2、puts 函数——输出字符串的函数

    格式:puts(字符数组名)

    作用:将一个字符串(以‘ \0 ’结束的字符序列)输出到终端(如:屏幕)。

    与printf( )函数的区别: (1)换行问题 printf( ): 不能自动换行,需要在结尾加 \n 。 puts( ): 能自动换行,因为在输出的时候会把字符串结束标志’ \0 ‘转换成’\n’。 (2)输出的数据类型 printf( ): 可以根据格式控制符来控制输出的类型。 puts( ): 只能输出字符串类型。 (3)输出变量的个数 printf( ): 可以一次性输出多个变量,且类型可以不一样。 puts( ): 每次只能输出一个字符串。

    3、strcat 函数——字符串连接函数

    格式:strcat(字符数组1名,字符数组2名) 作用:把两个字符数组中的字符串连接起来,把字符串2接到字符串1后面,结果存放在字符串数组1中,函数返回值是字符数组1的地址。

    注意说明:

    (1)字符数组1必须足够大,足够存入自己本身+字符数组2的总和长度,否则会越界。

    (2)字符数组1在定义的时候不能采用缺省数组长度的形式来定义(如:a[]="china";),

    如果采取该定义初始化方式,则没有足够的空间来存储,因为缺省的定义方式在定义完之后

    长度就定下来了,它的长度就是你所初始化的长度大小。

    (3)连接前两个字符串的后面都有‘\0’,连接时将字符串1后面的‘\0’取消,只在新串最

    后保留'\0'。

    4、strcpy和strncpy 函数——字符串复制函数

    strcpy 函数 格式:strcpy(字符数组1名,字符串2) 作用:将字符数组2复制到字符数组1中去。  strncpy 函数 格式:strncpy(字符数组1名,字符串2,复制的长度n) 作用:将字符串2的最前面的n个之前的字符复制到字符数组1中去。

    注意说明:

    (1)strcpy 函数中,“字符数组1” 必须足够大,以便容纳下“字符串2”;

    strncpy 函数中,“字符数组1” 的长度大小必须大于需要复制的长度大小,若需要复制的

    长度大小大于 “字符串2” 的总长,则把整个字符串2复制完之后,后面剩下的都给NULL;

    (2)两个函数的参数:“字符数组1”必须写成数组名形式,"字符串2" 可以是字符数组名,

    也可以是字符常量。  【如:strcpy(str1,"China"); 或者 strcpy(str1,str2); 】

    (3)若 “字符数组1” 中原本是有字符的,所复制的“字符串2”的长度比“字符数组1”中的

    字符长度少时,这时候会用复制的内容覆盖掉“字符数组1”中前面相应长度的对于位置。

    (4)若想把一个字符串常量或字符数组赋值给另一个字符数组时,这时只能用字符复制函

    数(strcpy函数 和 strncpy函数)或者 用赋值语句一个一个字符进行赋值。

    5、strcmp 函数——字符串比较函数

    格式:strcmp(字符串1,字符串2) 用法:用来比较字符串1和字符串2,

    若两个字符 相同,则函数返回值为0,若字符串1 大于 字符串2,则函数返回大于0的值,若字符串1 小于 字符串2,则函数返回小于0的值。

    字符串比较规则: 将两个字符串自左至右逐个字符相比,按ASCII码值大小来比较,直至出现不同字符或遇到“\0”为止。 若出现不同的字符,则以第一对不同的字符的比较结果为准,来判断大于还是小于。

    注意:两对字符串比较,不能用比较运算符(>、

    6、strlen 函数——测字符串长度的函数

    格式:strlen(字符数组名 或 字符串) 作用:测试字符串长度,函数返回值为字符串的实际长度(也称:有效长度),不包括 ‘ \0 ’在内。

    例如:

    char str[10]="China";

    printf("%d",strlen(str));

    得到的结果是 5 ,而不是10或6.

    也可以测字符串长度,如:strlen("China");

    知识拓展: 对于 sizeof() 的东西太多太复杂了,想详细了解的可以上百度百科查询,我以下的东西大部分都是出至百度百科

    sizeof() 是C语言中用来求一个对象(类型、变量、表达式……)所占内存大小(以字节为单位)的运算符。

    sizeof有两种语法形式,如下:

    sizeof(type_name);//sizeof(类型);

    sizeof object;//sizeof对象;

    例如:

    int i;

    sizeof(i);//ok

    sizeof i;//ok

    sizeof(int);//ok

    sizeof int;//error

    所以,通常为了方便记忆,常采取第一种:sizeof(x)这种带括号的形式 【x可以是 变量、数组、类型、表达式、指针 等等】

    在C语言中,对 sizeof() 的处理都是在 编译阶段进行 ,所以它可以被当作 常量表达式 使用。其 返回值类型为size_t,在头文件stddef.h中定义。这是一个依赖于编译系统的值(意思就是结果的值的大小受操作系统的影响)。

    一般定义的类型为 typedef unsigned int size_t; 【无符号整型%u】

    sizeof计算对象的大小也是转换成对对象类型的计算,也就是说,同种类型的不同对象其sizeof值都是一致的。sizeof对一个表达式求值,编译器根据表达式的最终结果类型来确定大小,一般不会对表达式进行计算。如:

    sizeof(2);//2的类型为int,所以等价于sizeof(int);

    sizeof(2+3.14);

    //3.14的类型为double,2也会被提升成double类型,所以等价于sizeof(double);

    注意:

    (1)函数、不能确定类型的表达式以及位域(bit-field)成员不能被计算sizeof值;

    (2)指针变量的sizeof值与指针所指的对象没有任何关系,在32位系统中,指针变量的

    sizeof通常为4个字节,在64位系统中指针变量的sizeof通常为8。

    (3)数组的sizeof值等于数组所占用的内存字节数。

    (4)与strlen的区别

    a)strlen()函数是求字符串的实际长度,而sizeof()不是实际长度;

    b)sizeof是算符,strlen是函数。

    c)sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''\0''结尾的。

    关于sizeof()的一个易错难题:(这是在百度百科上看到的一到题)

    7、strlwr 函数——转换为小写的函数

    格式:strlwr(字符串) 作用:将字符串中大写字母转换为小写字母。

    8、strupr 函数——转换为大写的函数

    格式:strupr(字符串) 作用:将字符串中小写字母转换为大写字母。

    以上介绍了8种常用字符串处理函数,他们的头文件是:string.h文件,使用时记得导入头文件。 还要强调的是:库函数并非C语言本身的组成部分,而是C语言编译系统为了方便用户使用而提供的公共函数,所以可能会存在函数的数量、函数名、函数功能等差异。

    五、数组的越界溢出

    数组越界: 指数组下标变量的取值超过了初始定义时的大小,导致对数组元素的访问出现在数组的范围之外。

    一般情况下,数组的越界错误主要包括两种:数组下标取值越界与指向数组的指针的指向范围越界,这些问题最常发生在因为循环体的终止条件设定不当而导致的。

    数组的越界溢出所导致的问题就是:1、数据的丢失 ;2、溢出的部分留在缓冲区可能会影响到后面邻接变量的值。

    1、数组下标取值越界

    问题所在: 在访问数组的时候,下标的取值不在定义好的取值范围,访问的是无法获取的内存地址。错误示范如下:

    int a[3],b;

    b=a[3];

    类似这种情况就是数组下标取值越界,因为int a[3]实际上就只有a[0]、a[1]、a[2],

    而并没有a[3]。

    2、指向数组的指针的指向范围越界

    问题所在: 定义数组时会返回一个指向第一个变量的头指针,对这个指针进行加减运算可以向前或向后移动这个指针,进而访问数组中所有的变量。但在移动指针时,如果不注意移动的次数和位置,会使指针指向数组以外的位置,导致数组发生越界错误。错误示范如下:

    int i;

    int *p;

    int a[5];

    /*数组a的头指针赋值给指针p*/

    p=a;

    for(i=0;i<10;i++)  //问题所在:数组只有5个数,但循环控制却后移10次。

    {

    /*指针p指向的变量*/

    *p=i+10;

    /*指针p下一个变量*/

    p++;

    }

    // 所以正确的答案应该是把 i<10 改成 i<5

    避免的方法: (1) 尽量使用显式的方式指定数组的边界(即:int a[10],而少用 int a[ ]),采用显式的方式既清晰显示数组的边界,方便代码的阅读,也方便在对数组进行读写操作时进行相应的检查。 (2) 使用宏定义的形式来指定数组的边界(这也是最常用的指定方式)如:

    #define MAX 10

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

    (3) 可以写一个数组越界检查函数进行处理。

    六、数组的动、静态问题

    动态数组: 【在这先简单提一下,后面讲到相关知识在详细展开来讲】 利用标准库函数中的内存的申请和释放函数,在程序的运行过程中,根据实际需要指定数组的大小,分配的存储空间在堆上。其本质是一个指向数组的指针变量。 常用的内存管理函数有以下三个:

    分配内存空间函数malloc分配内存空间函数 calloc释放内存空间函数free

    静态数组: 在声明时就已经确定大小的数组,即数组元素的个数固定不变,分配的存储空间在栈上,上面一直所提到的都是静态的数组,静态的数组也是最普通形式的数组。 定义的形式:int a[10];

    展开全文
  • C语言数组总结

    2019-02-26 11:29:43
    1、一般形式:类型说明 数组名[常量表达式];例如: int a[10]; 元素为a[0]----a[9]. 2、常量表达式中不允许包含变量,可以包含常量或符号常量。 3、数组元素下标可以是任何整型常量、整型变量或任何整型表达式。 ...

    数组

    定义:数组是有序的并且具有相同类型的数据的集合。

    一维数组

    1、一般形式:类型说明符 数组名[常量表达式];例如: int a[10]; 元素为a[0]----a[9].

    2、常量表达式中不允许包含变量,可以包含常量或符号常量。

    3、数组元素下标可以是任何整型常量、整型变量或任何整型表达式。

    4、可以对数组元素赋值,数组元素也可以参与运算,与简单变量一样使用。

    5、使用数值型数组时,不可以一次引用整个数组,只能逐个引用元素。

    6、需要整体赋值时只可以在定义的同时整体赋值。如

    int a[10]={0,1,2,3,4,5,6,7,8,9};正确。

    int a[10];a[10]={0,1,2,3,4,5,6,7,8,9};错误。

    7、可以只给一部分元素赋值。例如:

    int a[10]={5,8,7,6};后面没有赋值的元素值默认为0。

    8、对全部数组元素赋值时可以不指定数组长度,例如:

    int a[10]={0,1,2,3,4,5,6,7,8,9};可以写成 int a[]={0,1,2,3,4,5,6,7,8,9};

    但是,既不赋初值,也不指定长度是错误的。例如:int a[];错误。

    二维数组

    1、一般形式:类型说明符 数组名[常量表达式1][常量表达式2];例如:

    int a[3][4];可以看成是包含3个一维数组,每个一维数组里包含4个元素。一共3*4=12个元素。 所有元素为 a[0][0],a[0][1],a[0][2],a[0][3]

    a[1][0],a[1][1],a[1][2],a[1][3]

    a[2][0],a[2][1],a[2][2],a[2][3]

    2、与一维数组一样元素下标可以是是任何整型常量、整型变量或任何整型表达式。

    3、需要整体赋值时只可以在定义的同时整体赋值。例如:

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

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

    4、可以把所有数据写在一个花括号内。例如:

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

    5、可以只对部分元素赋值。例如:

    int a[3][4]={{1},{5},{9}};其余未赋值的元素默认为0。

    int a[3][4]={{1},{5,6}};可以看成是int a[3][4]={{1,0,0,0},{5,6,0,0},{0,0,0,0}};

    6、对全部数组元素赋值时可以省略第一维长度,第二维不可以省略。例如:

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

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

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

    字符数组

    1、定义:char a[10];字符数组a长度为10。每个元素只能存放一个字符。例如:

    a[0]=‘h’;a[1]=‘a’;a[2]=‘p’;

    2、初始化:

    char a[]={‘h’,‘a’,‘p’,‘p’,‘y’};

    char a[]=“happy”;

    char a[]={“happy”}; 注意,因为字符串结尾自动加’\0’,所以char a[]=“happy”;长度为6,不是5。

    3、C语言中没有字符串变量,字符串的输入、存储、处理和输出等必须通过字符数组实现。

    4、字符串的输入。

    scanf();可以用%C逐个字符输入比如char a[6];for(i=0;i<6;i++) scanf("%c",&a[i]);

    可以用%S以字符串的形式输入,比如char a[6];scanf("%s",a);注意,a前不用加&,因为a是数组名,

    已经代表了数组首地址。

    注意:以%S输入时,以第一个非空白字符开始,终止于第一个空白字符。比如:输入How are you

    时。只输出How.

    gets();作用为输入一个字符串。与scanf();功能一致,但空格和回车都存放在数组中,最后自动加入‘\0’.

    不会出现上面输出不全的情况。

    调用方式为:gets(数组名);需要包含头文件“stdio.h”.

    5、字符串的输出。

    printf();可以使用%c逐个字符输出,比如:char a[6];for(i=0;i<6;i++) printf("%c",a[i]);

    可以用%S以字符串的形式输出,比如char a[6];printf("%s",a);

    puts();输出一个字符串,结尾自动换行。

    调用形式:puts(字符数组名或字符串常量);需包含头文件“stdio.h”

    常用字符串处理函数(以下函数需要头文件“string.h”)

    1、strlen()作用是测试字符串长度。这里不包括‘\0’.使用形式strlen(数组名或字符串常量)

    2、strcat()作用是连接两个字符串。调用方式strcat(字符数组1名,字符数组2名);合并后的字符串存放在字

    符数组1中。

    3、strcmp()比较两个字符串是否相等。调用方式strcmp(字符串1,字符串2);相等时值为0。1>2时为正数。

    1<2时为负数。

    4、strcpy()复制字符串。调用方式strcpy(字符数组1,字符串2);2的内容复制到1中。1只能是字符数组名。

    展开全文
  • C语言数组属于构造数据类型。一个数组可以分解为多个数组元素,这些数组元素可以是基本数据类型或是构造类型。因此按数组元素的类型不同,数组又可分为数值数组、字符数组、指针数组、结构数组等各种类别。一维数组...
  • C语言数组知识点

    千次阅读 2018-12-19 23:23:45
    1,数组的创建:在创建数组时,我们必须定义数组的类型和大小,数组的大小不能为0,数组中的元素类型都是相同的。 2,一堆数组的使用, int arr[10] = { 0 }; int i = 0; for (i = 0; i &lt; 10; i++)//i&...
  • C语言数组的学习

    2015-05-13 17:30:00
    C语言中,数组属于构造数据类型。一个数组可以分解为多个数组元素,这些数组元素可以是基本数据类型或是构造类型。因此按数组元素的类型不同,数组又可分为数值数组、字符数组、指针数组、结构数组等各种类别。 ...
  • (转载)深入解析C语言数组和指针 原文地址:https://www.cnblogs.com/maluning/p/7955648.html 概述  指针是C语言的重点,同时也是让初学者认为最难理解的部分。有人说它是C语言的灵魂,只有深入...
  • C语言数组知识点梳理

    2020-03-14 21:49:18
    数组声明之后变为常量,不能放在等号左边;初值表{…}只能用于初始化。 数组元素只能逐个进行引用,不能一次性引用。 数组越界的危害: (1)会覆盖其他变量的值(越界短时) (2)会出现段错误(越界过长) a+i==&a...
  • 关注、星标公众号,直达精彩内容ID:技术让梦想更伟大作者:李肖遥所谓的数组越界,简单地讲就是指数组下标变量的取值超过了初始定义时的大小,导致对数组元素的访问出现在数组的范围之外,这类错误...
  • C语言数组知识小结

    2018-11-21 23:40:34
    整型,字符型,浮点型数据,这些只是简单的数据类型。对于简单的问题,使用这些简单的数据就可以了。但对于一些需要处理的数据,简单的数据难以反映数据的...数组的定义:数组是有序的并且具有相同类型的数据的集合。
  • 这是我写的一个测试程序,我想测试下数组索引写成'\0'结束字符的后果。结果得了97. 我有两个疑问,第一呢。数组索引为什么可以用字符呢,不应该只能是数字吗。第二个,97代码的是阿斯卡码的a把。但是我代码里a索引...
  • c语言数组详解

    万次阅读 多人点赞 2007-04-24 16:37:00
    C语言中, 数组属于构造数据类型。一个数组可以分解为多个数组元素,这些数组元素可以是基本数据类型或是构造类型。因此按数组元素的类型不同,数组又可分为数值数组、字符数组、指针数组、结构数组等各种类别。...
  • C语言中,几乎所有的数组在使用时,数组名都是作为一个指针常量,即数组第一个元素的地址,来使用的。其类型,完全取决于数组元素的类型,如果他们是int类型,那么数组名的类型就是指向“int的常量指针”,如果是...
  • c语言数组的声明和初始化This section contains aptitude questions and answers on C language Declarations and Initialization. 本节包含有关C语言声明和初始化的适切性问题和解答。 1) What will be the ...
  • 在谈指针的同时我们也要谈谈数组数组可以说和指针密不可分的,故把它俩放在一起谈。 一.指针 1.初级指针 内存和地址  硬件存储中有一个值得注意的地方是边界对齐。在要求边界对齐的机器上,整型值存储...
  • 由于 C 语言并不具有类似 Java 等语言中现有的静态分析工具的功能,可以对程序中数组下标取值范围进行严格检查,一旦发现数组上溢或下溢,都会因抛出异常而终止程序。也就是说,C 语言并不检验数组边界,数组的两端...
  • C语言字符数组的结束\0

    千次阅读 2020-03-04 16:23:35
    #include<stdio.h> int main(){ ...//错误 指定的数组长度不够时 //char a[]={'b','i','l','i','b','i','l','i'};//错误 不指定长度,每个字符用单引号时 //char a[9]={'b','i','l','i','b','...
  • p 指向一个 int 数组元素, p + i 的地址时数组中第 i 个元素的地址, 即 p + i 指向 第 i 个元素; 存储分配示例函数 :  -- char *alloc(int n) 函数 : 传入分配的字符个数, 返回连续字符存储单元指
  • 1. 字符数组的定义和初始化初始化字符数组的最简单方法是将每个字符分配给数组中的每个元素.char str [10] = {'I',','a','m',','h','a','p','p','y'}; <也就是说,将10个字符分配给str [0]至str [9] 10...
  • 【嵌入式开发】C语言 指针数组 多维数组

    万次阅读 热门讨论 2014-03-19 01:52:05
    ① 模拟C语言中内存分配策略 ; ② 使用 字符指针 和 字符数组 实现 字符串 拷贝 和 比较 ; ③ 指针数组, 数组中的元素 指向一个一维数组 ; ④ 多维数组 作为参数的时候, 其列数 不能省略 行可以省略, 否则就找不到...
  • } 操作 算术操作:+ - * / % 移位操作:>> 位操作:& ^ | 赋值操作:= += -= *= /= &= ^= |= >>= 单目操作: 逻辑操作:&& 逻辑与 || 逻辑或 条件操作:exp1?exp2:exp3 下标引用:[] () . -> ...
  • 空格符号和空字符是不一样的,在ASCII里面,空格(space)符号的ASCII码是0x20,而空字符是0x...空字符 一般来描述一个字符串的结尾,其实是控制的一种,但不能理解为没有字符,应该理解为代表什么都没有的字符.好比回车0x
  • C语言中得数组详解

    2014-12-10 16:05:52
    C语言中, 数组属于构造数据类型。一个数组可以分解为多个数组元素,这些数组元素可以是基本数据类型或是构造类型。因此按数组元素的类型不同,数组又可分为数值数组、字符数组、指针数组、结构数组等各种类别。 ...
  • C语言数组

    千次阅读 2006-10-07 15:24:00
    C语言中, 数组属于构造数据类型。一个数组可以分解为多个数组元素,这些数组元素可以是基本数据类型或是构造类型。因此按数组元素的类型不同,数组又可分为数值数组、字符数组、指针数组、结构数组等各种类别。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 22,363
精华内容 8,945
关键字:

c语言数组终止符

c语言 订阅