1. 程式人生 > >實驗室招新系列(一)

實驗室招新系列(一)

這次放題目出來的時間不太好,臨近期末,而且距離第一次出題中間隔的時間也有點長。原本我是想要早點將題目出完的,在招新計劃上出了點小分歧,導致最後放題目時間完了點。
但是不管怎樣,題目質量還是有的(至少我這麼認為咯),其中很多是華為的面試題,在這裡作為練習用的題目。

1.請寫出下列程式碼的輸出內容

#include  <stdio.h> 
int main(void) 
{ 
int a,b,c,d; 
a=10; 
b=a++; 
c=++a; 
d=10*a++; 
printf("b,c,d:%d%d%d",b,c,d); 
return 0; 
}
10 12 120

點評:這個是可以用來直接面試的,題目難度不大,主要考察對++的理解

2.全域性變數可不可以定義在可被多個.C檔案包含的標頭檔案中?為什麼?
這個題在招新群裡有很多人提出疑問,提出對題目不理解,對此表示略無語;
同時也有很多人在交上來的答案中直接寫“可以”或者“不可以”,把後面的為什麼三個字直接扔掉不看;
對於一直強調自己沒有學過的人,我只想說,你都學了,那我還出這題出來,是我吃多了?!沒學過自己去查去啊。
對於這個題,我原本的意思是讓自己去敲程式碼,然後測試能不能被包含。但是事實證明,我對剛入校學習不到半年的學弟學妹期望太高,並不是所有人都會有這樣的思維,這個確實是我的過。

題目的關鍵點也在於“為什麼”,而不是可以與不可以。
題解:可以,在不同的C檔案中以static形式來宣告同名全域性變數。   可以在不同的C檔案中宣告同名的全域性變數,前提是其中只能有一個C檔案中對此變數賦初值,此時連線不會出錯
程式的區域性變數存在於(堆疊)中,全域性變數存在於(靜態區 )中,動態申請資料存在於( 堆)中。

在這裡就不給出參考程式了。根據上面提到的思路自己再寫一寫程式碼測試一下,這裡僅僅提供思路。

遇到程式方面的問題,解決方法:搜尋引擎 && 寫程式測試

3.對static的理解
(1)static全域性變數與普通的全域性變數有什麼區別?
答:全域性變數的說明之前再加以static 就構成了靜態的全域性變數。全域性變數本身就是靜態儲存方式,靜態全域性變數當然也是靜態儲存方式。這兩者在儲存方式上並無不同。這兩者的區別雖在於非靜態全域性變數的作用域是整個源程式,當一個源程式由多個原始檔組成時,非靜態的全域性變數在各個原始檔中都是有效的。而靜態全域性變數則限制了其作用域,即只在定義該變數的原始檔內有效,在同一源程式的其它原始檔中不能使用它。由於靜態全域性變數的作用域侷限於一個原始檔內,只能為該原始檔內的函式公用,因此可以避免在其它原始檔中引起錯誤。從以上分析可以看出,把區域性變數改變為靜態變數後是改變了它的儲存方式即改變了它的生存期。把全域性變數改變為靜態變數後是改變了它的作用域,限制了它的使用範圍。
(2)static區域性變數和普通區域性變數有什麼區別?
答:static區域性變數只被初始化一次,下一次依據上一次結果值;
(3)static函式與普通函式作用域有什麼不同點?
答:僅在本檔案。只在當前原始檔中使用的函式應該說明為內部函式(static),內部函式應該在當前原始檔中說明和定義。對於可在當前原始檔以外使用的函式,應該在一個頭檔案中說明,要使用這些函式的原始檔要包含這個標頭檔案。
(4)static函式與普通函式有什麼區別?
答:static函式在記憶體中只有一份,普通函式在每個被呼叫中維持一份拷貝程式的區域性變數存在於(堆疊)中,全域性變數存在於(靜態區)中,動態申請資料存在於(堆)中。

點評:本題側重底層原理。其實任何一門語言,都是會有static的用法的,都大同小異,所以在這裡著重給出一個關於static用法的題,是希望能夠對static以及底層原理有一個更深層次的理解。

4.找錯:(有點難度的~)
分別找出三個函式中的錯誤~

void test1()   
{ 
    char string[10]; 
char* str1="0123456789";
strcpy(string, str1);   
} 
這裡string陣列越界,因為字串長度為10,還有一個結束符‘\0’。所以總共有11個字元長度。string陣列大小為10,這裡越界了。   PS:使用strcpy函式的時候一定要注意前面目的陣列的大小一定要大於後面字串的大小,否則便是訪問越界
void test2() 
{
         char string[10], str1[10];   
for(i=0; i<10;i++)   
{   
str1[i] ='a';   
} 
         strcpy(string, str1);   
}
這裡有一個一眼就能看出的問題,那就是變數i沒有定義,這在程式碼編譯階段編譯器可以幫你發現,很容易搞定。然而很多問題是自己造成的漏洞,編譯器是幫不上什麼忙的。這裡最大的問題還是str1沒有結束符,因為strcpy的第二個引數應該是一個字串常量。該函式就是利用判斷第二個引數的結束符來得到是否拷貝完畢。所以在for迴圈後面應加上str1p[9] = '\0'; 
PS:字元陣列和字串的最明顯的區別就是字串會被預設的加上結束符‘\0’
void test3(char* str1)   
{ 
char string[10];   
if(strlen(str1)<=10)   
{
strcpy(string, str1);  
     }   
} 
這裡的問題仍是越界問題。strlen函式得到字串除結束符外的長度。如果這裡是<=10話,就很明顯越界了。 

小結:上面的三個找錯的函式,主要是考查對字串和字元陣列的概念的掌握以及對strcpy函式和strlen函式的理解。本題在大一這個時候,如果能全部獨立地找出錯誤,說明功底非常好!

5.指出下面程式碼的輸出,並解釋為什麼。
(對地址掌握的深入挖潛)

int main() 
{ 
int a[5]={1,2,3,4,5}; 
int *ptr=(int *)(&a+1); 
printf("%d,%d",*(a+1),*(ptr-1)); 
} 

詳解:
(a+1)就是a[1],(ptr-1)就是a[4],執行結果是2,5

&a+1不是首地址+1,系統會認為加一個a陣列的偏移,是偏移了一個數組的大小(本例是5個int)
int ptr=(int )(&a+1);
則ptr實際是&(a[5]),也就是a+5 原因如下:
&a是陣列指標,其型別為 int (*)[5];
而指標加1要根據指標型別加上一定的值, 不同型別的指標+1之後增加的大小不同
a是長度為5的int陣列指標,所以要加 5*sizeof(int)
所以ptr實際是a[5]
但是prt與(&a+1)型別是不一樣的(這點很重要) 所以prt-1只會減去sizeof(int*)
a,&a的地址是一樣的,但意思不一樣,a是陣列首地址,也就是a[0]的地址,&a是物件(陣列)首地址,a+1是陣列下一元素的地址,即a[1],&a+1是下一個物件的地址,即a[5].

6.func(1) = ?

int func(int a)
{
    int b;
    Switch(a)
{
    case 1: b=30;
    case 2: b=20;
    case 3: b=10;
    case 4: b=0;
}
return b;
}

7.搞笑題(輕鬆一下):
C語言中有一種非常神奇的符號,叫做趨向於,長這個樣子“–>”。

#include<stdio.h>
int main(void)
{
    int i=10;
    while (i-->1)   //i趨向於1
    {
        printf ("%d",i);
    }
    return 0;
}

這樣可以輸出987654321.
請寫出你對–>的理解^_^
題解:第六題第七題都是拿來高校的。沒有趨向於這個符號,捏造的。六七題看不出來的,可以自掛東南枝。2333333

8.這是一道很嚴肅的題:
請想出一種方法,讓程式輸出1/3+1/6=0.5
聰明的你,一定可以找到解決的辦法~~
那麼接下來問題又來了,你知道在計算機中1/3和1/6是怎麼儲存的嗎?
1/3+1/6在計算機中又是怎麼算出等於0.5的呢?
題解:這個題貼近底層原理,涉及到進位制轉換;在這裡作為了解,主要是希望能夠通過搜尋引擎自己去查詢相關資料。

具體說來:
1/3和1/6都是無限迴圈小數,但是在CPU中,位數都是有限的;所以實際上1/3和1/6在記憶體裡不是長度無限的。
在64位機中測試:
1/3在記憶體中是0x3eaaaaab
1/6在記憶體中是0x3E2AAAAB
換算成小數的時候分別是0.3333333432…和0.1666666716…即在記憶體中就是不精確的
因為計算機內部都是二進位制的,這兩個數值用二進位制表示就是:
1/3 -> 0.010101010101010101010110
1/6 -> 0.001010101010101010101011
現在計算機做浮點都是硬浮點,那麼具體的計算就是0.100000………01
因為這個時候精度就已經多出一位,此時CPU就要做一個取捨,,最後的位數是01的預設舍掉,所以最後的結果剛好就是0.1000……0,轉成十進位制就是0.5

參考程式碼:

#include <stdio.h>
#include <string.h>
int main(void)
{
    /**
     *memcpy是c和c++使用的記憶體拷貝函式,
     *memcpy函式的功能是從源src所指的記憶體地址的起始位置開始拷貝n個位元組到目標dest所指的記憶體地址的起始位置中。
     *關於這個函式更詳細的內容,自行百度
     */
     /**
      *這裡的x,y都必須在一個數字上用到小數位,才能準確表示浮點型
      */
    floatx=1.0/3, y=1.0/6;
    unsigned inta, b;
    memcpy(&a,&x, sizeof(a));
    memcpy(&b,&y, sizeof(b));
    printf("%.100f\n %.100f\n %.100f\n", x, y, x+y);
    printf("%x%x\n", a, b);
    return 0;
}

相關推薦

實驗室系列

這次放題目出來的時間不太好,臨近期末,而且距離第一次出題中間隔的時間也有點長。原本我是想要早點將題目出完的,在招新計劃上出了點小分歧,導致最後放題目時間完了點。 但是不管怎樣,題目質量還是有的(至少我這麼認為咯),其中很多是華為的面試題,在這裡作為練習用的題目

JDK併發包溫故而知系列—— 競態條件與記憶體可見性

併發問題 併發問題是指多執行緒讀寫共享記憶體的時候,產生結果不可預期的情況,併發問題的產生的原因可以歸結為兩種,一是因為競態條件,二是因為記憶體可見性、 競態條件 什麼是競態條件 競態條件,官方解釋是如果程式執行順序的改變會影響最終結果,這就是一個競態條件。 這句話有點抽象,描述的有點抽象,我個人對競態條件

【ABAP自學系列

發的 img api .cn ima code pat 查看 屏幕 一、查看補丁包級別 然後看Patch Level即可。 常用T-code: SE38(寫程序) SE80(屏幕開發) Smartform(開發smartform打印) SE37(可以查看function

Linux基礎學習系列

內核版本 比較 其中 問題 測試版 工具 含義 語言 復制   Linux是一種類似於UNIX的操作系統,由Linus Torvalds於1991年在minix操作系統的基礎創建。Linux憑借其優良特性已經成為目前發展潛力最大的操作系統。   Linux的版本有內核版本和

spring boot學習系列

web服務器 應用程序 spring 控制器 做什麽 spring boot開發第一個應用程序1、spring boot是什麽?2、spring boot容易上手嗎?寫這篇文章技術文章,主要是記錄日常的學習以及理解。我們重新認識一下spring假設你受命使用spring開發一個簡單的hel

asp.net core入門教程系列

home padding 方式 title sys 活性 elf tro ash Asp.Net Core簡介 ASP.NET Core 是一個全新的開源、跨平臺框架,可以用它來構建基於網絡連接的現代雲應用程序,比如:Web 應用,IoT(Internet Of Thin

【原創】源碼角度分析Android的消息機制系列——Android消息機制概述

run 權限 開發 等待 通過 讀取 概述 走了 color ι 版權聲明:本文為博主原創文章,未經博主允許不得轉載。 1.為什麽需要Android的消息機制 因為Android系統不允許在子線程中去訪問UI,即Android系統不允許在子線程中更新UI。 為什麽不允許

vue系列子組件和父組件

top parent sage too msg pro 工具 light java 父組件傳遞數據到子組件props 父組件 <template> <div class="main"> <div class="top">

Hadoop源碼系列FairScheduler申請和分配container的過程

opened running fetch utils ostream png on() threshold metadata 1、如何申請資源 1.1 如何啟動AM並申請資源 1.1.1 如何啟動AM val yarnClient = YarnClient.createY

源碼分析系列x264_main_dataflow

images 9.png 所有 malloc 控制 相關 .com 圖1 memory http://www.cnblogs.com/xkfz007/articles/2616153.html 幀內幀間編碼部分關鍵函數 1.1 x264_encoder_open (x

ORM框架疏理——廖雪峰實戰系列

命令 delete ica 隱式 orm mod prim 數據結構 lam ORM(Object Relational Mapping,對象關系映射),是一種程序設計技術,用於實現面向對象編程語言裏不同類型系統的數據之間的轉換。從效果上來說,它其實創建了一個可在編程語言裏

優秀開源軟件學習系列——從零學習Spring4以及學習方法分享

文檔 軟件 準備 相關性 培訓 獎勵 在哪裏 方式 列表 一、目的1.掌握Spring4怎樣使用,以便將這個框架作為自己的一項技能。2.掌握Spring官網是怎樣介紹其產品的,在心中對Spring有最官方的、最直觀的了解。在Spring的相關領域,能夠知道怎麽下載Sprin

PHP系列PHP流程控制結構

php流程控制while(){}do{}while(); for( 表達式1; 表達式2;表達式3 ){ 語句或語句序列;} if(){}if(){}elseif{}<?php$i=0;while(true){ if($i>=100) break; echo "@@

RabbitMQ學習系列: 介紹

ref 原理 二維碼 host 屬性 訂閱 什麽 設計 發的 1. 介紹   RabbitMQ是一個由erlang開發的基於AMQP(Advanced Message Queue )協議的開源實現。用於在分布式系統中存儲轉發消息,在易用性、擴展性、高可用性等方面都非

Python開發MapReduce系列WordCount Demo

logs 3-9 line counter ota python開發 home num brush  原創,轉發請註明出處。   MapReduce是hadoop這只大象的核心,Hadoop 中,數據處理核心就是 MapReduce 程序設計模型。一個Map/Reduc

Javascript系列語法、關鍵保留字、變量

javascript ECMA是European Computer Manufacturers Association的縮寫,即歐洲計算機制造商協會。歐洲計算機制造商協會是制定信息傳輸與通訊的國際化標準組織。ECMAScript是ECMA制定的標準化腳本語言。目前JavaScript使用的ECMAS

Java集合幹貨系列-ArrayList源碼解析

div imp ins bject 增加 toa tof capacity == 前言 今天來介紹下ArrayList,在集合框架整體框架一章中,我們介紹了List接口,ArrayList繼承了AbstractList,實現了List。ArrayList在工作中經常用到,所

Openlayers系列關於地圖投影的理解

數據庫 nbsp 簡單的 是個 ace 投影 存儲 mongodb uid 近期開發以MongoDB為基礎的分布式地理數據管理平臺系統,被要求做一個簡單的demo給客戶進行演示。於是筆者便打算向數據庫中存儲一部分瓦片數據,寫一個簡單的存取服務器,使用Openlayers客戶

Python操作rabbitmq系列

targe 紅色 入門 web 之間 cap ssa 隊列 技術 從本文開始,接下來的內容,我們將討論rabbitmq的相關功能。我的這些文章,最終是要實現一個項目(具體是什麽暫不透露)。前面每一篇,都是在為這個系統做準備。rabbitmq,是我們這個項目的關鍵部分之一。所

Python爬蟲系列:從零開始,安裝環境

tar 公司 pip nal 網頁 解析 目標 http caption 在上一個系列,我們學會使用rabbitmq。本來接著是把公司的celery分享出來,但是定睛一看,celery4.0已經不再支持Windows。公司也逐步放棄了服役多年的celery項目。恰好,公司找