• 程序员面试常见问题-整理-1


    程序员面试常见问题-整理-1
    2016.2.19 by Huangtao


    以下是海康威视应用软件开发工程师笔试题涉及到的一些知识:
    =====================================================================
    Sizeof(结构体):
    字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:
    1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
    2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
    3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。

    一个类能够实例化,编译器就需给它分配内存空间,来指示类实例的地址。这里编译器默认分配了一个字节(如:char,编译器相关),以便标记可能初始化的类实例,同时使空类占用的空间也最少(即1字节)。
    对于结构体和空类大小是1这个问题,首先这是一个C++问题,在C语言下空结构体大小为0(当然这是编译器相关的)。这里的空类和空结构体是指类或结构体中没有任何成员。
    在C++下,空类和空结构体的大小是1(编译器相关),这是为什么呢?为什么不是0?
    这是因为,C++标准中规定,“no object shall have the same address in memory as any other variable” ,就是任何不同的对象不能拥有相同的内存地址。 如果空类大小为0,若我们声明一个这个类的对象数组,那么数组中的每个对象都拥有了相同的地址,这显然是违背标准的。

    int *a; int &a; int & *a; int * &a
    int i;
    int *a = &i;//这里a是一个指针,它指向变量i
    int &b = i;//这里b是一个引用,它是变量i的引用,引用是什么?它的本质是什么?下面会具体讲述
    int * &c = a;//这里c是一个引用,它是指针a的引用
    int & *d;//这里d是一个指针,它指向引用,但引用不是实体,所以这是错误的


    数组指针和指针数组的区别:
    数组指针(也称行指针)
    定义 int (*p)[n];
    ()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。
    如要将二维数组赋给一指针,应这样赋值:
    int a[3][4];
    int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。
    p=a; //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
    p++; //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]
    所以数组指针也称指向一维数组的指针,亦称行指针。

    指针数组
    定义 int *p[n];
    []优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1是错误的,这样赋值也是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 *p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。
    如要将二维数组赋给一指针数组:
    int *p[3];
    int a[3][4];
    for(i=0;i<3;i++)
    p[i]=a[i];
    这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]
    所以要分别赋值。

    这样两者的区别就豁然开朗了,数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。
    还需要说明的一点就是,同时用来指向二维数组时,其引用和用数组名引用都是一样的。
    比如要表示数组中i行j列一个元素:
    *(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j]
    优先级:()>[]>*


    指针函数与函数指针的区别:
    1、指针函数是指带指针的函数,即本质是一个函数。函数返回类型是某一类型的指针
    类型标识符 *函数名(参数表)
    int *f(x,y);
    首先它是一个函数,只不过这个函数的返回值是一个地址值。函数返回值必须用同类型的指针变量来接受,也就是说,指针函数一定有函数返回值,而且,在主调函数中,函数返回值必须赋给同类型的指针变量。

    2、函数指针是指向函数的指针变量,即本质是一个指针变量。
    int (*f) (int x); /* 声明一个函数指针 */
    f=func; /* 将func函数的首地址赋给指针f */
    指向函数的指针包含了函数的地址,可以通过它来调用函数。声明格式如下:
    类型说明符 (*函数名)(参数)
    其实这里不能称为函数名,应该叫做指针的变量名。这个特殊的指针指向一个返回整型值的函数。指针的声明笔削和它指向函数的声明保持一致。
    指针名和指针运算符外面的括号改变了默认的运算符优先级。如果没有圆括号,就变成了一个返回整型指针的函数的原型声明。
    例如:
    void (*fptr)();
    把函数的地址赋值给函数指针,可以采用下面两种形式:
    fptr=&Function;
    fptr=Function;
    取地址运算符&不是必需的,因为单单一个函数标识符就标号表示了它的地址,如果是函数调用,还必须包含一个圆括号括起来的参数表。
    可以采用如下两种方式来通过指针调用函数:
    x=(*fptr)();
    x=fptr();
    第二种格式看上去和函数调用无异。但是有些程序员倾向于使用第一种格式,因为它明确指出是通过指针而非函数名来调用函数的。


    Const
    修饰指针:
    (位于星号左侧,用来修饰指针所指的变量,即指针指向为常量;位于星号右侧,用来修饰指针本身,即指针本身是常量)
    const int *A; 或 int const *A;
    //const修饰指向的对象,A可变,A指向的对象不可变
    int *const A;
    //const修饰指针A, A不可变,A指向的对象可变
    const int *const A;
    //指针A和A指向的对象都不可变


    指针和引用区别:(都是地址的概念)
    非空区别;
    合法性区别;
    可修改性区别;
    应用区别。


    C++中为什么用模板类?
    (1)可用来创建动态增长和减小的数据结构
    (2)它是类型无关的,因此具有很高的可复用性。
    (3)它在编译时而不是运行时检查数据类型,保证了类型安全
    (4)它是平台无关的,可移植性
    (5)可用于基本数据类型
    模板就是实现代码重用机制的一种工具。它实现了将类型参数化,就是将类型定义为参数,实现了真正的代码可重用性。模板分为两大类:函数模板和类模板。由于类模板包含类型参数,所以类模板又称作参数化的类。如果说类是对象的抽象,抽象是类的实例;那么可以说类模板是类的抽象,而类是类模板的实例。利用类模板可以建立各种数据类型的类。


    构造函数与析构函数的调用顺序
    http://blog.csdn.net/bresponse/article/details/6914155


    编写strcpy函数(10分)
    已知strcpy函数的原型是
    char *strcpy(char *strDest, const char *strSrc);
    其中strDest是目的字符串,strSrc是源字符串。
    (1)不调用C++/C的字符串库函数,请编写函数 strcpy
    char *strcpy(char *strDest, const char *strSrc);
    {
    assert((strDest!=NULL) && (strSrc !=NULL)); // 2分
    char *address = strDest; // 2分
    while( (*strDest++ = * strSrc++) != ‘/0’ ) // 2分
    NULL ;
    return address ; // 2分
    }

    (2)strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值?
    答:为了实现链式表达式。 // 2分
    例如 int length = strlen( strcpy( strDest, “hello world”) );

    //===================================================================
    // 利用栈来解决一个字符串之中使用的括号是否匹配的问题
    //===================================================================
    
    #include <iostream>
    using namespace std;
    
    #define stacksize 100   // 定义栈的空间大小
    
    // 定义栈的结构体
    struct stack
    {      
        char strstack[stacksize];
        int top;     
    };
    
    // 定义一个新栈s,初始化栈顶为-1
    void InitStack(stack &s)
    {    
        s.top = -1;
    }
    
    char Push(stack &s, char a)
    {
        if (s.top == stacksize - 1)
            return 0;
        s.top++;
        s.strstack[s.top] = a;
        return a;
    }
    
    char Pop(stack &s)
    {
        if (s.top == -1)
            return 0;
        char a = s.strstack[s.top];
        s.top--;
        return a;
    }
    
    // 栈为空时返回值为1
    int Empty(stack &s)
    {
        if (s.top == -1)
            return 1;
        else
            return 0;
    }
    
    // 检查括号是否匹配的函数
    int Check(char * str)
    {   
        stack s;
        InitStack(s);
        int strn = strlen(str);
        for (int i = 0; i < strn; i++)
        {
            char a = str[i];
            switch (a)
            {
            case '{':
            case '[':
            case '(':
                Push(s, a);        //若是左括号,则进行入栈操作
                break;
            case ')':            //若是右括号,则进行出栈操作,若出栈元素不是与输入相对应的左括号,则字符串括号中不匹配
                if (Pop(s) != '(')
                    return 0;
                break;
            case ']':
                if (Pop(s) != '[')
                    return 0;
                break;
            case '}':
                if (Pop(s) != '{')
                    return 0;
                break;
            default:break;
            }
        }
        int re = Empty(s);
        if (re == 1)
            return 1;    //栈为空
        else
            return 0;    //栈不为空,有左括号,即存在‘(’或'['或'{'未匹配
    }
    
    int main()
    {
        char str[100];
        cout << "请您输入一个长度小于100的字符串:" << endl;
        cin >> str;
        int re = Check(str);
        if (re == 1)
            cout << "您输入的字符串中的括号完全匹配!" << endl;
        else if (re == 0)
            cout << "您输入的字符串中的括号不匹配!" << endl;
    
        return 0;
    }
    //===================================================================
    // 用户输入M,N值,从1至N开始顺序
    // 循环数数,每数到M输出该数值,
    // 直至全部输出
    //===================================================================
    
    #include <stdio.h>
    
    // 节点
    typedef struct node
    {
        int data;
        node* next;
    }node;
    
    // 创建循环链表
    void createList(node*& head, node*& tail, int n)
    {
        if (n<1)
        {
            head = NULL;
            return;
        }
        head = new node();
        head->data = 1;
        head->next = NULL;
    
        node* p = head;
        for (int i = 2; i<n + 1; i++)
        {
            p->next = new node();
            p = p->next;
            p->data = i;
            p->next = NULL;
        }
    
        tail = p;
        p->next = head;
    }
    
    // 打印循环链表
    void Print(node*& head)
    {
        node* p = head;
    
        while (p && p->next != head)
        {
            printf("%d ", p->data);
            p = p->next;
        }
        if (p)
        {
            printf("%d
    ", p->data);
        }
    }
    
    void CountPrint(node*& head, node*& tail, int m)
    {
        node* cur = head;
        node* pre = tail;
    
        int cnt = m - 1;
        while (cur && cur != cur->next)
        {
            if (cnt)
            {
                cnt--;
                pre = cur;
                cur = cur->next;
            }
            else
            {
                pre->next = cur->next;
                printf("%d ", cur->data);
                delete cur;
                cur = pre->next;
                cnt = m - 1;
            }
        }
    
        if (cur)
        {
            printf("%d ", cur->data);
            delete cur;
            head = tail = NULL;
        }
        printf("
    ");
    }
    
    int main()
    {
        node* head;
        node* tail;
        int m;
        int n;
        scanf("%d", &n);
        scanf("%d", &m);
        createList(head, tail, n);
        Print(head);
        CountPrint(head, tail, m);
        return 0;
    }
  • 相关阅读:
    一个简单的反反爬~
    查缺补漏 -- python 之 and or的优先级
    从今天开始看《Redis深度历险》--HyperLogLog
    从今天开始看《Redis深度历险》--位图
    从今天开始看《Redis深度历险》--延时队列
    从今天开始看《Redis深度历险》--分布式锁
    redis之set【官方文档搬运+翻译】
    从今天开始看《Redis深度历险》--基础
    collections模块学习之namedtuple
    元组赋值谜题
  • 原文地址:https://www.cnblogs.com/ht-beyond/p/5201504.html
Copyright © 2020-2023  润新知