linux c/c++面試知識點(diǎn)整理(四)

31、printf輸出時在%和字母之間插入數(shù)字表示場寬的規(guī)則?

? ? ? ?當(dāng)實(shí)際長度不夠時, 右對齊;
? ? ? ?如果字符串或者整數(shù)的長度超過說明的場寬, 則按其實(shí)際長度輸出;
? ? ? ?如果是浮點(diǎn)數(shù), 若整數(shù)部分超過了說明的整數(shù)位場寬, 則按其實(shí)際長度輸出, 若是小數(shù)部分超過了說明的小數(shù)位場寬, 則按說明的寬度以四舍五入輸出。

32、逗號表達(dá)式?

? ? ? ?例如:printf(“%d %d %d\n”, (a,b,c),b,c);
? ? ? ?那么將輸出才c,b,c這3個值,因?yàn)槎禾柋磉_(dá)式的值就是表達(dá)式中最后一個表達(dá)式的值;
? ? ? ?即:表達(dá)式1,表達(dá)式2,表達(dá)式3…表達(dá)式n 就是表達(dá)式n的值。

33、c語言中標(biāo)識符第一次字符必須是什么?

? ? ? ?第一個字符必須是字母或者下劃線,不能是數(shù)字。

34、數(shù)據(jù)流程圖(DFD圖)是什么

? ? ? ?DFD圖是結(jié)構(gòu)化方法的需求分析工具。

35、hash_set和set的區(qū)別?

? ? ? ?hast_set以hashtable為底層機(jī)制,而set以RB-tree(紅黑樹)為底層機(jī)制;
? ? ? ?set有元素自動排序功能,而hash_set沒有;
? ? ? ?set可在logN下完成查找、插入和刪除等操作,hash_set可在常數(shù)時間復(fù)雜度下完成這些操作,但是取決于哈希表的負(fù)載情況;
? ? ? ?hast_multiset則允許鍵值重復(fù);

36、static的用途以及類中使用static的規(guī)則。

? ? ? ?用途:
? ? ? ?static限制變量的作用域;
? ? ? ?static不顯示的初始化時,會被隱式的初始化為0;
? ? ? ?static設(shè)置變量的存儲域,變量存儲在靜態(tài)區(qū);
? ? ? ?類中使用static的規(guī)則:
? ? ? ?不能通過類名來調(diào)用類的非靜態(tài)成員函數(shù),可以調(diào)用靜態(tài)成員函數(shù);
? ? ? ?類的對象可以使用靜態(tài)成員函數(shù)和非靜態(tài)成員函數(shù);
? ? ? ?類的靜態(tài)成員函數(shù)中不能使用類的非靜態(tài)成員,因?yàn)榇藭r靜態(tài)成員函數(shù)已經(jīng)分配了存儲空間,而非靜態(tài)成員卻還沒有分配內(nèi)存,相當(dāng)于變量聲明了但是未定義就直接使用;
? ? ? ?類的非靜態(tài)成員函數(shù)(包括常函數(shù))可以使用類的靜態(tài)成員函數(shù)和靜態(tài)成員變量,并且非靜態(tài)成員常函數(shù)可以修改靜態(tài)成員變量;
? ? ? ?類的靜態(tài)成員變量必須初始化以后才能使用;

37、數(shù)據(jù)庫三范式

? ? ? ?第一范式:數(shù)據(jù)庫表中的所有字段值都是不可分解的原子值,比如地址字段,根據(jù)需求拆分成省份和城市更方便
? ? ? ?第二范式:在一個數(shù)據(jù)庫表中,一個表中只能保持一種數(shù)據(jù),不可以把多種數(shù)據(jù)保存在同一張數(shù)據(jù)庫表中,比如訂單信息和商品信息就要分為兩個表
? ? ? ?第三范式:每一列數(shù)據(jù)都和主鍵直接相關(guān),而不能間接相關(guān),就是說字段值要和主鍵有直接關(guān)系
巴斯-科德范式:第三范式的一個子集,在第一范式基礎(chǔ)上,任何非主屬性不能對主鍵子集依賴。

38、網(wǎng)絡(luò)編程中設(shè)計(jì)并發(fā)服務(wù)器,使用多進(jìn)程和多線程,請問有什么區(qū)別?

? ? ? ?1)兩者都可以提高程序的并發(fā)度,提高程序運(yùn)行效率和響應(yīng)時間
? ? ? ?2)線程和進(jìn)程在使用上各有優(yōu)缺點(diǎn):線程執(zhí)行開銷小,但不利于資源管理和保護(hù);而進(jìn)程正相反。

39、可以用作switch的參數(shù)的類型

? ? ? ?int、short、byte、char、long
? ? ? ?基本上可以轉(zhuǎn)換為整數(shù)的類型都可以用作switch的參數(shù)。

40、linux使用多線程的方法

? ? ? ?互斥鎖、信號量、條件變量、全局變量、讀寫鎖。
? ? ? ?1)互斥鎖:當(dāng)線程A鎖定了互斥變量時,線程B再去鎖定時就會被掛起,直到A解鎖。
? ? ? ?注意:當(dāng)線程要不斷的去輪詢檢查某個條件以判斷是否可以操作需同步的數(shù)據(jù)時,可使用條件變量提高效率。
demo如下:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

pthread_mutex_t mutex;

void *print_msg(void *arg)
{
    int i = 0;
    pthread_mutex_lock(&mutex); //互斥鎖加鎖
    for (i = 0; i < 20; i++)
    {
        printf(" i = %d\n", i);
        usleep(200);
    }
    pthread_mutex_unlock(&mutex);

}

int main()
{
    pthread_t id1, id2;
    pthread_mutex_init(&mutex, NULL);
    pthread_create(&id1, NULL, print_msg, NULL);
    pthread_create(&id2, NULL, print_msg, NULL);
    pthread_join(id1, NULL);  //使主線程等待該線程結(jié)束后才結(jié)束,否則主線程很快結(jié)束,該線程沒有機(jī)會執(zhí)行
    pthread_join(id2, NULL);
    pthread_mutex_destroy(&mutex);

    return 0;
}

? ? ? ?2)信號量:實(shí)際是一個整數(shù),只要信號量的value大于0,其他線程就可以sem_wait成功,成功后信號量的value減1。若value值不大于0,則sem_wait使得線程阻塞,直到sem_post釋放后value值加1,但是sem_wait返回之前還是會將此value值減1。
demo如下:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
#include <stdlib.h>

void *thread_func(void* msg);
sem_t sem;
sem_t sem_add;

#define MSG_SIZE 512

int main()
{
    int res = -1;
    pthread_t thread;
    void *thread_result = NULL;
    char msg[MSG_SIZE];

    res = sem_init(&sem, 0, 0);
    if (res == -1)
    {
        printf("sem init failed\n");
        exit(-1);
    }

    res = sem_init(&sem_add, 0, 1);
    if (res == -1)
    {
        printf("sem_add init failed\n");
        exit(-1);
    }

    res = pthread_create(&thread, NULL, thread_func, msg);
    if (res != 0)
    {
        printf("pthread_create failed\n");
        exit(-1);
    }
    printf("input some text. Enter 'end' to finish...\n");
    
    sem_wait(&sem_add);
    while(strcmp("end\n", msg) != 0)
    {
        if (strncmp(msg, "TEST", 4) == 0)
        {
            strcpy(msg, "copy_data\n");
            sem_post(&sem);
            sem_wait(&sem_add);
        }
        fgets(msg, MSG_SIZE, stdin);
        sem_post(&sem);  //sem信號量加1,讓子線程開始執(zhí)行
        sem_wait(&sem_add);  //sem_add信號量減1,等待子線程處理完成

    }

    printf("waiting for thread to finish...\n");
    res = pthread_join(thread, &thread_result);
    if (res != 0)
    {
        printf("pthread_join faild\n");
        exit(-1);
    }

    printf("thread joined\n");

    sem_destroy(&sem);
    sem_destroy(&sem_add);
    exit(0);

    return 0;
}

void* thread_func(void* msg)
{
    char *ptr = (char*)msg;
    sem_wait(&sem);
    while(strcmp("end\n", ptr) != 0)
    {
        int i = 0;
        for (; ptr[i] != '\0'; ++i )
        {
            if (ptr[i] >= 'a' && ptr[i] <= 'z')
            {
                ptr[i] -= 'a' - 'A';
            }
        }
        printf("you input %d characters\n", i - 1);
        printf("to uppercase: %s\n", ptr);

        sem_post(&sem_add);
        sem_wait(&sem);
    }
    sem_post(&sem_add);
    pthread_exit(NULL);
}

? ? ? ?3)條件變量:經(jīng)常和互斥鎖一起使用,使用時,條件變量被用來阻塞一個線程,當(dāng)條件不滿足時,線程會解開相應(yīng)的互斥鎖并等待條件發(fā)生變化,一旦其他的某個線程改變了條件變量,它將通知相應(yīng)的條件變量喚醒一個或多個正被此變量阻塞的線程,這些線程將重新鎖定互斥鎖并重新測試條件是否滿足。
? ? ? ?pthread_cont_init()
? ? ? ?pthread_cont_destroy()
? ? ? ?pthread_cont_wait() //線程解開mutex指向的鎖并被條件變量阻塞
? ? ? ?pthread_cont_timedwait() //多了時間參數(shù),當(dāng)時間過了以后,即使條件變量不滿足,阻塞也被解除
? ? ? ?pthread_cont_signal()/pthread_cont_broadcast //喚醒被條件變量阻塞的線程。
demo見我的另外一篇文章:
linux c/c++ 面試題目整理(四)中的第34題
? ? ? ?4)讀寫鎖:可以多個線程同時占用讀模式的讀寫鎖,但是只能一個線程占用寫模式的讀寫鎖。
? ? ? ?當(dāng)讀寫鎖是寫加鎖狀態(tài)時,在這個鎖被解鎖前,所有試圖對這個鎖加鎖的線程都會被阻塞;
? ? ? ?當(dāng)讀寫鎖是讀加鎖狀態(tài)時,其他線程可以讀模式得到訪問權(quán),但是以寫模式對它進(jìn)行加鎖的線程都將被阻塞;
? ? ? ?當(dāng)讀寫鎖是在讀模式加鎖狀態(tài)時,如果有其他線程試圖以寫模式加鎖,讀寫鎖通常會阻塞隨后的讀模式鎖請求,避免讀模式鎖長期占用,而寫模式所長期阻塞;
讀寫鎖適用于對數(shù)據(jù)讀的次數(shù)比寫的次數(shù)多的情況。
? ? ? ?API接口:
? ? ? ?初始化和銷毀:
? ? ? ?int pthread_rwlock_init();
? ? ? ?int pthread rwlock_destroy();
? ? ? ?讀加鎖、寫加鎖、解鎖:
? ? ? ?pthread_rwlock_rdlock();
? ? ? ?pthread_rwlock_wrlock();
? ? ? ?pthread_rwlock_unlock();
? ? ? ?非阻塞獲得讀鎖和寫鎖:
? ? ? ?pthread_rwlock_tryrdlock();
? ? ? ?pthread_rwlock_trywrlock();
demo如下

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

#define Read_Num 2

pthread_rwlock_t lock;

class Data
{
    public:
        Data(int i, float f): I(i), F(f){}
        int GetI()
        {
            return I;
        }

        float GetF()
        {
            return F;
        }

    private:
        int I;
        float F;
};

Data *pData = NULL;

void *read(void *arg)
{
    int *id = (int*)arg;
    while(true)
    {
        pthread_rwlock_rdlock(&lock);
        printf(" reader %d is reading data\n", *id);
        if (pData == NULL)
        {
            printf("data is NULL\n");
        }
        else
        {
            printf("data: I = %d, F = %f\n", pData->GetI(), pData->GetF());
        }
        pthread_rwlock_unlock(&lock);
    }
    pthread_exit(0);
}

void *write(void *arg)
{
    while(true)
    {
        pthread_rwlock_wrlock(&lock);  //寫鎖加鎖后,解鎖前,所有試圖對該鎖加鎖的線程都會被堵塞
        printf("writer is wiriting data:\n");
        if (pData == NULL)
        {
            pData = new Data(2, 2.2);
            printf("writer is writing data: %d, %f\n", pData->GetI(), pData->GetF());
        }
        else
        {
            delete pData;
            pData = NULL;
            printf("wirter free the data\n");
        }
        pthread_rwlock_unlock(&lock);

    }
    pthread_exit(0);
}

int main()
{
    pthread_t reader[Read_Num];
    pthread_t writer;
    for (int i = 0; i < Read_Num; i++)
    {
        pthread_create(&reader[i], NULL, read, (void*)&i);
    }
    pthread_create(&writer, NULL, write, NULL);
    while(1)
    {
        sleep(1);
    }
    return 0;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容