C/C++笔试题(13)

 

1.下面的代码输出是什么,为什么?
       void foo(void)
       {
            unsigned int a = 6;
            int b = -20;
            (a+b>6)?puts(">6"):puts("<=6");//puts
为打印函数
       }
输出 >6

就是考察隐式转换.int型变量转化成unsigned int, b成了正数.

2. b)运行下面的函数会有什么结果?为什么?
       void foo(void)
          {
               char string[10],str1[10];
               int i;
               for(i=0;i<10;i++)
               {
                    str1[i] = 'a';
               }
               strcpy(string, str1);
           printf("%s",string);
          }

首先搞清strcpy函数的实现方法,

char * strcpy(char * strDest,const char * strSrc)
{
 
 if ((strDest == NULL) || (strSrc == 
NULL)) 
 
  
 throw "Invalid argument(s)";
 
 char * strDestCopy = 
strDest; 
 
 while ((*strDest++ = *strSrc++) != 
'/0'); 
 
 return strDestCopy;
}

由于str1末尾没有‘/0’结束标志,所以strcpy不知道拷贝到何时结束.
printf
函数,对于输出char* 类型,顺序打印字符串中的字符直到遇到空字符('\0')或已打印了由精度指定的字符数为止.

下面是微软的两道笔试题....

3. Implement a string class in C++ with basic functionality like comparison, concatenation, input and output. Please also provide some test cases and using scenarios (sample code of using this class).

Please do not use MFC, STL and other libraries in your implementation.

我的实现方案如下,这道题真地对c++的主要特性都进行了较好地考察.

String.h:

#ifndef STRING_H
#define STRING_H

#include <iostream>
using namespace std;

class String{
   public:
    String();
       String(int n,char c);
    String(const char* source);
    String(const String& s);
    //String& operator=(char* s);
    String& operator=(const String& s);
    ~String();

    char& operator[](int i){return a[i];}
    const char& operator[](int i) const {return a[i];}//
对常量的索引
.
    String& operator+=(const String& s);
    int length();

   friend istream& operator>>(istream& is, String& s);//搞清为什么将>>设置为友元函数的原因.
   //friend bool operator< (const String& left,const String& right);
   friend bool operator> (const String& left, const String& right);//
下面三个运算符都没必要设成友元函数,这里是为了简单
.
   friend bool operator== (const String& left, const String& right);
   friend bool operator!= (const String& left, const String& right);
   private:
    char* a;
    int size;
};

#endif


String.cpp:


#include "String.h"
#include <cstring>
#include <cstdlib>

String::String(){
    a = new char[1];
    a[0] = '/0';
    size = 0;
}

String::String(int n,char c){
 a = new char[n + 1];
 memset(a,c,n);
 a[n] = '/0';
 size = n;
}

String::String(const char* source){

 if(source == NULL){
  a = new char[1];
  a[0] = '/0';
  size = 0;
 }
 else
 {   size = strlen(source);
  a = new char[size + 1];
  strcpy(a,source);
 }
}

String::String(const String& s){
 size = strlen(s.a);//
可以访问私有变量
.
 a = new char[size + 1];
 //if(a == NULL)
 strcpy(a,s.a);
}

 

String& String::operator=(const String& s){
 if(this == &s)
  return *this;
 else
 {
  delete[] a;
        size = strlen(s.a);
  a = new char[size + 1];
  strcpy(a,s.a);
  return *this;
 }
}
String::~String(){
 delete[] a;//    
}

String& String::operator+=(const String& s){
  int j = strlen(a);
  int size = j + strlen(s.a);
  char* tmp = new char[size+1];
  strcpy(tmp,a);
  strcpy(tmp+j,s.a);
 delete[] a;
 a = tmp;

 return *this;
 }

int String::length(){
 return strlen(a);
}

main.cpp:

#include <iostream>
#include "String.h"

using namespace std;

bool operator==(const String& left, const String& right)
{
 int a = strcmp(left.a,right.a);
    if(a == 0)
  return true;
 else
  return false;
}
bool operator!=(const String& left, const String& right)
{
 return  !(left == right);
}

ostream& operator<<(ostream& os,String& s){
 int length = s.length();
 for(int i = 0;i < length;i++)
  //os << s.a[i];
这么不行,私有变量
.
  os << s[i];
 return os;
}


String operator+(const String& a,const String& b){
 String temp;
 temp = a;
 temp += b;
 return temp;

}

bool operator<(const String& left,const String& right){
 
 int j = 0;
 while((left[j] != '/0') && (right[j] != '/0')){
  if(left[j] < right[j])
   return true;
  else
  {
   if(left[j] == right[j]){
    j++;
    continue;
   }
   else
    return false;
  }
 }
 if((left[j] == '/0') && (right[j] != '/0'))
  return true;
 else
  return false;
}

bool operator>(const String& left, const String& right)
{   int a = strcmp(left.a,right.a);
    if(a > 0)
  return true;
 else
  return false;
 
}

istream& operator>>(istream& is, String& s){
 delete[] s.a;
 s.a = new char[20];
 int m = 20;
    char c;
 int i = 0;
 while (is.get(c) && isspace(c));
    if (is) {
  do {s.a[i] = c;
       i++;
    /*if(i >= 20){
      cout << "Input too much characters!" << endl;
      exit(-1);
    }*/
    if(i == m - 1 ){
     s.a[i] = '/0';
     char* b = new char[m];
     strcpy(b,s.a);
                 m = m * 2;
        s.a = new char[m];
     strcpy(s.a,b);
     delete[] b;
    }
  }
  while (is.get(c) && !isspace(c));
        //
如果读到空白,将其放回
.
  if (is)
   is.unget();
 }
 s.size = i;
 s.a[i] = '/0';
 return is;
}


int main(){
 String a = "abcd";
 String b = "www";
 //String c(6,b);
这么写不对.
    String c(6,'l');
 String d;
 String e = a;//abcd
 String f;
 cin >> f;//
需要输入
...
 String g;
 g = a + b;//abcdwww

 if(a < b)
  cout << "a < b" << endl;
 else
  cout << "a >= b" << endl;
 if(e == a)
  cout << "e == a" << endl;
 else
  cout << "e != a" << endl;
 
 b += a;
 
 cout << a << endl;
 cout << b << endl;
    cout << c << endl;
 cout << d << endl;
 cout << e << endl;
 cout << f << endl;
 cout << g << endl;
 cout << g[0] << endl;
 return 0;
}

 

 

4. Implement a single-direction linked list sorting algorithm. Please first define the data structure of linked list and then implement the sorting algorithm.

 

5.编写一个函数,返回两个字符串的最大公串!例如,“adbccadebbca”“edabccadece”,返回“ccade”

 

联想笔试题


  1.设计函数 int atoi(char *s)

 int atoi(const char *nptr);     //字符串转化为数字
 
函数说明
 atoi()
会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再 遇到非数字或字符串结束时('/0')才结束转换,并将结果返回。
返回值 返回转换后的整型数。

#include <stdio.h>
#include <ctype.h>

int myAtoi(const char* s){
 int result = 0;
 int flag = 1;
 int i = 0;
 while(isspace(s[i]))    //
isspace 测试字符是否为空格字符
  i++;
 if(s[i] == '-'){
  flag = -1;
  i++;
 }
 if(s[i] == '+')
  i++;
 while(s[i] != '/0'){
  if((s[i] > '9') || (s[i] < '0'))
   break;
  int j = s[i] - '0';
  result = 10 * result + j;
  i++;
 }
 result = result * flag;
 return result;
}

int main(){
 char* a = "   -1234def";
 char* b = "+1234";
 int i = myAtoi(a);
 int j = myAtoi(b);
 printf("%d /n",i);
 printf("%d",j);
 return 0;
}


 

 

 2int i=(j=4,k=8,l=16,m=32); printf(“%d”, i); 输出是多少?

3.解释局部变量、全局变量和静态变量的含义。

4.解释堆和栈的区别。

一、预备知识程序的内存分配

一个由c/C++编译的程序占用的内存分为以下几个部分
1
、栈区(stack—   由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2
、堆区(heap —   一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3
、全局区(静态区)(static,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
4
、文字常量区  —常量字符串就是放在这里的。 程序结束后由系统释放
5
、程序代码区存放函数体的二进制代码。
二、例子程序
这是一个前辈写的,非常详细
//main.cpp
int a = 0;
全局初始化区
char *p1;
全局未初始化区
main()
{
int b;

char s[] = "abc";

char *p2;

char *p3 = "123456"; 123456/0
在常量区,p3在栈上。
static int c =0
全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得来得1020字节的区域就在堆区。
strcpy(p1, "123456"); 123456/0
放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}

二、堆和栈的理论知识

2.1申请方式
stack:
由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间

heap:
需要程序员自己申请,并指明大小,在cmalloc函数

p1 = (char *)malloc(10);
C++中用new运算符

p2 = (char *)malloc(10);
但是注意p1p2本身是在栈中的。


2.2
申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时, 会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,

这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

2.3申请大小的限制
栈:在Windows,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址

和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是 2M (也有的说是 1M ,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。


2.4
申请效率的比较:
栈由系统自动分配,速度较快。但程序员是无法控制的。
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。

2.5堆和栈中的存储内容
栈: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。

2.6存取效率的比较

char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa
是在运行时刻赋值的;

bbbbbbbbbbb是在编译时就确定的;
但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。
比如:
#include
void main()
{
char a = 1;
char c[] = "1234567890";
char *p ="1234567890";
a = c[1];
a = p[1];
return;
}
对应的汇编代码
10: a = c[1];
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
0040106A 88 4D FC mov byte ptr [ebp-4],cl
11: a = p[1];
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
00401070 8A 42 01 mov al,byte ptr [edx+1]
00401073 88 45 FC mov byte ptr [ebp-4],al
第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据edx读取字符,显然慢了。

堆和栈的区别及内存泄露- -
                                      

    堆和栈是两个不同的概念。在学微机原理时没有感觉到,因为书上只提到了堆栈;数据结构上也提到过栈。但是,始终不明白什么是堆,什么是栈。后来无意翻看了C++,才知道(只是知道,不是明白,更称不上懂)它们的区别。

    简单的来讲堆(heap)上分配的内存,系统不释放,而且是动态分配的。栈(stack)上分配的内存系统会自动释放,它是静态分配的。

    mallocnew分配的内存都是从heap上分配的内存,从heap上分配的内存必须有程序员自己释放,用free来释放,否则这块内存会一直被占用而得不到释放,就出现了内存泄露(Memory Leak。这样会造成系统的可分配内存的越来越少,导致系统崩溃。

    C/C++跨国语言,在任何平台上都可以使用。所以,Memory Leak在每个系统上都会出现。避免方法就是在写完malloc后,紧跟着就在下一行写free。然后在两行代码中间加其他的代码。哈哈,梁肇新的成对编码,这样会很好的解决。

 

5.论述含参数的宏与函数的优缺点。

 

普天C++笔试题


  1.实现双向链表删除一个节点P,在节点P后插入一个节点,写出这两个函数。

//假设线性表的双向链表存储结构
typedef struct DulNode{
    struct DulNode *prior;  //
前驱指针
     ElemType data;    //
数据
     struct DulNode *next;  //
后继指针
}DulNode,*DuLinkList;
//
删除操作
Status ListDelete_DuL(DuLinkList &L,int i,ElemType &e)
{
  if(!(p=GetElemP_DuL(L,i))) //
此处得到i位置的节点指针,如果有需要也得写出具体函数实现
    return ERROR;
  e=p->data;
  p->prior->next=p->next;
  p->next->prior=p->prior;
  free(p);
  return OK;
}
//
插入操作
Status ListInsert_DuL(DuLinkList &L,int i,ElemType &e)
{
  if(!(p=GetElemP_DuL(L,i)))
    return ERROR;
  if(!(s=(DuLinkList)malloc(sizeof(DuLNode)))) 
    return ERROR;

  s->data=e;
  s->prior=p->prior;
  p->prior->next=s;
  s->next=p;
  p->prior=s;
  return OK;
}

2.写一个函数,将其中的/t都转换成4个空格。

该函数命名为convert,参数的意义为:
*strDest
目的字符串,*strSrc源字符串,length源字符串的长度
函数实现为:

char* convert(char *strDest, const char *strSrc,int length)
{
  char * cp = strDest;
  int i=0;
  while(*strSrc && i<length)  // 
跳出条件

  {
    if (*strSrc=='/t')  //
/t转换成4个空格
    {
      for(int j=0;j<4;j++)
        *cp++=' ';
    }
    else      //
否则直接拷贝 
      *cp++=*strSrc;
    strSrc++;
    i++;
  }
  return strDest;
}

3Windows程序的入口是哪里?写出Windows消息机制的流程。

Windows程序的入口是WinMain函数.消息机制:系统将会维护一个或多个消息队列,所有产生的消息都会被放入或是插入队列中。系统会在队列中取出每一条消息,根据消息的接收句柄而将该消息发送给拥有该窗口的程序的消息循环。每一个运行的程序都有自己的消息循环,在循环中得到属于自己的消息并根据接收窗口的句柄调用相应的窗口过程。而在没有消息时消息循环就将控制权交给系统。

4.如何定义和实现一个类的成员函数为回调函数?

所谓的回调函数,就是预先在系统的对函数进行注册,让系统知道这个函数的存在,以后,当某个事件发生时,再调用这个函数对事件进行响应。
定义一个类的成员函数时在该函数前加CALLBACK即将其定义为回调函数,函数的实现和普通成员函数没有区别

5C++里面是不是所有的动作都是main()引起的?如果不是,请举例。

不是,比如中断引起的中断处理不是直接由main()引起的,而是由外部事件引起的。

在运行c++程序时,通常从main()函数开始执行。因此如果没有main(),程序将不完整,编译器将指出未定义main()函数。
  
例外情况:如, windows编程中,可以编写一个动态连接库(dll)模块,这是其他windows程序可以使用的代码。由于DLL模块不是独立的程序,因此不需要main().用于专用环境的程序--如机器人中的控制器芯片--可能不需要main().但常规的独立程序都需要main().

比如全局变量的初始化,就不是由main函数引起的.但是这个初始化动作并不能为编译器的断点所截断

6C++里面如何声明const void f(void)函数为C程序中的库函数?

在该函数前添加extern “C”声明

7.下列哪两个是等同的
  int b;
  
A const int* a = &b;
  
B const* int a = &b;
  
C const int* const a = &b;
  D int const* const a = &b;

各式表示的意思分别为:
A const int* a = &b; //*a
const,但指针a可变
B const* int a = &b; //a
const,但*a可变
C const int* const a = &b; //a
*a都是const,常量和指针的值都不能改变
D int const* const a = &b; //a
*a都是const,常量和指针的值都不能改变
因此CD两者是相同的。
总结个技巧:如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。

8.内联函数在编译时是否做参数类型检查?

做类型检查,因为内联函数就是在程序编译时,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体来代替。

void g(base & b){
  
b.play;
  
}
  
void main(){
  
son s;
  
g(s);
  
return;
  }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值