C语言 第七章

目录

1. 数组的定义和初始化

2.  数组元素的访问与螺旋矩阵

 3. 向函数传递数组

4. 函数实现

4.1 计算最大值的函数实现

4.2 查找算法的函数实现

4.3  排序算法的函数实现

 5. 一维数组下标越界问题分析

 5. 小结


1. 数组的定义和初始化

  • 数组的作用
    • 保存大量同类型的相关数据
  • 数组的定义
    • int a[10]
      • 数组名代表首地址
      • 定义一个有10个int类型元素的一维数组
        • 在内存中分配连续的存储空间给此数组
      • 为什么数组下标从0开始
        • 使编译器的实现简化一点,且下标的运算速度少量提高
    • 数组的数据类型——每一元素占内存空间的字节数
    • 数组的存储类型——内存的动态、静态存储区或CPU的寄存器
  • 一维数组的初始化
    • 静态数组和全局数组自动初始化为0值,否则,是随机数
    • 赋值初始化
      • int a[5] = {62, 74, 56, 88, 90};
    • 更高效的数组初始化方法
      • memset(a, 0, sizeof(a));
      • 用sizeof(a)来获得数组a所占的内存字节数
      • #include <string.h>
  • 一维数组元素的访问
    • 数组名[下标]
    • 引用时下标允许是int型变量或表达式
  • 一维数组元素的赋值
    • 通过循环语句遍历赋值

memcpy(b, a, sizeof(a));

  •  数组a复制给数组b
  • #include <string.h>
  • 数组的逻辑存储结构
    • 多维数组存放顺序:按行存放,线性存储 
    • 已知每行的列数才能正确读出数组元素
  • 二维数组的定义和初始化
  • 讨论
    • memcpy(b, a, sizeof(a));
    • 使用这条语句时,如果数组a和b的长度不一样,那么会导致什么结果,是否存在安全隐患?

2.  数组元素的访问与螺旋矩阵

  • 螺旋矩阵代码
#include<stdio.h>
#define N 10
void PrintArray(int a[][N], int m, int n);
void SetArray(int a[][N], int len, int n);
int main()
{
	int a[N][N], n;
	printf("Input n:");
	scanf("%d", &n);
	SetArray(a, 1, n);
	PrintArray(a, n, n);
	return 0;
}

//迭代算法
void SetArray(int a[][N], int len, int n)
{
	//level为走过的圈数 
	int m, k, level;
	level = n>0 ? (n+1)/2 : -1;
	printf("%d\n", level);
	for (m=0; m<level; m++)
	{
		//top
		for(k=m; k<n-m; k++)
			a[m][k] = len++;
		//right
		for(k=m+1; k<n-m-1; k++)
			a[k][n-m-1] = len++;
		//bottom
		for(k=n-m-1; k>m; k--)
			a[n-m-1][k] = len++;
		//left
		for(k=n-m-1; k>m; k--) 
			a[k][m] = len++;
	} 
}

//递归算法
void SetArray(int a[][N], int len, int start, int border)
{ 
	int k;
	if (start > border) return;
	else if (start == border)
	{
		a[start][start] = len;
		return ;
	}
	else
	{
		//top
		for(k=start;k<border;k++)
			a[start][k]=len++;
		//right
		for(k=start;k<border;k++)
			a[k][border]=len++;
		//bottom
		for(k=border;k>start;k--)
			a[border][k]=len++;
		//left
		for(k=border;k>start;k--)
			a[k][start]=len++;
		SetArray(a, len, start+1, border-1);
	}
}

void PrintArray(int a[][N], int m, int n)
{
	int i, j;
	for (i=0; i<m; i++)
	{
		for (j=0; j<n; j++)
		{
			printf("%d\t", a[i][j]);
		}
		printf("\n");
	} 
}

 3. 向函数传递数组

  • 简单变量和数组作函数参数的区别

  • 键盘输入数组
    • 计数控制—键盘输入数组元素个数
      for(i=0; i<n; i++)
      {
          scanf("%d", &score[i]);
      }
    • 标记控制—负值作为输入结束标记
      do{
          i++;
          printf("Input Score:");
          scanf("%d", &score[i]);
      }while(score[i]>=0);
  • 向函数传递一维数组
    • int Average(int score[], int n);
    • 通常不指定数组的长度,用另一个形参来指定数组的大小
  • 向函数传递二维数组
    • void Average(int score[][COURSE_N], float aver[], int n);
    • 向函数传递二维数组的首地址
    • 在声明函数的二维数组 形参 时,不能省略数组第二维的长度
    • 通常不指定数组的长度,用另一个形参n来指定二维数组的行数
    • 元素地址:首地址+偏移量
      • a[i][j]在数组中相对于第一个元素的偏移位置:i * 3 + j

4. 函数实现

4.1 计算最大值的函数实现

  • 用一个函数能同时返回 最大值及其所在数组的下标两个 值吗?
    • 可以,可以用形参进行返回。

4.2 查找算法的函数实现

  • 线性查找
    • 平均情况:查找次数是数据量的一半
  • 二分查找
    • 要求数据表是已排好序的
    • 先将表的中间位置记录的关键字与查找关键字比较
    • mid = (high + low) / 2
      • 如果数组很大,low和high之和大于有符号整数的极限值INT_MAX(在limits.h中定义)。就会发生数值溢出,使mid成为一个负数
      • 防止溢出的解决方案:mid = low + (high - low) / 2;(修改计算中间值的方法,用减法代替加法)
    • 最多所需的比较次数是第一个大于表中元素个数的2的幂次数
      •  14个数,最多比较的次数是4
    • 缺点
      • 要求待查表按关键字有序排列,否则需要先进行排序操作
      • 必须采用顺序存储结构,插入和删除数据需移动大量的数据
        • 把逻辑上相邻的结点存储在物理位置上相邻的存储单元中,结点之间的逻辑关系由存储单元的邻接关系来体现
      • 适用于不经常变动而查找频繁的有序表 

4.3  排序算法的函数实现

  • 交换法排序
    • 每次将待排序中第一个数放在其最终的位置上
  • 选择法排序
    • 在每一遍比较中,在剩余的待比较的数中选择一个最小的数与这个剩余序列的第1个数交换位置
  • 冒泡算法
    • 比较相邻的两个数据,若顺序不对,则将其位置交换
#include<stdio.h>
void ChangeSort(int score[], int n);
void Display(int score[], int n);
void SelectionSort(int score[], int n);
void BubbleSort(int score[], int n);
int main()
{
	int score1[5] = {84, 83, 88, 87, 61};
//	ChangeSort(score1, 5);
//	SelectionSort(score1, 5);
	BubbleSort(score1, 5);
	Display(score1, 5);
	
	
}

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

//交换法排序 
void ChangeSort(int score[], int n)
{
	int i, j, temp;
	for(i=0; i<n-1; i++)
	{
		for(j=i+1; j<n; j++)
		{
			if(score[i]>score[j])
			{
				temp = score[i];
				score[i] = score[j];
				score[j] = temp;
			}
		}
	}
}

//选择法排序
void SelectionSort(int score[], int n)
{
	int i, j, k, temp;
	for(i=0; i<n-1; i++)
	{
		k = i;
		for(j=i+1; j<n; j++)
		{
			if(score[j] < score[k])
			{
				k = j;
			}
			if(k != i){
				temp = score[i];
				score[i] = score[k];
				score[k] = temp;
			}
		}
	}
}

//冒泡法排序
void BubbleSort(int score[], int n)
{
	int i, j, temp;
	for(i=0; i<n-1; i++)
	{
		for(j=0; j<n-1-i; j++)
		{
			if(score[j]>score[j+1])
			{
				temp = score[j];
				score[j] = score[j+1];
				score[j+1] = temp;
			}
		}
	}
 } 

 5. 一维数组下标越界问题分析

  • 访问数组元素时,下标越界是大忌
    • 编译器通常不检查下标越界,导致程序运行时错误
    • 下标越界,将访问数组以外的空间,可能带来严重后果
  •  对于数组定义 int a[2][3],虽然a[0][3]和a[1][0]指的是同一元素,但隐患严重
  • 使用数组的基本原则
    • 永远清楚每个数组有多大,永远不要让下标越界
    • 字符数组永远留意'\0'

 筛选求素数

#include<stdio.h>
#include<math.h>
#define N 100
void SiftPrime(int a[], int n);
void PrintPrime(int a[], int n);
int main()
{
	int a[N+1];
	SiftPrime(a, N);
	PrintPrime(a, N);
 } 
 
void SiftPrime(int a[], int n)
{
	int i, j;
	for(i=2; i<=n; i++)
	{
		a[i] = i;
	}
	for(i=2; i<=sqrt(n); i++)
	{
		for(j=i+1; j<=n; j++)
		{
			if(a[i]!=0 && a[j]!=0 && a[j]%a[i]==0)
			{
				a[j] = 0;
			}
		}
	}
}

void PrintPrime(int a[], int n)
{
	int i;
	for(i=2; i<=n; i++)
	{
		if(a[i] != 0)
		{
			printf("%d\t", a[i]);
		}
	}
//	printf("\n");
}

 6. 小结

  • 不能使用数组名对数组元素进行初始化
  •  不能使用变量定义数组的长度
  • 形参、实参的数量和返回值不一致导致编译错误
  • 形参、实参的类型和顺序不一致导致运行时错误
  • 函数传递多维函数时,需要定义第一维以外的后面所有维的长度声明
  • 在函数中定义的静态局部数组元素不会被初始化为零

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值