程序員面試常見問題-整理-1

程序員面試常見問題-整理-1
2016.2.19 by Huangtaonode


如下是海康威視應用軟件開發工程師筆試題涉及到的一些知識:
=====================================================================
Sizeof(結構體):
字節對齊的細節和編譯器實現相關,但通常而言,知足三個準則:
1) 結構體變量的首地址可以被其最寬基本類型成員的大小所整除;
2) 結構體每一個成員相對於結構體首地址的偏移量(offset)都是成員大小的整數倍,若有須要編譯器會在成員之間加上填充字節(internal adding);
3) 結構體的總大小爲結構體最寬基本類型成員大小的整數倍,若有須要編譯器會在最末一個成員以後加上填充字節(trailing padding)。ios

一個類可以實例化,編譯器就需給它分配內存空間,來指示類實例的地址。這裏編譯器默認分配了一個字節(如:char,編譯器相關),以便標記可能初始化的類實例,同時使空類佔用的空間也最少(即1字節)。
對於結構體和空類大小是1這個問題,首先這是一個C++問題,在C語言下空結構體大小爲0(固然這是編譯器相關的)。這裏的空類和空結構體是指類或結構體中沒有任何成員。
在C++下,空類和空結構體的大小是1(編譯器相關),這是爲何呢?爲何不是0?
這是由於,C++標準中規定,「no object shall have the same address in memory as any other variable」 ,就是任何不一樣的對象不能擁有相同的內存地址。 若是空類大小爲0,若咱們聲明一個這個類的對象數組,那麼數組中的每一個對象都擁有了相同的地址,這顯然是違背標準的。c++

 

 

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]
優先級:()>[]>*安全


指針函數與函數指針的區別:
一、指針函數是指帶指針的函數,即本質是一個函數。函數返回類型是某一類型的指針
類型標識符 *函數名(參數表)
int *f(x,y);
首先它是一個函數,只不過這個函數的返回值是一個地址值。函數返回值必須用同類型的指針變量來接受,也就是說,指針函數必定有函數返回值,並且,在主調函數中,函數返回值必須賦給同類型的指針變量。數據結構

二、函數指針是指向函數的指針變量,即本質是一個指針變量。
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\n", 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("\n");
}

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;
}
相關文章
相關標籤/搜索