c++常考题

本文探讨了C++编程中的常见技巧与易犯错误,包括字符串处理、内存管理、函数指针使用、类型转换控制等内容,并提供了实用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}
  1. 找错题
#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指针
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值