您的位置:首页 > 编程语言 > C语言/C++

c++常考题

2016-09-25 20:12 253 查看

1. 如何判断一个单链表是否有环?(注意不能用标志位,最多只能用两个额外的指针)

2.strlen函数的写法,strcpy函数的手动写出

注意怎样才能拿到全部的分数!

#include <iostream>
#include <assert.h>
using namespace std;

void cpy(char *dest, const char *source){
assert(dest != NULL && source != NULL);
char *tempdest = dest;
while((*dest++ = *source++) != '\0')
{
}
dest = tempdest;
}
int length_s(const char *temp)
{
if(temp == NULL)
return 0;
int length = 0;

while(*temp++ != '\0')
{
length++;
}

return length;
}
int main()
{
char sourece[] = "chengyanglalalas";
char*temp = new char[100];
cpy(temp,sourece);
cout<<length_s(temp)<<endl;
cout<<temp<<endl;
return 0;
}


找错题

#include <iostream>
#include <cstring>
#include <stdlib.h>
using namespace std;

void getmemory(char *p) // char * &p
{
p = (char *)malloc(100);
}

int main()
{
char *str = NULL;
getmemory(str);
strcpy(str,"helloworld");
cout<<str<<endl;
return 0;
}


#include <iostream>
#include <cstring>
#include <stdlib.h>
using namespace std;

char* getmemory()
{
char p[] = "helloworld";
return p;
}

int main()
{
char *str = getmemory();
cout<<str<<endl;
return 0;
}


这一种也是错误,因为p[] 为函数的局部变量,当程序执行结束后,会自动释放内存。【需要理解变量的生命周期】。如果写成:static char p[] = “helloworld”; 就没事了~或者改成char *p = “helloworld”; 这样,helloworld是一个全局变量,所以返回地址的时候,是正确的~

#include <iostream>
#include <cstring>
#include <stdlib.h>
using namespace std;

void getmemory(char ** str, int num){
*str = (char *)malloc(num);
}

int main()
{
char *str = NULL;
getmemory(&str,100);
strcpy(str,"helloworld");
cout<<str<<endl;
return 0;
}


这里存在问题吗?

在申请内存及赋值语句上,str = (char )malloc(num); 之后没有判断是否申请成功!!!应当加上:

if(*str) == NULL{
//进行申请内存失败处理
}


之后还要对函数进行free!!!

#include <iostream>
#include <cstring>
#include <stdlib.h>
using namespace std;

下面的代码为什么没有发生错误?对它赋值,结果是超出了它本身的长度了啊?
int main()
{
cout<<sizeof(char)<<endl;
char *str = (char *)malloc(sizeof(char) * 10);
//char *str = new char[10];
strcpy(str,"helloworldssss");
cout<<str<<endl;
return 0;
}


swap(int *p1, int *p2)
{
int *p ;
*p = *p1;
*p1 = *p2;
*p2 = *p
}


这段程序是错误的,因为p是一个野指针,有可能指向系统区,导师程序运行崩溃。应该为如下:

swap(int *p1, int *p2)
{
int p ;
p = *p1;
*p1 = *p2;
*p2 = p
}


extern关键字和c/c++编译链接

下面的例子包含了c++调用c的全局变量和函数,以及c调用c++的函数和全局变量~

reference.cpp

#include <iostream>
#include <cstring>
#include <stdlib.h>
#include "cppfile.cpp"
extern "C" //表明使用c的风格进行编译file.c
{
#include "file.c"
}
using namespace std;
extern void add(int a, int b);
extern void usecpp(int s);
int main()
{
extern int a ;
extern int b ;
//extern char s[11] ; //必须指明长度...
extern char *s;
extern char str[11];
cout<<a<<endl;
cout<<b<<endl;
cout<<s<<endl;
cout<<str<<endl;
add(a,b);
usecpp(100);
return 0;
}


file.c

#ifndef __FILE__C
#define __FILE__C
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "cppfile.cpp"
int a = 100;
int b = 20;
//char s[11]= "helloworld";
char *s = "helloworld";
void add(int a, int b){
printf("the sum is %d \n",a+b);
}

extern void printcpp(int i); //c调用cpp的函数,加了extern意思是 在外部可以找到它的声明和定义

void usecpp(int s)
{
printcpp(s);
}
#endif


cppfile.cpp

#include <iostream>
#include <string.h>
#ifndef __CPPFILE__CPP
#define __CPPFILE__CPP
using namespace std;
char str[] = "helloworld";

extern "C" void printcpp(int i){ // 给编译器说明,按照c的风格编译该函数(以为c不支持重载)
cout<<"cppHeader  "<<i<<endl;
}
#endif


上面是一种做法,如何引用别人的全局变量。【如果别人的 c文件中并没有对变量声明为extern】(这种做法比较笨拙~)

另外一个应用场景是:自己定义cpp文件,加上extern int a = 100; 这种,供别的程序调用,而不用再写一遍extern int a;这种话了。

reference.cpp

#include <iostream>
using namespace std;
#include "test1.cpp"//不仅可以引用cpp中的函数和变量,还可以用c的~
int main()
{
printaabb(aa,bb);
return 0;
}


test1.cpp

#ifndef __test1__cpp
#define __test1__cpp

extern int aa = 100;
extern int bb = 20;
extern int printaabb(int aa, int bb)
{
cout<<aa<<" is aa"<<bb<<" is bb from test1.cpp"<<endl;
}
#endif


如何引用c的文件~

reference.cpp

#include <iostream>
using namespace std;
extern "C"{
#include "file.c"
}
int main()
{
printaabb(a,b,s);
return 0;
}


file.c

#ifndef __FILE__C
#define __FILE__C
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

extern int a = 100;//声明为全局变量
extern int b = 20;
extern char s[11]= "helloworld";
extern void printaabb(int aa, int bb,char s[])
{
cout<<aa<<" is aa"<<bb<<" is bb from file.c"<<endl;
cout<<s<<endl;
}
#endif


请记住, 只在头文件中做声明,真理总是这么简单第二种方法比较简单一点~

总结:

extern有两个作用

第一个,当它与”C”一起连用时,如: extern “C” void fun(int a, int b);则告诉编译器在编译fun这个函数名时按着C的规则去翻译相应的函数名而不是C++的,C++的规则在翻译这个函数名时会把fun这个名字变得面目全非,可能是fun@aBc_int_int#%$也可能是别的,这要看编译器的”脾气”了(不同的编译器采用的方法不一样),为什么这么做呢,因为C++支持函数的重载啊,在这里不去过多的论述这个问题,如果你有兴趣可以去网上搜索,相信你可以得到满意的解释!

第二,当extern不与”C”在一起修饰变量或函数时,如在头文件中: extern int g_Int; 它的作用就是声明函数或全局变量的作用范围的关键字,其声明的函数和变量可以在本模块活其他模块中使用,记住它是一个声明不是定义!也就是说B模块(编译单元)要是引用模块(编译单元)A中定义的全局变量或函数时,它只要包含A模块的头文件即可,在编译阶段,模块B虽然找不到该函数或变量,但它不会报错,它会在连接时从模块A生成的目标代码中找到此函数。

当函数提供方单方面修改函数原型时,如果使用方不知情继续沿用原来的extern申明,这样编译时编译器不会报错。但是在运行过程中,因为少了或者多了输入参数,往往会照成系统错误,这种情况应该如何解决?  答案与分析:  目前业界针对这种情况的处理没有一个很完美的方案,通常的做法是提供方在自己的xxx_pub.h中提供对外部接口的声明,然后调用方include该头文件,从而省去extern这一步。以避免这种错误。  宝剑有双锋,对extern的应用,不同的场合应该选择不同的做法。

函数指针及其的运用——何为函数指针

函数指针及其的运用——何为函数指针

http://www.cnblogs.com/uniqueliu/archive/2011/07/27/2118619.html

关于typedef的用法总结(推荐)

http://www.cnblogs.com/csyisong/archive/2009/01/09/1372363.html

C语言typedef的用法

http://www.cnblogs.com/afarmer/archive/2011/05/05/2038201.html

#include <iostream>
using namespace std;
typedef int (*fun)(int,int);
int max(int a,int b)
{
return a>b?a:b;
}
int main()
{
fun f;
f = max; // the first way
int (*p)(int,int) = &max; // the second way
cout<<f(1,222)<<endl;
cout<<p(1,32)<<endl;
return 0;
}


15道题目

#include <iostream>
using namespace std;
class Number{
public:
string type;
Number():type("void"){
}
explicit Number(short):type("short"){
}
Number(int):type("int"){
}
};
void Show(const Number &n)
{
cout<<n.type<<endl;
}
int main()
{
short s = 42;
Show(s);
return 0;
}

或者:

#include <iostream>
using namespace std;
class Number{
public:
string type;
Number():type("void"){
}
Number(short):type("short"){
}
explicit Number(int):type("int"){
}
};
void Show(const Number &n)
{
cout<<n.type<<endl;
}
int main()
{
int s = 42;
Number b(s);
Show(s); // short...因为隐式类型转换,它变成了short
return 0;
}


解释:传入的是short类型,但是short类型的构造函数被声明为explicit,也就是只能进行显示类型转换,不能使用隐式类型转换。

在C++中, 只有一个参数的构造函数除了具有构造函数的功能之外,它还是一个隐含的类型转换操作符。

class A
{
private:
int m_i;

public:
explicit A(int i)
{
m_i = i;
}
};

int main()
{
A a = 1;

return 0;
}


在不用explicit 关键字之前,下面的代码是无误的:A a = 1;,它会自动调用只有一个参数的构造函数进行类型转换。使用explicit关键字声明这个构造函数后编译直接报错,可以避免这种自动类型转换的发生。

double dArray[2] = {4,8},*p,*q;
p = &dArray[0];
q = p + 1;
cout<<*p<<endl;
cout<<*q<<endl;
cout<<p<<endl;
cout<<q<<endl;
cout<<q-p<<endl;


指针加减,按照的是指向地址类型的加减,只跟类型位置有关系,q和p指向的数据类型以实际数据类型来算差一个位置,因此q-p为1

int a[3];
a[0] = 0;
a[1] = 1;
a[2] = 2;
int *p,*q;
p = a;
cout<<p<<endl;
cout<<*p<<endl;
q = &a[2];
cout<<q<<endl;
cout<<*q<<endl;
cout<<a[q-p]<<endl;




指针与引用的区别

1)非空区别。指针可以为空,引用不可以

2) 合法性区别。在使用引用之前,不需要测试它的合法性,但是指针一定要测试是否为空

3)可修改区别。引用总是指向在初始化时被指定的对象,以后不能改变,但指定的对象的内容可以改变

4) 应用区别。下面情况应该使用指针:一是考虑到存在不指向任何对象的可能;二是需要能够在不同时刻指向不同的对象;如果总是指向一个对象并且一旦指向一个对象就不会改变指向,那么应该用引用

const常量赋值时必须初始化

const double di; //wrong
const double di = 192;//right


类存储空间偏移

#include <iostream>
using namespace std;
class A{
public:
A():mv_a(1),mv_b(2){
}
int mv_a;
int mv_b;
};
class B{
public:
B():mv_c(3){
}
void printC()
{
cout<<mv_c<<endl;
}
int mv_c;
};
int main()
{
A a;
B b = (B&)a;
b.printC();
return 0;
}
B 只有一个元素是int mv_c;但是a类的内存空间存放的第一个元素位置是m_a,  b的内存地址首地址,比如0x22ff52,当b.printC()调用B::printC()来打印m_c时,编译器对mv_c的认识
就是m_c距离对象的偏移量0,于是打印了对象a首地址的偏移量 0x22ff52+ 0,于是打印了是mv_a的值...


函数指针

int (*fun)(int ,int);
int *fun(int,int);
const int  *a;//const指针;
int *const b //指向const的指针
const int * const b ; //指向const的const指针
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息