C语言进阶⑫(指针下)(指针和数组笔试题解析)(杨氏矩阵)(下)

简介: C语言进阶⑫(指针下)(指针和数组笔试题解析)(杨氏矩阵)

C语言进阶⑫(指针下)(指针和数组笔试题解析)(杨氏矩阵)(中):https://developer.aliyun.com/article/1513063

3笔试题二

3.1指向函数指针数组的指针

声明一个指向含有10个元素的数组的指针,其中每个元素是一个函数指针,该函数的返回值是int,

参数是int*,正确的是( )

A.(int *p[10])(int*)

B.int [10]*p(int *)

C.int (*(*p)[10])(int *)

D.int ((int *)[10])*p

解析:

A选项,第一个括号里是一个完整定义,第二个括号里是个类型,四不像。BD选项,[]只能在标识符右边,双双排除。只有C是能编过的。


3.2函数指针

定义一个函数指针,指向的函数有两个int形参并且返回一个函数指针,返回的指针指向一个有一个

int形参且返回int的函数。下面哪个是正确的?( )

A.int (*(*F)(int, int))(int)

B.int (*F)(int, int)

C.int (*(*F)(int, int))

D.*(*F)(int, int)(int)

解析:

D类型不完整先排除,然后看返回值,B的返回值是int,C的返回值是int *,故选A。判断返回值类型只需要删掉函数名/函数指针和参数列表再看就行了。int (*(*F)(int, int))(int)删掉(*F)(int, int)后剩下int (*)(int),符合题意。

3.3函数指针

设有以下函数void fun(int n,char *s){……},则下面对函数指针的定义和赋值均是正确的是:( )

A.void (*pf)(int,char); pf=&fun;

B.void (*pf)(int n,char *s); pf=fun;

C.void *pf(); *pf=fun;

D.void *pf(); pf=fun;

解析:

CD前半句压根就不是定义而是声明,A选项参数列表的第二个参数错了。应为char *,B选项正确。需要说明的是,对于函数名来说,前面的&和*都会被忽略,所以fun前面加不加取地址都没区别。只有定义出的函数指针变量(如题面中的pf)加上&后才会变成二级函数指针。

3.4指针+-

 
#include <stdio.h>
int main()
{
    int aa[2][5] = { 10,9,8,7,6,5,4,3,2,1 };
    int* ptr1 = (int*)(&aa + 1);
    int* ptr2 = (int*)(*(aa + 1));
    printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
    return 0;
}

A.1, 6

B.10, 5

C.10, 1

D.1, 5

解析:

&aa的类型是int (*)[2][5],加一操作会导致跳转一个int [2][5]的长度,直接跑到刚好越界的位置。减一以后回到最后一个位置1处。*(aa + 1)相当于aa[1],也就是第二行的首地址,自然是5的位置。减一以后由于多维数组空间的连续性,会回到上一行末尾的6处。故选A。


3.5数组指针

 
#include <stdio.h>
int main()
{
    int a[5] = { 5, 4, 3, 2, 1 };
    int* ptr = (int*)(&a + 1);
    printf("%d,%d", *(a + 1), *(ptr - 1));
    return 0;
}

A.5, 1

B.4, 1

C.4, 2

D.5, 2

解析:

*(a + 1)等同于a[1],第一个是4,a的类型是int [5],&a的类型就是int(*)[5],是个数组指针。所以给int(*)[5]类型加一,相当于加了一个int [5]的长度。也就是这个指针直接跳过了a全部的元素,直接指在了刚好越界的位置上,然后转换成了int *后再减一,相当于从那个位置向前走了一个int,从刚好越觉得位置回到了1的地址处,所以第二个是1,故选B。

3.6函数参数设计

下面代码中print_arr函数参数设计哪个是正确的?( )

 
 int arr[3][5] = {1,2,3,4,5,6,7,8,9,10};
 print_arr(arr, 3, 5);

A.void print_arr(int arr[ ][ ],int row, int col);

B.void print_arr(int* arr, int row, int col);

C.void print_arr(int (*arr)[5], int row, int col);

D.void print_arr(int (*arr)[3], int row, int col);

解析:

二维数组相当于数组的数组,传到子函数变成数组的指针。int arr[3][5]相当于是3个元素的arr,每个元素是int [5],所以int [5]是类型说明不能省略。丢失的信息只有数组的元素个数,也就是3。A丢了类型中的5,B选项arr是首元素地址,首元素是第一行数组,指针层次错了。D选项5写成了3,

3.7函数设计

下面test函数设计正确的是:( )

 
char* arr[5] = {"hello", "bit"};
test(arr);

A.void test(char* arr);

B.void test(char** arr);

C.void test(char arr[5]);

D.void test(char* arr[5]);

解析:

指针的数组传递给子函数变为指针的指针,也就是二级指针。但是允许中括号写法,

写成char **arr、char *arr[]、char * arr[5]都可。所以BD正确。


3.8(编程)杨氏矩阵

杨氏矩阵


有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,


请编写程序在这样的矩阵中查找某个数字是否存在。


要求:时间复杂度小于O(N);


解题:


如杨氏矩阵:


1 2 3


4 5 6


7 8 9


再如:


1 2 3


2 3 4


3 4 5


查找某个元素——若遍历二维数组,若数组有n个元素,


则最坏情况下找n次,即时间复杂度为O(N),(时间复杂度是数据结构的内容,现在不懂可以略过)


而题目要求时间复杂度小于n。时间复杂度小于O(N)的算法:

 
#include<stdio.h>
int find_arr(int arr[3][3], int row, int col, int k)
{
    int x = 0, y = col - 1;//从右上角开始找
    while (x < row && y >= 0)
    {
        if (arr[x][y] > k)
        {
            y--;
        }
        else if (arr[x][y] < k)
        {
            x++;
        }
        else
        {
            printf("%d %d\n", x, y);
            return 1;
        }
    }
    return 0;
}
 
int main()
{
    int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
    //  1   2   3
    //  4   5   6
    //  7   8   9
    //若要找的元素是k=2,比右上角的3小,因为3是一列中最小的元素,所以去掉一列;
    //    若要找的元素是k=7,比右上角的3大,因为3是一行中最大的元素,
    //    所以去掉一行;7比在剩下的元素中右上角的6还要大,则又去掉一行;
    //    7与剩下元素中右上角的9小,则在这一行中查找7,
    //    (因为9已经是剩下元素所在列中最小的元素)去掉一列;
    //    8比7大说明还在8的左边,去掉一列;7与7相等则找到;
    //    如果7还找不到则结果就是找不到。
 
    int k = 0;
    scanf("%d", &k);
        //找到返回1 找不到返回0
    //传arr和行、列、要找的元素
    if (find_arr(arr, 3, 3, k))
    {
        printf("找到了\n");
        
    }
    else
    {
        printf("找不到\n");
    }
    return 0;
}

虽然封装了函数,但是找到的下标是自己打印的,这不是好的解决办法。

解决办法:用函数查找,用函数带回或返回找不到。

而且return不能直接带回两个值。

更好的代码实现:

 
#include<stdio.h>
int find_arr(int arr[3][3], int* row, int* col, int k)
{
    int x = 0, y = *col - 1;//从右上角开始找
    while (x < *row && y >= 0)
    {
        if (arr[x][y] > k)
        {
            y--;
        }
        else if (arr[x][y] < k)
        {
            x++;
        }
        else
        {
            *row = x;
            *col = y;
            return 1;
        }
    }
    return 0;
}
int main()
{
    int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
    int k = 0, x = 3, y = 3;
    scanf("%d", &k);
    //找到返回1 找不到返回0
    //传arr和行、列、要找的元素
    //传行和列的地址,则在函数中所求的下标就可以通过这两个地址放到x、y中
    if (find_arr(arr, &x, &y, k))
    {
        printf("找到了,下标是%d,%d\n",x,y);
        
    }
    else
    {
        printf("找不到\n");
    }
    return 0;
}
//这里传& x和& y的好处:
//既可以带进函数两个值:3和3,在函数中使用;
//又可以在函数结束的时候带回值——这种设计是返回型参数(输出型参数),
//用指针修改,把数值带回去。

3.9(编程)模拟实现qsort

自己敲出一个模拟的qsort并应用

目录
相关文章
|
8月前
|
存储 监控 算法
关于员工上网监控系统中 PHP 关联数组算法的学术解析
在当代企业管理中,员工上网监控系统是维护信息安全和提升工作效率的关键工具。PHP 中的关联数组凭借其灵活的键值对存储方式,在记录员工网络活动、管理访问规则及分析上网行为等方面发挥重要作用。通过关联数组,系统能高效记录每位员工的上网历史,设定网站访问权限,并统计不同类型的网站访问频率,帮助企业洞察员工上网模式,发现潜在问题并采取相应管理措施,从而保障信息安全和提高工作效率。
135 7
|
9月前
|
存储 人工智能 Java
一文轻松拿捏C语言的指针的基础使用
本文介绍了C语言中的指针概念,包括直接访问和间接访问内存的方式、指针变量的定义与使用、取址运算符`&`和取值运算符`*`的应用,帮助读者深入理解指针这一C语言的核心概念。君志所向,一往无前!
168 0
|
11月前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
879 14
|
11月前
|
存储 算法 C语言
【C语言】深入浅出:C语言链表的全面解析
链表是一种重要的基础数据结构,适用于频繁的插入和删除操作。通过本篇详细讲解了单链表、双向链表和循环链表的概念和实现,以及各类常用操作的示例代码。掌握链表的使用对于理解更复杂的数据结构和算法具有重要意义。
3301 6
|
11月前
|
存储 网络协议 算法
【C语言】进制转换无难事:二进制、十进制、八进制与十六进制的全解析与实例
进制转换是计算机编程中常见的操作。在C语言中,了解如何在不同进制之间转换数据对于处理和显示数据非常重要。本文将详细介绍如何在二进制、十进制、八进制和十六进制之间进行转换。
1722 5
|
11月前
|
C语言 开发者
【C语言】断言函数 -《深入解析C语言调试利器 !》
断言(assert)是一种调试工具,用于在程序运行时检查某些条件是否成立。如果条件不成立,断言会触发错误,并通常会终止程序的执行。断言有助于在开发和测试阶段捕捉逻辑错误。
279 5
|
8月前
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
790 29
|
8月前
|
前端开发 数据安全/隐私保护 CDN
二次元聚合短视频解析去水印系统源码
二次元聚合短视频解析去水印系统源码
283 4
|
8月前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
8月前
|
移动开发 前端开发 JavaScript
从入门到精通:H5游戏源码开发技术全解析与未来趋势洞察
H5游戏凭借其跨平台、易传播和开发成本低的优势,近年来发展迅猛。接下来,让我们深入了解 H5 游戏源码开发的技术教程以及未来的发展趋势。

推荐镜像

更多
  • DNS