二维数组概念以及函数习题

以下是对图片中二维数组相关知识的总结与补充:

一、二维数组的定义与基本访问

  1. 定义格式类型说明符 数组名[行数][列数]; ,比如 int a[3][4]; ,表示定义了一个 3 行 4 列的整型二维数组 ,用于存储按行和列排列的数据。
  2. 元素访问:通过 数组名[行下标][列下标] 来访问元素,下标从 0 开始计数 。若下标超出定义的范围(比如行数定义为 3,却用 a[3][0] 访问 ),会造成数组越界,可能引发程序错误 。

二、二维数组的存储特性

二维数组在内存中是按行优先的顺序连续存储的 。可将其理解为 “数组的数组” ,比如 a[3][4] ,可看作是 3 个长度为 4 的一维整型数组(a[0]a[1]a[2] )依次存储,体现了单一性(元素类型统一 )、连续性(内存存储连续 )、有序性(按行下标、列下标有序排列 )

三、二维数组的地址与内存理解

  • 数组名(如 a )代表二维数组的首地址,等价于 &a[0] ,是指向包含若干列元素的一维数组的指针 。
  • a[i] 代表第 i 行一维数组的首地址,等价于 &a[i][0] ,是指向该行第一个元素的指针 。
  • a[i][j] 就是具体存储的元素值,可通过指针运算等方式灵活操作其读写 。

四、二维数组的初始化

  1. 完整初始化:如 int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; ,用大括号嵌套的形式,按行给数组元素赋初值 。
  2. 省略行的初始化:允许省略行数(不能省略列数 ),编译器会根据初值个数和列数自动推算行数 。例如 int a[][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; ,会自动识别为 3 行 4 列的数组 ,但列数必须明确指定,保证每行元素个数一致的规则 。

五、二维数组的输入输出(补充常见操作 )

若要输出二维数组内容,可结合循环:

#include 
int main() {
    int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
    for (int i = 0; i < 3; i++) { 
        for (int j = 0; j < 4; j++) { 
            printf("%d ", a[i][j]); 
        }
        printf("\n"); 
    }
    return 0;
}

通过嵌套循环,外层控制行,内层控制列,逐个输出元素,并用 printf("\n"); 实现每行结束后换行 ,类似地,输入也可借助循环,用 scanf 逐个为 a[i][j] 赋值 。

六、二维数组与函数(补充关联知识 )

二维数组可作为函数参数传递 ,不过传递时一般需指定列数(或通过其他方式让函数知晓列数 ),常见形式如 void func(int a[][4], int row)row 用于接收行数 ),在函数内部按行、列下标操作数组元素,实现数据处理,比如对二维数组求和、找最大值等功能 。

计算二维数组所有元素之和:

#include  //计算二维数组所有元素之和:
#if 0
int main(void)
{
	int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
	int line=sizeof(a)/sizeof(a[0]);
	int row=sizeof(a[0])/sizeof(a[0][0]);
	int i,j,sum=0;
	for(i=0;i

这段代码的逻辑是通过嵌套循环遍历二维数组的所有元素,并计算它们的总和,具体步骤如下:

  1. 定义并初始化二维数组

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

    定义了一个3行4列的二维数组a,并初始化了12个整数元素。

  2. 计算数组的行数和列数

    • int line = sizeof(a) / sizeof(a[0]);
      通过sizeof(a)获取整个二维数组的总字节数,除以一行元素的字节数sizeof(a[0]),得到行数(结果为3)。
    • int row = sizeof(a[0]) / sizeof(a[0][0]);
      通过一行元素的总字节数sizeof(a[0]),除以一个元素的字节数sizeof(a[0][0]),得到列数(结果为4)。
  3. 初始化求和变量

    int i, j, sum = 0;
    

    定义循环变量i(行索引)、j(列索引),以及累加和变量sum并初始化为0。

  4. 嵌套循环遍历数组并求和

    • 外层循环for(i=0; i:控制行索引,从0遍历到行数-1(0~2)。
    • 内层循环for(j=0; j:控制列索引,从0遍历到列数-1(0~3)。
    • 每次循环执行sum += a[i][j];,将当前元素a[i][j]的值累加到sum中。
  5. 输出结果并结束程序

    printf("%d\n", sum);
    return 0;
    

    打印累加得到的总和(1+2+…+12=78),然后程序正常退出。

整个逻辑通过动态计算行列数(而非硬编码3和4),使代码更灵活——当数组的行数或列数改变时,循环条件会自动适配,无需手动修改。

注:代码被#if 0#endif包裹,这会让预处理器忽略中间的代码(相当于暂时注释掉)。如果要运行程序,需要删除这两行。

计算二维数组外围元素之和。

int main(void)    //计算二位数组外围元素之和。
{
	int a[][4]={1,2,3,4,5,6,7,8,9,10,11,12};
	int line=sizeof(a)/sizeof(a[0]);
	int rows=sizeof(a[0])/sizeof(a[0][0]);
	int i,j;
	int sum=0;
	for(i=0;i

这段代码的功能是计算二维数组外围元素的总和,逻辑清晰且正确,具体分析如下:

核心思路

通过判断元素是否位于数组的"外围"(即第一行、最后一行、第一列或最后一列),将符合条件的元素值累加求和。

代码解析

  1. 数组定义与初始化

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

    定义了一个3行4列的二维数组(行数由初始化元素个数自动推导)

  2. 计算行列数

    • line = sizeof(a)/sizeof(a[0]):得到行数(3行)
    • rows = sizeof(a[0])/sizeof(a[0][0]):得到列数(4列)
  3. 外围元素判断逻辑

    if(0==i||0==j||i==line-1||j==rows-1)
    

    这个条件判断元素是否位于:

    • 第一行(i=0)
    • 第一列(j=0)
    • 最后一行(i=line-1,即i=2)
    • 最后一列(j=rows-1,即j=3)
  4. 求和过程
    对所有满足外围条件的元素进行累加,最终得到外围元素总和。

计算结果

对于这个3×4的数组,外围元素包括:

  • 第一行:1,2,3,4
  • 最后一行:9,10,11,12
  • 中间行的第一列和最后一列:5,8

总和为:1+2+3+4+5+8+9+10+11+12 = 65

这段代码的优点是通过动态计算行列数,使程序可以适应不同大小的二维数组,只需保证数组定义正确即可。

二维数组同行逆序:

int main(void)  //二维数组同行逆序
{
	int a[][4]={1,2,3,4,5,6,7,8,9,10,11,12};
	int line=sizeof(a)/sizeof(a[0]);
	int rows=sizeof(a[0])/sizeof(a[0][0]);
	int i,j;
	for(i=0;i

这段代码的功能是实现二维数组中每行元素的逆序排列(即每行内部的元素首尾互换),具体逻辑如下:

核心思路

对二维数组的每一行,将该行的第1个元素与最后1个元素交换、第2个元素与倒数第2个元素交换……以此类推,直到完成该行所有元素的逆序。

代码解析

  1. 数组定义与初始化

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

    定义了一个3行4列的二维数组,初始值为:

    1  2  3  4
    5  6  7  8
    9 10 11 12
    
  2. 计算行列数

    • line = sizeof(a)/sizeof(a[0]):得到行数(3行)
    • rows = sizeof(a[0])/sizeof(a[0][0]):得到列数(4列)
  3. 每行逆序的核心逻辑

    for(i=0; i<line; ++i)  // 遍历每一行
    {
        for(j=0; j<rows/2; ++j)  // 遍历每行前半部分元素
        {
            // 交换当前元素与对称位置的元素
            int t = a[i][j];
            a[i][j] = a[i][rows-1-j];
            a[i][rows-1-j] = t;
        }
    }
    
    • 外层循环(i控制):逐个处理每一行
    • 内层循环(j控制):只需要遍历到每行的中间位置(rows/2),因为每个交换操作会同时处理两个元素
    • 交换逻辑:a[i][j]a[i][rows-1-j]互换(例如第1行中,j=0时交换a[0][0]a[0][3]j=1时交换a[0][1]a[0][2]
  4. 输出结果
    逆序后的数组为:

  4  3  2  1  
  8  7  6  5  
 12 11 10  9  

关键细节

  • 内层循环只需要执行rows/2次(对于4列数组,只需循环2次),避免重复交换
  • 交换操作仅在同一行内进行,不同行之间的元素不会互相影响
  • 无论数组行数多少,只要列数固定,该逻辑都能正确逆序每行元素

这种实现方式高效且简洁,时间复杂度为O(行数×列数/2),是处理二维数组每行逆序的经典方法。

在二维字符型数组内找最大的一维字符型数组

#include
int main(void)   //在二维字符型数组内找最大的一维字符型数组
{
	char s[][100]={"hello","world","china"};
	int rows = sizeof(s)/sizeof(s[0]);
	int i;
	char max[100];
	for(i=1;i

这段代码的意图是在二维字符数组中找到"最大"的字符串(按字典序比较),但代码存在逻辑缺陷,具体分析如下:

代码逻辑解析

  1. 数组定义

    char s[][100]={"hello","world","china"};
    

    定义了一个二维字符数组,包含3个字符串:“hello”、“world”、“china”

  2. 计算行数

    int rows = sizeof(s)/sizeof(s[0]);  // 结果为3,即有3个字符串
    
  3. 查找"最大"字符串的逻辑

    • 定义max字符数组用于存储结果
    • 循环从i=1开始遍历数组(跳过了第一个元素s[0]
    • 使用strcmp比较maxs[i]
      • strcmp(max, s[i]) < 0,表示s[i]字典序大于max
      • 此时用strcpys[i]复制到max
    • 最后输出max

存在的问题

代码的关键缺陷max数组未初始化就直接使用:

  • 初始状态下max中是随机的垃圾值
  • 第一次比较strcmp(max, s[1])时,是用随机值和"world"比较,结果不可控
  • 可能导致最终结果错误,甚至程序异常

正确逻辑修正

应先将第一个字符串s[0]初始化给max,再从第二个字符串开始比较:

char max[100];
strcpy(max, s[0]);  // 先初始化max为第一个字符串
for(i=1; i<rows; ++i)
{
    if(strcmp(max, s[i]) < 0)  // 若当前字符串更大
    {
        strcpy(max, s[i]);    // 更新max
    }
}

字典序比较规则

strcmp函数的比较规则:

  • 返回值 < 0:第一个字符串字典序小于第二个
  • 返回值 = 0:两个字符串相等
  • 返回值 > 0:第一个字符串字典序大于第二个

对于示例中的三个字符串,正确的比较结果是"world"(最大),因为字典序:“china” < “hello” < “world”。

二维字符型数组的逆序:

#include
int main(void)  //二维字符型数组的逆序。
{
	
	char s[][100]={"hello","world","china"};
	int rows = sizeof(s)/sizeof(s[0]);
	int i;
	for(i=0;i

这段代码的功能是对二维字符数组中的字符串进行整体逆序排列(即交换数组中字符串的位置,使整个数组的顺序反转),具体逻辑如下:

核心思路

通过对称交换二维字符数组中的字符串元素,将数组的整体顺序反转。例如,原数组为 ["hello", "world", "china"],逆序后变为 ["china", "world", "hello"]

代码解析

  1. 数组定义与初始化

    char s[][100]={"hello","world","china"};
    

    定义了一个二维字符数组,包含3个字符串:"hello""world""china",每个字符串最多可存储99个字符(加结束符\0共100字节)。

  2. 计算字符串数量

    int rows = sizeof(s)/sizeof(s[0]);  // 结果为3,即数组中有3个字符串
    

    通过sizeof计算数组总行数(字符串数量),sizeof(s)是整个二维数组的总字节数,sizeof(s[0])是单个字符串的字节数(100)。

  3. 逆序交换的核心逻辑

    for(i=0; i<rows/2; ++i)  // 循环到数组中间位置
    {
        char t[100];         // 临时字符串,用于交换
        strcpy(t, s[i]);                  // 步骤1:将s[i]复制到临时变量t
        strcpy(s[i], s[rows-1-i]);        // 步骤2:将对称位置的字符串复制到s[i]
        strcpy(s[rows-1-i], t);           // 步骤3:将临时变量t(原s[i])复制到对称位置
    }
    
    • 外层循环控制交换次数,只需循环到数组中间(rows/2),避免重复交换。对于3个元素的数组,rows/2为1,即只需要交换1次。
    • 交换逻辑:第i个字符串与第rows-1-i个字符串互换(例如i=0时,交换第1个和第3个字符串)。
    • 使用strcpy函数复制字符串内容,因为直接赋值(如t = s[i])无法复制字符串内容(只会传递地址)。
  4. 输出逆序后的结果

    for(i=0; i<rows; ++i)
    {
        puts(s[i]);  // 逐个输出逆序后的字符串
    }
    

    原数组经过逆序后,输出结果为:

    china
    world
    hello
    

关键细节

  • 逆序操作针对的是字符串在二维数组中的位置,而非字符串内部字符的逆序。
  • 交换字符串时必须使用字符串复制函数(strcpy),不能直接用赋值运算符,因为字符数组名代表首地址,直接赋值会导致地址操作错误。
  • 循环终止条件i < rows/2是高效实现的关键,确保每个元素只参与一次交换。

这段代码通过对称交换的方式实现了二维字符数组的整体逆序,逻辑清晰且高效,时间复杂度为O(rows/2),适用于任意数量字符串的二维字符数组逆序场景。

二维字符型数组的升序排序:

#include
#include
int main(void)
{
    char s[][100]={"hello","world","china"};
    int rows = sizeof(s)/sizeof(s[0]);  // 3个字符串
    int i,j;

    // 外层循环:控制排序轮次(共rows-1轮)
    for(i=0;i s[j](字典序),则交换两者
            if(strcmp(s[i],s[j])>0)
            {
                char t[100];
                strcpy(t,s[i]);
                strcpy(s[i],s[j]);
                strcpy(s[j],t);
            }
        }
    }

    // 排序完成后,统一输出结果
    for(i=0;i

这段代码实现了对二维字符数组中的字符串按字典序进行升序排序(从小到大排列),采用的是类似选择排序的思路,具体逻辑如下:

一、核心功能与整体思路

通过嵌套循环遍历二维字符数组,比较字符串的字典序,将较小的字符串交换到前面,最终使整个数组按字典序从小到大排列。

二、代码分步解析

  1. 数组定义与初始化

    char s[][100]={"hello","world","china"};
    

    定义了一个二维字符数组,包含3个字符串:"hello""world""china",每个字符串最多可存储99个字符(加上结束符\0共100字节)。

  2. 计算字符串数量

    int rows = sizeof(s)/sizeof(s[0]);  // 结果为3
    

    通过sizeof运算符计算数组中字符串的数量:

    • sizeof(s)是整个二维数组的总字节数
    • sizeof(s[0])是单个字符串(一行)的字节数(100)
    • 两者相除得到字符串的总个数(3个)
  3. 排序核心逻辑

    // 外层循环:控制排序轮次(共rows-1轮)
    for(i=0;i<rows-1;++i)
    {
        // 内层循环:比较第i轮未排序的元素
        for(j=i+1;j<rows;++j)
        {
            // 比较字符串字典序
            if(strcmp(s[i],s[j])>0)
            {
                // 交换两个字符串
                char t[100];
                strcpy(t,s[i]);
                strcpy(s[i],s[j]);
                strcpy(s[j],t);
            }
        }
    }
    
    • 外层循环(i控制):从0到rows-2(共2轮),每轮确定一个位置的元素

      • 第1轮(i=0):确定数组中最小的字符串,放在第1个位置
      • 第2轮(i=1):确定剩余元素中最小的字符串,放在第2个位置
    • 内层循环(j控制):从i+1开始到数组末尾,负责与外层循环指定的位置元素进行比较

      • 这样设计避免了重复比较(不需要和已经排好序的元素比较)
    • 比较与交换

      • 使用strcmp(s[i], s[j])比较两个字符串的字典序:
        • 若返回值>0,表示s[i]的字典序大于s[j]
      • 当需要交换时,用strcpy函数复制字符串内容(不能直接用赋值运算符,因为字符数组名是地址)
  4. 输出排序结果

    for(i=0;i<rows;++i)
    {
        puts(s[i]);
    }
    

    排序完成后,遍历数组并输出每个字符串,结果为:

    china
    hello
    world
    

    (字典序规则:china < hello < world

三、关键技术点

  1. 字典序比较strcmp函数是核心,它按照ASCII码值逐个比较字符,直到遇到不同字符或结束符
  2. 字符串交换:必须使用strcpy函数复制整个字符串内容,不能直接用=赋值(数组名是常量地址,不能被赋值)
  3. 排序效率:通过j=i+1的设计减少了一半的比较次数,比简单的双重循环(j从0开始)更高效

这段代码逻辑清晰,正确实现了二维字符数组的升序排序功能,对于理解字符串排序和二维数组操作很有帮助。

二维字符型数组查找字符串:

#include
int main(void)  //二维字符型数组查找字符串:
{

	char s[][100]={"hello","world","china"};
	int rows = sizeof(s)/sizeof(s[0]);
	int begin = 0;
	int end=rows -1;
	int mid;
	char n[100];
	scanf("%s",n);
	while(begin<=end)
	{
		mid = (begin+end)/2;
		if(strcmp(s[mid],n)<0)
		{
			begin=mid +1;
		}
		else if(strcmp(s[mid],n)>0)
		{
			end=mid-1;
		}
		else
		{
			break;
		}
	}
	if(begin<=end)
	{
		printf("found\n");
	}
	else
	{
		printf("nofound\n");
	}
	return 0;
}

这段代码的意图是在二维字符数组中使用二分查找法查找指定字符串,但存在一个关键前提条件未满足,导致查找逻辑可能失效。具体分析如下:

一、核心思路与设计

代码尝试通过二分查找(折半查找) 算法在字符串数组中查找用户输入的目标字符串,基本流程是:

  1. 确定查找范围(begin为起始索引,end为结束索引)
  2. 计算中间位置,比较中间元素与目标字符串
  3. 根据比较结果缩小查找范围,直到找到目标或范围无效

二、代码分步解析

  1. 数组定义与初始化

    char s[][100]={"hello","world","china"};
    

    定义了包含3个字符串的二维字符数组,初始值为"hello""world""china"

  2. 计算数组长度与初始化变量

    int rows = sizeof(s)/sizeof(s[0]);  // 结果为3(数组中有3个字符串)
    int begin = 0;                     // 查找范围起始索引(初始为0)
    int end = rows - 1;                // 查找范围结束索引(初始为2)
    int mid;                           // 中间位置索引
    char n[100];                       // 存储用户输入的目标字符串
    
  3. 获取用户输入

    scanf("%s",n);  // 读取用户输入的目标字符串
    
  4. 二分查找核心逻辑

    while(begin <= end)  // 当查找范围有效时循环
    {
        mid = (begin + end)/2;  // 计算中间位置索引
        
        // 比较中间字符串与目标字符串
        if(strcmp(s[mid], n) < 0)
        {
            // 中间字符串字典序小于目标字符串,缩小左范围
            begin = mid + 1;
        }
        else if(strcmp(s[mid], n) > 0)
        {
            // 中间字符串字典序大于目标字符串,缩小右范围
            end = mid - 1;
        }
        else
        {
            // 找到目标字符串,跳出循环
            break;
        }
    }
    
  5. 查找结果判断与输出

    if(begin <= end)
    {
        printf("found\n");  // 找到目标(循环因break退出)
    }
    else
    {
        printf("nofound\n");  // 未找到目标(范围无效)
    }
    

三、关键问题与局限性

二分查找的前提条件是数组必须已按升序排序,但当前数组s的初始顺序是["hello", "world", "china"],未按字典序排序(正确升序应为["china", "hello", "world"])。这会导致:

  • 即使目标字符串存在于数组中,也可能查找失败
  • 查找结果具有随机性(依赖中间值比较)

例如:若用户查找"china",由于初始数组无序,二分查找会错误判定为"nofound"。

四、正确使用的前提

要使这段代码正常工作,必须先确保二维字符数组已按字典序升序排列。修改数组初始化部分即可:

char s[][100]={"china","hello","world"};  // 已升序排序

此时查找任意存在的字符串(如"hello")会返回"found",查找不存在的字符串(如"test")会返回"nofound"。

总结

代码实现了二分查找的基本逻辑,但忽略了二分查找对有序数组的依赖。在数组无序的情况下,查找结果不可靠;若数组已按字典序升序排列,则能高效(时间复杂度O(log n))地完成字符串查找。

函数开头部分,定义一个函数找abc里的最大值:

int maxOfThreeNumbers(int a,int b,int c)
{
	int max;
	max=a>b?a:b;
	max=max>c?max:c;
	return max;
}
int main(void)
{
	int max;
	max=maxOfThreeNumbers(10,20,5);
	printf("%d\n",max);
	return 0;
}

这段代码的功能是定义一个函数用于求三个整数中的最大值,并在主函数中调用该函数进行测试,逻辑清晰且正确。具体分析如下:

一、函数定义:maxOfThreeNumbers

该函数的作用是接收三个整数参数,返回其中的最大值,实现逻辑如下:

int maxOfThreeNumbers(int a, int b, int c)
{
    int max;
    // 第一步:比较a和b,将较大值存入max
    max = a > b ? a : b;
    // 第二步:比较max(a和b中的较大值)与c,更新max为三者中的最大值
    max = max > c ? max : c;
    return max;  // 返回最大值
}
  • 核心思路:通过两次三目运算符实现比较。先在ab中取较大值,再将这个较大值与c比较,最终得到三个数中的最大值。
  • 三目运算符condition ? expr1 : expr2的作用:若condition为真,返回expr1;否则返回expr2,适合简单的二选一逻辑。

二、主函数main的执行流程

主函数负责调用上述函数并输出结果,步骤如下:

  1. 定义变量int max; 用于存储函数返回的最大值。
  2. 调用函数max = maxOfThreeNumbers(10, 20, 5);
    传入三个实参10205,函数内部计算后返回最大值20,并赋值给max
  3. 输出结果printf("%d\n", max); 打印最大值20
  4. 程序结束return 0; 表示程序正常退出。

三、执行结果与关键细节

  • 对于输入的三个数10205,函数的计算过程为:

    • 第一步:比较1020max暂存20
    • 第二步:比较205max保持20
    • 最终返回20,主函数输出20
  • 函数的通用性:该函数不仅限于这三个数,对于任意三个整数(如-305)都能正确返回最大值,体现了函数的复用性。

  • 变量作用域:函数内部的max与主函数中的max不同作用域的变量,互不干扰(函数内的max仅在maxOfThreeNumbers中有效,主函数的max仅在main中有效)。

总结

这段代码通过函数封装了“求三数最大值”的逻辑,主函数负责调用和输出,结构清晰,符合模块化编程思想。核心逻辑利用三目运算符简化了比较过程,代码简洁高效,能正确处理任意三个整数的最大值求解。

判断一个整数是否能被3整除:

int div3(int input)
{
	int panduan;
	
	panduan=input%3?0:1;

	return panduan ;

}
int main(void)
{
	int	input;
	scanf("%d",&input);
	div3(input);
	printf("%d\n",div3(input));
	return 0;
}

这段代码的功能是判断一个整数是否能被3整除,并返回判断结果。具体逻辑分析如下:

一、函数定义:div3

该函数用于判断输入的整数是否能被3整除,返回值为判断结果:

int div3(int input)
{
    int panduan;
    // 核心判断逻辑:利用取余运算
    panduan = input % 3 ? 0 : 1;
    return panduan;
}
  • 取余运算input % 3 计算输入值除以3的余数。若能被3整除,余数为0;否则余数为非0值。
  • 三目运算符input % 3 ? 0 : 1 的含义是:
    • input % 3 结果为非0(不能被3整除),则 panduan 赋值为0
    • input % 3 结果为0(能被3整除),则 panduan 赋值为1
  • 函数返回值:1表示“能被3整除”,0表示“不能被3整除”

二、主函数main的执行流程

  1. 定义变量int input; 用于存储用户输入的整数。
  2. 获取输入scanf("%d", &input); 读取用户从键盘输入的整数。
  3. 函数调用
    • 第一次调用 div3(input);:计算结果但未使用(此调用可省略,不影响最终输出)
    • 第二次调用 div3(input);:将返回值作为printf的参数,用于输出结果
  4. 输出结果printf("%d\n", div3(input)); 打印判断结果(1或0)。

三、执行示例

  • 若输入 6(能被3整除),函数返回1,输出 1
  • 若输入 7(不能被3整除),函数返回0,输出 0

四、可优化点

代码中存在一次多余的函数调用 div3(input);(仅调用未使用结果),可删除以提高效率,优化后的主函数如下:

int main(void)
{
    int input;
    scanf("%d", &input);
    printf("%d\n", div3(input));  // 仅保留一次必要的调用
    return 0;
}

这段代码通过封装判断逻辑到函数中,实现了“判断整数能否被3整除”的功能,逻辑清晰,利用取余运算和三目运算符使代码简洁高效。

通过嵌套调用函数来求解多个数中的最大值

int maxOfTwoNumbers(int a,int b)
{
	int max;
	max=a>b?a:b;
	return max;
}
int maxOfThreeNumbers(int a,int b,int c)
{
	int max;
	max=a>b?a:b;
	max=max>c?max:c;
	return max;
}
int main(void)
{
	int max;
	max=maxOfThreeNumbers(10,20,maxOfTwoNumbers(29,39));
	printf("%d\n",max);
	return 0;
}

这段代码的功能是通过嵌套调用函数来求解多个数中的最大值,具体逻辑如下:

一、函数定义与功能

  1. maxOfTwoNumbers函数

    int maxOfTwoNumbers(int a, int b)
    {
        int max;
        max = a > b ? a : b;  // 三目运算符比较a和b,取较大值
        return max;
    }
    

    功能:接收两个整数参数,返回其中的最大值。

  2. maxOfThreeNumbers函数

    int maxOfThreeNumbers(int a, int b, int c)
    {
        int max;
        max = a > b ? a : b;  // 先比较a和b,取较大值
        max = max > c ? max : c;  // 再用前一步结果与c比较,取最大值
        return max;
    }
    

    功能:接收三个整数参数,返回其中的最大值。

二、主函数main的执行流程

  1. 函数嵌套调用

    max = maxOfThreeNumbers(10, 20, maxOfTwoNumbers(29, 39));
    

    执行顺序是从内到外

    • 先执行内层函数maxOfTwoNumbers(29, 39)
      比较29和39,返回较大值39。
    • 再执行外层函数maxOfThreeNumbers(10, 20, 39)
      此时三个参数实际为10、20、39,函数内部先比较10和20(得20),再用20与39比较(得39),最终返回39。
  2. 结果输出

    printf("%d\n", max);  // 输出变量max的值39
    

三、关键逻辑与执行结果

  • 代码通过函数嵌套调用的方式,将maxOfTwoNumbers的返回值作为maxOfThreeNumbers的第三个参数,实现了“求四个数(10、20、29、39)中最大值”的效果。
  • 最终结果为39,因为在这四个数中39是最大的。

四、代码特点

  1. 复用性maxOfTwoNumbers函数被嵌套调用,体现了函数的可复用性,避免了代码重复。
  2. 执行顺序:函数参数的计算顺序是从内到外,先处理嵌套的内层函数,再将结果作为参数传递给外层函数。
  3. 逻辑清晰:通过分步比较(先两数比较,再三数比较),使最大值求解的逻辑层次分明。

这段代码展示了函数嵌套调用的用法,能够灵活处理多个数值的最大值求解,逻辑简洁且高效。

int year(int n)
{
	return(n%4==0&&n%100!=0||n%400==0);		
}
void print(int a,int b)
{
	int i;
	for(i=a;i<=b;++i)
	{
		if( year(i) )
		{
			printf("%d\n",i);
		}
		
	}

}

int main(void)
{
	print(1900,2100);
	return 0;
}

这段代码的功能是判断并打印指定年份范围内的所有闰年,具体逻辑如下:

一、函数定义与功能

  1. year函数

    int year(int n)
    {
        return (n%4==0 && n%100!=0 || n%400==0);		
    }
    

    功能:判断一个年份是否为闰年,返回判断结果(1表示是闰年,0表示不是)。

    闰年判断规则(通过逻辑表达式实现):

    • 能被4整除,且不能被100整除(普通闰年)
    • 或者 能被400整除(世纪闰年)
      逻辑表达式(n%4==0 && n%100!=0 || n%400==0)完美体现了这一规则,结果为真(非0)时返回1,为假时返回0。
  2. print函数

    void print(int a,int b)
    {
        int i;
        for(i=a;i<=b;++i)  // 遍历从a到b的所有年份
        {
            if( year(i) )  // 调用year函数判断是否为闰年
            {
                printf("%d\n",i);  // 是闰年则打印该年份
            }
        }
    }
    

    功能:接收两个参数(起始年份a和结束年份b),遍历该范围内的所有年份,调用year函数判断并打印其中的闰年。

二、主函数main的执行流程

int main(void)
{
    print(1900,2100);  // 调用print函数,打印1900到2100年之间的闰年
    return 0;
}
  • 主函数仅调用print函数,传入参数19002100,指定要查询的年份范围。
  • print函数负责具体的遍历和判断工作,最终在控制台输出1900到2100年间所有的闰年。

三、关键细节与执行结果

  • 特殊年份处理:1900年虽然能被4整除,但它是世纪年(能被100整除且不能被400整除),所以不是闰年,代码会正确排除它。
  • 2000年是世纪闰年(能被400整除),代码会正确识别并打印。
  • 输出结果示例(部分):1904、1908、…、2000、2004、…、2100(注意:2100年不是闰年,不会被打印)。

四、代码特点

  1. 功能拆分:将闰年判断和打印功能拆分为两个函数,职责明确,符合模块化编程思想。
  2. 逻辑简洁year函数通过一个逻辑表达式即可完成闰年判断,高效且易读。
  3. 灵活性print函数通过参数接收年份范围,可灵活查询任意区间的闰年,不限于1900-2100。

这段代码正确实现了闰年判断的逻辑,通过函数分工使代码结构清晰,能够准确输出指定范围内的所有闰年。

#include
int min(int a,int b)
{
	int minmin;
	if(a==0&&b==0)
	{
		printf("这两个数无最大公约数\n");
		return -1;
	}
	else if(a==0||b==0)
	{	minmin=a==0?abs(b):abs(a);
		return minmin;
	}

	else
	{
		int ava=abs(a);
		int avb=abs(b);
		minmin=ava>avb?avb:ava;
		return minmin;
	}
}
int GCD(int a,int b)
{
	int mm=min(a,b);
	int i;
	for(i=mm;i>0;--i)
	{
		if(a%i==0&&b%i==0)
		{
			printf("能找到最大公约数:%d\n",i);
			break;
		}
	}//注释:两个非0整数(不管正负),必能找到它们的最大公约数。
}
int main(void)
{
	int a,b;
	printf("请输入两个数字:\n");
	scanf("%d%d",&a,&b);
	GCD(a,b);
	return 0;
}

这段代码的功能是计算并输出两个整数的最大公约数(GCD),整体逻辑分为函数分工协作完成,具体分析如下:

一、核心函数功能与逻辑

  1. min函数:预处理输入的两个数,确定公约数的查找范围

    int min(int a, int b)
    {
        int minmin;
        // 情况1:两数均为0,无最大公约数
        if(a==0 && b==0)
        {
            printf("这两个数无最大公约数\n");
            return -1;
        }
        // 情况2:其中一个数为0,另一个数的绝对值即为最大公约数
        else if(a==0 || b==0)
        {
            minmin = a==0 ? abs(b) : abs(a);  // 三目运算符简化判断
            return minmin;
        }
        // 情况3:两数均非0,返回两数绝对值中的较小值(作为查找上限)
        else
        {
            int ava = abs(a);  // 取绝对值,处理负数情况
            int avb = abs(b);
            minmin = ava > avb ? avb : ava;  // 取较小值
            return minmin;
        }
    }
    
    • 关键作用:处理特殊情况(含0的输入),并为非0情况确定公约数的最大可能值(两数绝对值的较小者),减少后续查找次数。
    • 对负数的处理:通过abs函数取绝对值,确保负数不影响公约数计算(公约数与正负无关)。
  2. GCD函数:查找并输出最大公约数

    int GCD(int a, int b)
    {
        int mm = min(a, b);  // 调用min函数获取查找上限或特殊情况结果
        int i;
        // 从上限mm向下遍历,找到第一个能同时整除两数的数(即最大公约数)
        for(i = mm; i > 0; --i)
        {
            if(a % i == 0 && b % i == 0)
            {
                printf("能找到最大公约数:%d\n", i);
                break;  // 找到后立即退出循环
            }
        }
    }
    
    • 查找逻辑:采用“从大到小遍历”的方式,第一个能同时整除ab的数就是最大公约数,确保高效性。
    • 依赖min函数的返回值:mm要么是查找上限(两数绝对值较小者),要么是0的特殊情况中有效的那个数的绝对值。

二、主函数main的执行流程

int main(void)
{
    int a, b;
    printf("请输入两个数字:\n");
    scanf("%d%d", &a, &b);  // 获取用户输入的两个整数
    GCD(a, b);  // 调用GCD函数计算并输出最大公约数
    return 0;
}
  • 流程简单:获取用户输入,调用核心函数GCD处理,无需额外逻辑。

三、关键场景与执行结果

  1. 两数均为0
    min函数输出“这两个数无最大公约数”,GCD函数中的循环不执行(mm=-1,循环条件i>0不满足)。

  2. 其中一个数为0
    例如输入06min函数返回6abs(6)),GCD函数循环中i=6时满足0%6==0 && 6%6==0,输出“能找到最大公约数:6”。

  3. 两数均非0(含负数)
    例如输入-1218

    • min函数取绝对值后为1218,返回较小值12
    • GCD函数从12向下遍历,第一个能同时整除-1218的数是6,输出结果为6。

四、代码特点与可优化点

  • 优点

    1. 考虑了含0的特殊情况,逻辑严谨;
    2. 通过取绝对值处理负数,适用性强;
    3. 函数分工明确(min预处理,GCD查找),结构清晰。
  • 可优化点

    1. GCD函数未定义返回值(实际应返回找到的公约数),虽然当前仅打印结果,但返回值可增强函数复用性;
    2. 可采用更高效的“辗转相除法”替代遍历查找,减少循环次数(尤其对大数更优)。

总结

这段代码通过minGCD函数协作,完整实现了两个整数的最大公约数求解,涵盖了特殊情况(含0、负数)的处理,逻辑正确且实用。核心思路是“确定查找范围→从大到小遍历验证”,适合理解最大公约数的基本求解逻辑。

算两个数的最大公约数:

#include 
#include   // 用于abs函数

// 计算最大公约数(辅助函数)
int gcd(int a, int b) {
    a = abs(a);  // 取绝对值,处理负数
    b = abs(b);
    
    // 辗转相除法求最大公约数
    while (b != 0) {
        int temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}

// 计算最小公倍数
int lcm(int a, int b) {
    // 检查是否有零输入
    if (a == 0 || b == 0) {
        printf("错误:输入不能为零,最小公倍数无意义\n");
        return -1;
    }
    
    // 利用公式:最小公倍数 = 两数乘积的绝对值 / 最大公约数
    int abs_product = abs(a) * abs(b);  // 先计算乘积的绝对值
    int common_divisor = gcd(a, b);     // 获取最大公约数
    int result = abs_product / common_divisor;  // 计算最小公倍数
    
    printf("最小公倍数是:%d\n", result);
    return result;
}

int main(void) {
    int a, b;
    printf("请输入两个整数(用空格分隔):");
    scanf("%d %d", &a, &b);
    
    lcm(a, b);  // 调用函数计算并输出结果
    
    return 0;
}

输入年月给出改月的天数:

int isLeapyear(int year)
{
	return (year%4==0&&year%100!=0||year%400==0);
}
int daysOfTheMonth(int year,int month)
{
	int a[]={31,0,31,30,31,30,31,31,30,31,30,31};
	if(month<=0||month>=12)
	{
		return -1;
	}
	if(month!=2)
	{
		return a[month-1];
	}
	else
	{
		return isLeapyear(year)?29:28;
	}

}
int main(void)
{
	int year,month;
	printf("请输入要确认天数的年月\n");
	scanf("%d%d",&year,&month);
	int ret;
	ret=daysOfTheMonth(year,month);
	if(ret<0)
	{
		puts("error");
	}
	else
	{
		printf("%d\n",daysOfTheMonth(year,month));
	}
	return 0;
}

你可能感兴趣的:(开发语言,算法,c语言,ubuntu)