C/C++练习题(二)

1、下面这些指针分别代表什么?

float(**p1)[10];
double*(*p2)[10];
double(*p3[10])();
int*((*p4)[10]);
long(**p5)(int(*a)[]);

p1是一个二维指针,它指向的一维指针又指向了一个数组,这个数组的类型是float[10]; p2是一个指针,它指向了一片数组,这个数组的每个元素的类型是double p3是一个10个元素的数组,数组的每个元素都是一个函数指针,即double()(); p4是一个二维指针,这个二维指针指向了一个函数指针(注意指向的不是函数而是函数指针),这个函数指针指向的函数的返回值是long,参数是一个指向类型为int大小为10的一个数组。



2、查找字符串中第一个只出现一次的字符并输出。(如:aabbcddefg 则输出 'c')

分析:这个问题只要考察是否有空间换时间的思想。 因为这里出现的都是ASCII码,所以我们建立一个大小为256的数组,之后遍历字符串,以字符串中的字符为下标累加数组元素,这样我们就可以得到一个直方图。

void findOneChar(const char* str)
{
    int array[256] = {0};
    char* p = (char*)s;

    while( *p )
    {
        array[*p++]++;
    }
    while( *s && (array[*s] != 1) )
    {
        s++;
    }
    printf("%c\n", *s);
}

1、下面程序有问题吗?如果有,请指出。

#include <stdio.h>
char* ptr = (char*)malloc(10);

void main(void)
{
    if(NULL == ptr)
    {
        printf("malloc failed!\n");
        return;
    }
    else
    {
        // Do something...
    }
    return;
}

1、程序中使用了malloc,起码要包含一些头文件吧; 2、ptr是全局变量,全局变量要使用常量来初始化。这里会编译出错。 3、即使忽略上面的情况,程序也可能会造成内存泄露,大家可能认为现代OS在进程结束的时候就会回收这个进程申请的内存资源,但是如果致力于嵌入式开发,我们就需要考虑一些小型的操作系统,因为一些特殊的目的并没有实现这样的自动回收功能,所以,必须要谨慎。


2、下面程序有问题吗?如果有,请指出并修改。

#include <stdio.h>

int main(int argc, char* argv[])
{
    int flag = 0;
    char passwd[10];
    memset(passwd, 0, sizeof(passwd));
    strcpy(passwd, argv[1]);

    if(0 == strcmp("LinuxGeek", passwd))
    {
        flag = 1;
    }
    
    if(flag)
    {
        printf("PASS\n");
    }
    else
    {
        printf("ERROR\n");
    }
    
}

除开那些包含头文件之类的错误,这个程序最大的问题就是安全性。 这个程序从功能来看是用来检测密码的,如果用户输入LinuxGeek的时候通过检测,但是由于使用了strcpy和strcmp,那么当用户输入超过10的时候就会产生越界。由于栈地址是从高地址往低地址增长的,所以passwd后面的空间恰好是flag对应的空间,这样当输入超过长度为10的字符串时,flag就会被修改成非0值(经过测试bcc32 结果为error , qt下为pass,所以有没有污染还是要看编译器,但是我们不能编写依赖编译器的代码,一定要规范。),于是检测通过,PASS就会被输出。 所以我们应该使用strncpy和strncmp来加强安全性。



3、有两个程序a和b都有相同的代码,如下: int buffer[16] ...... printf("%p", &buffer[0]); printf("buffer[0] = %d", buffer[0]);

同时运行a和b最终程序输出: 0x20001300 buffer[0] = 100 0x20001300 buffer[0] = 1000

为什么会有相同和不同的结果??


首先,为什么两个程序的数组地址居然一样呢? 题目没有说明是什么样的数组,是全局的还是局部的,但是两个程序的代码是一样的,如果使用相同的编译器的话,最终生成的可执行程序也是一样的。

好,现在程序运行成为进程。 要知道,现代操作系统都有虚拟空间的,每个进程独享自己的4G虚拟空间,所以说这里的地址一样。程序运行的实际物理地址是不一样的,但是我们看不到;至于buffer[0]的值不同,是因为没有初始化,值是随机的。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 函数指针数组的指针

    pf是一个指针,这个指针指向一个有3个元素的数组,每个元素是一个参数为char* ,返回值为char *的指针。 示例:

    Daotin
  • 图片瀑布流,so easy!

    简单来说,就是有很多图片平铺在页面上,每张图片的宽度相同,但是高度不同,这样错落有致的排列出 n 列的样子很像瀑布,于是就有了瀑布流图片一说。

    Daotin
  • 正本清源区块链——Caoz

    本课程内容分为两部分: 第一部分,烧脑篇,介绍区块链的技术概念,目标本源和技术演进,以及信息安全相关的风险。 第二部分,诱惑篇,介绍区块链的产业链,相关产业...

    Daotin
  • LeetCode 400.第N个数字 - JavaScript

    在无限的整数序列 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, …中找到第 n 个数字。

    心谭博客
  • 使用monit搭建一个监控系统

    马哥linux运维 | 最专业的linux培训机构 ---- 上周用monit搭建或者说定制了一个监控系统,来监控服务器发生事情。当然了主要是监控异常,因为我...

    小小科
  • 设置Spring单元测试的外部依赖

    比如单元测试中依赖redis-mock,就必须在Spring上下文下载之前就先启动Redis Server,否则就会报下面的错误

    十毛
  • 巧用闪回数据库来查看历史数据 (r10笔记第47天)

    国庆期间有一个例行维护的任务,需要在大早上7点起来,先根据业务指定的SQL查出指定数据,然后运行一个存储过程来更新数据。 查出来的这部分数据需要...

    jeanron100
  • 矩阵分解之SVD和SVD++

    上述两个问题,在矩阵分解中可以得到解决。原始的矩阵分解只适用于评分预测问题,这里所讨论的也只是针对于评分预测问题。

    abs_zero
  • $(window).load()与$(document).ready()的区别

    1.执行时间不同:从字面的意思上理解,$(document).ready()就是文档准备好了。也就是浏览器已经解析完整个html文档,dom树已经建立起来了,...

    java达人
  • 双边过滤算法

         双边过滤算法作为一种改进的高斯过滤算法,在图像去噪,和均匀模糊(又称为磨皮),去锯齿效应上有不错的效果.双边过滤是采用Raised cosines函数...

    Gxjun

扫码关注云+社区

领取腾讯云代金券