牛客模拟面试-03

静态库和动态库如何制作及使用,区别是什么

静态库在程序的链接阶段链接到可执行文件中,其实静态库就是一堆目标文件的集合

构建静态库

alt

使用这个命令也可以编译成功,但是这样很繁琐,不如将其功能打包成一个静态库 gcc main.c ./src/add.c ./src/div.c ./src/mult.c ./src/sub.c ./include/head.h -o app

静态库制作

cd src

将源文件编译成目标文件

gcc -c add.c div.c mult.c sub.c

之后会编译而不链接生成 add.o dic.o mult.o sub.o

使用ar命令构建静态库

注意libcalc.a在使用-l时,链接器会忽略lib和.a前缀和后缀,所以只需要-lcalc即可

ar rv ../lib/libcalc.a add.o div.o mult.o sub.o

显示打包文件的内容

ar t ../lib/libcalc.a

编译main.c

gcc -c main.c

链接静态库并编译目标文件main.o,这里需要指定连接静态库的目录和包含头文件的目录

gcc main.o -o app -lcalc -L ./lib/ -I ./include/

运行可执行文件(编译链接后的) ./app

构建动态库

alt

到了程序中;动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加 载到内存中供程序调用。

cd src

PIC表示位置无关代码的意思 -f表示设置PIC为true

gcc -c -fPIC add.c sub.c mult.c div.c

gcc -shared add.o sub.o mult.o div.o -o ../lib/libcalc.so

gcc main.c -o app -I ./include/ -l calc -L ./lib/

直接运行./app会报错,找不到动态库的路径

  • 静态库:GCC 进行链接时,会把静态库中代码打包到可执行程序中
  • 动态库:GCC 进行链接时,动态库的代码不会被打包到可执行程序中
  • 程序启动之后,动态库会被动态加载到内存中,通过 ldd (list dynamic dependencies)命令检查动态库依赖关系
  • 如何定位共享库文件呢? 当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径。 此时就需要系统的动态载入器来获取该绝对路径。 对于elf格式的可执行程序,是 由ld-linux.so来完成的, 它先后搜索elf文件的 DT_RPATH段 ——> 环境变量 LD_LIBRARY_PATH ——> /etc/ld.so.cache文件列表 ——>/lib/,/usr/lib 目录找到库文件后将其载入内存。

通过ldd指令检查app的动态依赖关系如下,发现找不到所以来的动态链接库libcalc.so的绝对路径。 以下方法只在当前终端有效

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/yeahqing/git/CppLearn/CxxProjects/静态库和动态库的构建/动态库的构建/lib

以下方法永久有效

方法一: 修改当前用户的环境变量 vim ~/.bashrc 最后一行插入: export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/usr_name/linux/lession06/library/lib source ~/.bashrc

修改系统环境变量 方法二: sudo vim /etc/profile 最后一行插入:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/usr_name/linux/lession06/library/lib source /etc/profile

方法三 配置/etc/ld.so.cache文件列表 sudo vim /etc/ld.so.conf 最后一行插入:/home/usr_name/linux/lession06/library/lib sudo ldconfig

方法四 将所依赖度动态库复制到/lib或/usr/lib目录下也可,但不推荐,因为这两个目录下有大量的系统库文件

修改Ubuntu20.04下的终端只显示当前目录名

修改当前用户的~/.bashrc 使用:62找到第62行。 将里面的小写w改为大写W即可。之后保存退出,使用source ~/.bashrc使其生效。


if [ "$color_prompt" = yes ]; then
    PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
    PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi

说一说STL 中常见容器的实现原理

【得分点】

vector、deque、stack、queue、list、set、map

【参考答案】

标准回答

  1. vector

vector 是一种动态数组,在内存中具有连续的存储空间,支持快速随机访问,由于具有连续的存储空间,所以在插入和删除操作方面,效率比较慢。

  1. deque

deque 是一种双向开口的连续线性空间,元素在内存连续存放,随机存取任何元素都在常数时间完成,在两端增删元素具有较佳的性能。

  1. stack

stack 是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口。stack 容器允许新增元素,移除元素,取得栈顶元素,但是除了最顶端外,没有任何其他方法可以存取 stack 的其他元素,stack 不允许有遍历行为。

  1. queue

queue 是一种先进先出(First In First Out,FIFO)的数据结构,它有两个出口,queue 容器允许从一端新增元素,从另一端移除元素。

  1. list

list 内部实现的是一个双向链表,元素在内存不连续存放,在任何位置增删元素都能在常数时间完成,不支持随机存取。

  1. map map内部自建一棵红黑树(一种自平衡二叉树),这棵树具有数据自动排序的功能,所以在map内部所有的数据都是有序的,以二叉树的形式进行组织。

  2. set

set 底层使用红黑树实现,插入删除操作时仅仅移动指针即可,不涉及内存的移动和拷贝,所以效率比较高。set 中的元素都是唯一的,而且默认情况下会对元素进行升序排列。不能直接改变元素值,因为那样会打乱原本正确的顺序,要改变元素值必须先删除旧元素,再插入新元素。不提供直接存取元素的任何操作函数,只能通过迭代器进行间接存取。

简述一下堆和栈的区别

【得分点】

管理方式、空间大小、是否产生内存碎片、生长方向、分配方式、分配效率

【参考答案】

标准回答

堆和栈主要有如下几点区别:管理方式、空间大小、是否产生内存碎片、生长方向、分配方式、分配效率。

  1. 管理方式

对于栈来讲,是由编译器自动管理,无需手动控制;对于堆来说,分配和释放都是由程序员控制的。

  1. 空间大小

总体来说,栈的空间是要小于堆的。堆内存几乎是没有什么限制的;但是对于栈来讲,一般是有一定的空间大小的。

  1. 碎片问题

对于堆来讲,由于分配和释放是由程序员控制的(利用new/delete 或 malloc/free),频繁的操作势必会造成内存空间的不连续,从而造成大量的内存碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的数据结构,在某一数据弹出之前,它之前的所有数据都已经弹出。

  1. 生长方向

对于堆来讲,生长方向是向上的,也就是沿着内存地址增加的方向,对于栈来讲,它的生长方式是向下的,也就是沿着内存地址减小的方向增长。

  1. 分配方式

堆都是动态分配的,没有静态分配的堆。栈有两种分配方式:静态分配和动态分配,静态分配是编译器完成的,比如局部变量的分配;动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,它的动态分配是由编译器实现的,无需我们手工实现。

  1. 分配效率

栈是机器系统提供的数据结构,计算机会在底层对栈提供支持,分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率很高。堆则是C/C++ 函数提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率要比栈底的多。

编程题: 01背包问题,动态规划

版本1


int knapsack(int V, int n, vector<vector<int> >& vw) {
 	vector<vector<int>> dp(n+1, vector<int>(V+1));
  
  	for (int i = 1; i <= n; i++)
    {
    	for (int j = 1; j <= V; j++)
        {
        	dp[i][j] = dp[i-1][j];
          	if (j >= vw[i-1][0])
            {
            	dp[i][j] = max(dp[i][j], dp[i-1][j-vw[i-1][0]] + vw[i-1][1]);
            }
        }
    }
  	return dp[n][V];
}


int knapsack(int V, int n, vector<vector<int> >& vw) {
	
  vector<int> dp(V+1, 0);
  
  for(int i = 0; i < n; i++){
  	for (int j = V; j >= vw[i][0]; j--)
    {
    	dp[j] = max(dp[j], dp[j - vw[i][0]] + vw[i][1]);
    }
  }
  
  return dp[V];
}

全部评论

相关推荐

安静的垂耳兔在泡澡:ks已经第八次投递了,它起码挂了还让你再投,不错了
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务