- N +

c語言程序設計編程題答案 c語言程序設計馮林課后答案

本篇文章給大家談談c語言程序設計編程題答案,以及c語言程序設計馮林課后答案對應的知識點,文章可能有點長,但是希望大家可以閱讀完,增長自己的知識,最重要的是希望對各位有所幫助,可以解決了您的問題,不要忘了收藏本站喔。

單片機為什么還在用C語言編程

單片機為什么還在用C語言編程?答案是:C語言是最適合單片機編程的高級語言。

這個問題的意思應該是:現在有很多很好用的高級語言,如java,python,VC等等,為什么這些語言不能用來編寫單片機程序呢?那么這個問題的答案就是:不能不能,而是不合適。

一、單片機編程的特點

對單片機編程來說,首先要考慮的是單片機的程序空間和數據空間都是有限的,所以要讓程序盡量短小精悍,以節省程序占用的存儲空間。

第二、單片機編程的一個主要對象是對單片機的端口和內部寄存器的操作和配置,這個需要比較精確的時序控制。

第三、單片機算法運算中,盡量使用加法、減法、移位運算,因為乘法和除法運算會非常費時間,尤其是除法,會耗費很多時間,這對于速度本身就有限制的單片機來說,是一個很大的負擔。

二、高級語言編寫單片機程序的缺陷

高級語言可以實現更為優化的算法,更為方便的執行方案,但是,高級語言對程序存儲空間的占用要比匯編和C語言多很多。這是最致命的一點,單片機有限的存儲空間需要靠精打細算來設計程序,根本經不起高級語言臃腫的代碼體積。

高級語言無法實現精確的時序控制。

三、C語言是一個折中選擇

其實用C語言開發單片機也是一個折中方案,因為最適合單片機開發的編程語言實在太過晦澀難懂,并且每一種單片機的匯編指令有很大區別,所以想把一個程序從這種單片機移植到另一種單片機簡直是癡心妄想,還不如重新寫一遍程序。

而C語言代碼執行效率高,也比較精簡,更便于移植......所以在現今的單片機編程語言中,C語言才會占據絕對主導地位

c語言可以泛型編程嗎如何實現

泛型編程是一個非常常見的編程方式。主要目的是實現靜態聯編,使得函數可以接受不同類型的參數,并且在編譯的時候確定正確的類型。

很多語言都對泛型編程提供了支持,比如在C++中可以使用函數模版和類模版來實現泛型編程;在Java、Objective-C或者C#等單根繼承的語言中,也可以使用類似java.lang.Object、NSObject等類型進行編程。在具有類型推斷功能(比如Swift)的編程語言中,更是可以直接使用泛型編程。

不過C語言是高級語言編程的基礎語言,那如何在C語言中實現泛型編程,確實是一個問題。首先C語言不支持函數重載,不支持模版類型,所以實現起來確實比較困難。

0x01泛型指針(void*)簡介

void*是C語言中的一種類型,大家都知道在大多數編程語言中,void類型都代表所謂的空類型,比如一個函數的返回一個空類型void,這是很常見的用法。

注意:返回值為void并不是沒有返回值,而是代表返回空類型,這就是你仍然可以在這些函數中使用return語句的原因。只有一些語言的構造函數和析構函數才沒有返回值,在這些函數中,不可以使用return語句,他們是有顯著的不同的,Objective-C是一門獨特的語言,它的類的初始化方法是一個普通方法,返回值是instancetype(當前類的指針類型)類型。

而void*可能就稍微鮮為人知一些,void*在C語言中可以表示人任意類型的指針。畢竟對于內存單元的地址而言,所謂它存儲的數據類型,只是每次取出的字節數不同而已,這些內存單元的地址本身并沒有什么不同。下面會更好的體現這句話的含義。

void*的大小和普通類型的指針一樣,總是一個字,具體的大小因機器的字長而異,例如對于32位機器是4個字節,對于64位機器是8個字節。

我沒有考證過16位的8086機器上指針的大小,因為8086的地址是20位的,這個有興趣的話可以回去試一試。

個人認為指針的大小仍然是16位,因為20位是物理地址,而物理地址是由段地址和偏移地址計算出的,在匯編之后C語言的指針可能只是變成相對于段地址的偏移地址,畢竟對于8086而言數據一般總是在DS段中,而代碼一般總是在CS段中。(斜體字代表尚未考證的說法)

在C語言中,其他普通類型的指針可以自動轉換為void*類型,而void*類型一般只能強制轉換為其他普通類型的指針,否則會出現警告或錯誤。

有一個特別大的坑就是關于所謂void*指向數組的情況,這里直接上代碼解釋了。

voidSwap(void*array,intx,inty,intmallocsize){

void*temp=malloc(mallocsize);

memcpy(temp,array+mallocsize*x,mallocsize);

memcpy(array+mallocsize*x,array+mallocsize*y,mallocsize);

memcpy(array+mallocsize*y,temp,mallocsize);

free(temp);

}

這是一個比較經典的交換函數,借助的是臨時變量temp,但是這個函數是泛型的,對于memcpy的使用稍后會介紹。需要注意的是,array指向一個數組的話,不能直接用&array[x]或者array+x獲得指向第x個元素的地址,因為void*類型默認的指針偏移量是1,和char*是相同的,這對于絕大多數類型來說都會出現錯誤。所以在使用的時候必須知道該泛型類型原來所占的長度,我們需要一個名為mallocsize的int類型形參來告訴我們這個值,在計算指針偏移的時候乘以它。這就相當于C++編程中的模版類型定義或者Java中的泛型參數了。

同時要注意對于void*類型的指針,任何時候都不可以對其進行解引用運算(或者在課堂上老師習慣叫做“取內容”?),原因是顯然的:void類型的變量并不合法。所以如果想進行解引用運算,必須先將其轉換為普通類型的指針。用于數組的時候還需要注意解引用運算符的優先級是高于加法的,所以要加括號,比如這樣:

inta=*(array+mallocsize*x);

這句代碼完美的體現了C語言編程的丑陋。

0x02sizeof運算符簡介

sizeof運算符相信學過C語言的朋友都不會陌生,但是sizeof是一個運算符估計就沒多少人知道了,返回的類型是size_t類型。sizeof運算符返回某個類型所占用的空間大小。這里只說一點就是,如果對一個指針類型或者數組名(實際上數組名就是指針常量嘛)求sizeof的話,返回結果總是一個字(見上面所述)。而對一個結構體類型求sizeof,并不是簡單的將結構體中各個類型的sizeof求和得到,而是要涉及到內存對齊問題,這里不多做介紹了,詳細了解可以訪問:如何理解struct的內存對齊?-知乎。

0x03memcpy函數簡介

memcpy是一個經常和void*配合使用的函數,其函數原型為:

void*memcpy(void*,constvoid*,size_t);

所屬的頭文件為string.h,大家也看出來了,這個函數本身就是以void*類型作為參數和返回值,其實也很好理解,就是一個賦值的過程,進行內存拷貝。把第二形參指向的內存拷貝到第一形參,拷貝的字節數由第三形參指定。當然了第三個參數一般通過sizeof運算符求出,這里就不舉例子了。返回值我沒有研究過,也沒用過,如果有知道的朋友可以評論區交流。

0x04C語言中實現泛型編程

說了這么多,還沒提到泛型編程。不過前面也提的差不多了,總體思想就是使用void*類型當作泛型指針,然后再輔以類似于mallocsize的參數指定所占內存大小,所占內存大小通過sizeof運算符求得,如果需要進行賦值的話,利用memcpy函數完成,下面就直接給一個例子出來,是泛型的快速排序算法,說明這些問題:

#ifndefCompare_h

#defineCompare_h

#include<stdio.h>

#include"JCB.h"

intIsGreater(void*x,void*y);

intIsGreaterOrEqual(void*x,void*y);

intIsSmaller(void*x,void*y);

intIsSmallerOrEqual(void*x,void*y);

#endif/*Compare_h*/

//

//Compare.c

//Job-Dispatcher

//

//Createdby路偉饒on2017/11/16.

//Copyright?2017年路偉饒.Allrightsreserved.

//

#include"Compare.h"

intIsGreater(void*x,void*y){

return*(int*)x>*(int*)y;

}

intIsGreaterOrEqual(void*x,void*y){

return*(int*)x>=*(int*)y;

}

intIsSmaller(void*x,void*y){

return*(int*)x<*(int*)y;

}

intIsSmallerOrEqual(void*x,void*y){

return*(int*)x<=*(int*)y;

}

//

//QuickSort.h

//Job-Dispatcher

//

//Createdby路偉饒on2017/11/16.

//Copyright?2017年路偉饒.Allrightsreserved.

//

#ifndefQuickSort_h

#defineQuickSort_h

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include"Compare.h"

voidQuickSort(void*array,intleft,intright,intmallocsize);

#endif/*QuickSort_h*/

//

//QuickSort.c

//Job-Dispatcher

//

//Createdby路偉饒on2017/11/16.

//Copyright?2017年路偉饒.Allrightsreserved.

//

#include"QuickSort.h"

voidSwap(void*array,intx,inty,intmallocsize){

void*temp=malloc(mallocsize);

memcpy(temp,array+mallocsize*x,mallocsize);

memcpy(array+mallocsize*x,array+mallocsize*y,mallocsize);

memcpy(array+mallocsize*y,temp,mallocsize);

free(temp);

}

intQuickSortSelectCenter(intl,intr){

return(l+r)/2;

}

intQuickSortPartition(void*array,intl,intr,intmallocsize){

intleft=l;

intright=r;

void*temp=malloc(mallocsize);

memcpy(temp,array+mallocsize*right,mallocsize);

while(left<right){

while(IsSmallerOrEqual(array+mallocsize*left,temp)&&left<right){

left++;

}

if(left<right){

memcpy(array+mallocsize*right,array+mallocsize*left,mallocsize);

right--;

}

while(IsGreaterOrEqual(array+mallocsize*right,temp)&&left<right){

right--;

}

if(left<right){

memcpy(array+mallocsize*left,array+mallocsize*right,mallocsize);

left++;

}

}

memcpy(array+mallocsize*left,temp,mallocsize);

returnleft;

}

voidQuickSort(void*array,intleft,intright,intmallocsize){

if(left>=right){

return;

}

intcenter=QuickSortSelectCenter(left,right);

Swap(array,center,right,mallocsize);

center=QuickSortPartition(array,left,right,mallocsize);

QuickSort(array,left,center-1,mallocsize);

QuickSort(array,center+1,right,mallocsize);

}

這里留了一個懸念,明明可以直接比較的,為什么還要這么麻煩使用好多函數完成,也就是關于Compare.h的用處的問題,下面會揭曉答案。

0x05泛型的協議問題

剛剛那個問題就涉及到了一個泛型的協議問題,我這里是借用了Objective-C中的一個概念去闡述。就像剛剛那個問題,既然我的快速排序是泛型的,那么怎么保證實際傳入泛型參數一定是可比較的呢?舉個例子,顯然int、float、double是可以進行比較的,char使用ASCII編碼方案的比較我們也理解,String類型甚至也是可以比較的。但是如果在其他語言中,對象之間如何進行比較呢?這就是個問題了。在C++中我們可以進行運算符重載,這樣就仍舊可以使用比較運算符,借助運算符重載函數來完成。不過對于Java、Objective-C這種語言該怎么辦?而且如果傳入的泛型參數沒有實現對應的運算符重載函數怎么辦?這時候就要引入一個協議的概念,簡單來說就是,如果某個類型想要作為排序泛型函數的泛型參數,那你必須實現可比較的協議。這個協議在Swift語言中就稱為Comparable,這樣的話在編譯的時候,編譯器才知道這個泛型參數是可以進行比較的,這樣才能完成我們的操作,否則的話就會出現錯誤。這就是泛型中的協議問題。

0x06總結

C語言的泛型編程以void*作為泛型類型,本質上是泛型指針。

C語言的泛型編程需要知道一個泛型類型變量所占的內存大小,這個可以通過sizeof求得并傳入泛型函數。

C語言的泛型編程中要注意數組的偏移問題,void*的默認偏移是1,對于絕大多數類型來說都是錯誤的,需要自行編程轉換。

C語言的泛型編程中使用memcpy函數進行泛型變量的拷貝和賦值。

C語言的泛型編程中也需要注意協議問題,但是C中就只能自行編寫函數進行定義了,在其他語言中可以使用現成的接口或者協議。

不會英語能學會編程嗎

無論是在生活中還是網絡上經常能夠看到有人問“我英語不好,能不能學編程”,大聲宣稱“中國應該有自己的漢語編程語言”的人比比皆是,愛國者有之、借機攻擊我國科技者有之、不懂裝懂者有之等等等等。那么英語和我們常見的編程到底有什么關系,不懂英語到底能不能學會甚至學好編程呢。

一顆思考的心

首先,我們來看看英語和編程到底是什么關系。我認為編程最主要的有兩個方面的東西,一個就是代碼,這是毋庸置疑的;另一個就是文檔了,也就是參考資料。

首先來看看代碼。下面的一個是C語言代碼,一個是Python代碼。

我們再來看看文檔。下面是C/C++參考文檔,以及一個python的參考文檔。

如果你不懂英文,確實很容易就被這些東西嚇壞。剛剛激起的學習熱情很可能被無情的澆滅。可是實際上,如果想寫一個程序,用到的英文其實是很少的,其他的你可以全部采用漢語拼音。我們再來看看那兩個代碼圖片中真正必須用英文的部分。我用紅色框線標出來。

你很可能不信,怎么會那么少,那其他的那些呢。那個C語言的因為程序小,所以稍顯多些。其他的除了幾個庫函數外,你都可以用漢語拼音來完成。

實際上C語言和C++語言本身需要的英文單詞,學名關鍵詞或者保留字,也就幾十個。我們來看看C、C++以及Python的關鍵詞。

可以看到C/C++的關鍵詞一共62個,是不是大部分都是你認識的,而且一點也不難記,實際上也用不著刻意的去背記,用著用著就知道了。

python的關鍵詞一共33個。

也就是說你只需要記住這幾十個單詞就可以寫程序。不要不信,事實上就是如此。

這就是編程本身和英語的關系。說白了就是幾十個英語單詞的關系。初中一年級的詞匯量恐怕要比這多多了。

那么編程中和英語關系最大的地方是哪里,就是剛才說的文檔。因為也有很多文檔是英文的,這個如果英語不好確實看不了。

那么,不懂英文看不懂英文文檔能不能學好編程?

答案是:能。

為什么?

因為編程的中文資料也很多很豐富,足夠你學習用了。

百度一下,可以看到有那么的書夠你選夠你看。

因此,你僅僅需要的是買一本書,然后耐心的跟著書本去學習。

那么,既然英語不好不影響學習編程,學好英語重不重要?

答案:重要

最新的文檔資料基本上都是英文的,因此如果你想了解最前沿的資訊,會英文是必須的。同時,看的懂英文文檔能夠幫助學習。比如我經常用的python、qt、以及很多人都會用到的msdn大部分都是英文資料。因此在查找資料時英文幫助很大。在搜索解決難題時,也有更多的選擇,比如stackoverflow就幫我解決了很多問題。中文搜索不到的,英文就能及時幫你。

而且,計算機英語比較簡單,一個詞典夠了,多看看就能夠流暢的閱覽了。重要的在于堅持二字。

那么計算機編程真正需要的是什么?

答案:邏輯思維能力、抽象理解能力以及數學能力。不過高難數學的應用在非常專業的領域,所以不用擔心。

充滿自信的你怎么能夠不嘗試一下呢。

最后我們來討論一下漢語編程的必要性。漢語編程有沒有?答案是有的。如果你覺得那幾十個單詞確實很難的話,你可以投奔漢語編程。但是漢語語義豐富、重碼率很高,除了漢字你認識外,其他的并不比英文編程有更多的優勢。最起碼的目前的漢語編程沒有英文編程簡潔。再再退一步講,如果你想找份工作,那么招聘廣告的要求就是最基本的要求。到時候你再考慮有沒有必要學習。而且不管是什么語言的編程,最基本的編程思想是不變的,編程思想并不會因為語言不同而變得更簡單或更難。

我也學了C語言,為什么不能編出程序

哥們看你要想編什么程序了。

如果你現在能在控制臺打印出hello,world,那么你就編出了一個程序。要知道很多牛逼的程序都是這種控制臺的,所以從你學C語言開始,就不存在編不出程序這種問題。

屁哥認為你想說的是沒能編出可視化界面的程序吧,如QQ,網易云音樂等等。兄弟,你現在之所以認為自己編不出程序,還是因為你學的知識太少了!一個合格的程序員僅僅學一門語言是不夠的,一般比較出名的程序員都能熟練使用3門以上的語言,至少精通一門語言!

屁哥也是程序員,主要做iOS系統的軟件。不過現在屁哥大約會5種語言,當然不是很熟練,不過要是有要求,屁哥可以用這些語言隨時上項目。

編程語言的側重點不同,所服務的程序也不同。如你學的C,主要是用來做底層的應用,偏系統級的開發,注重效率,真正用C語言寫程序的都是大牛。其他的,像java可以做服務器后端,安卓手機app,跨平臺的桌面程序等等,方便快捷;c++可以做偏重效率的程序,如QQ就用了大量的c++,還有大型的3D游戲等;c#主要服務windows系統,可以做網站,桌面程序(win平臺),手機(winphone,已死),游戲(基于u3d引擎)等等;Objective-C(ios,mac等蘋果程序,屁哥的本命語言);至于其他的php,Python,ruby,js,go,swift各有各的功用,在這里屁哥就不一一列舉了~

編程是一門枯燥的工作,同時又是一門富有藝術創造的工作,想要成為好的程序員唯有不斷的學習,沒有止境!

純手打,屁哥呈現。

C語言是用什么編出的

首先答案是c語言是用c語言編寫。

語言自舉性

一個語言能否自己編寫自己實現自己編譯,這叫自編譯,自舉性。目前能實現自舉性的語言沒有幾個,而自舉性也就成了一個語言能否真實強大的標志。

一般來說圖靈完備的語言,編譯型語言,虛擬機語言可以實現自舉。而解釋型語言基本上很難。

現代很多語言都沒實現自舉,Java(jvm),Javascript,python,ruby,lua,php,perl……一堆。這些語言編譯器、解釋器都是c語言。

一個語言能自舉是他們社區和開發一直夢寐以求的事情,也是他們情懷和追求所在。有一個語言為了實現自舉成功,花了近20年,前年圣誕節才正式推出了第一個正式版本。它就是perl6,perl的下一代語言。perl6支持過程、OO、函數式三種程模式,支持虛擬機的語言(自己的虛擬機和jvm)。為了做好perl6,社區搞了一個功能啟示錄,把要實現的功能好點子都錄進去。后來一個日本人參考這個啟示錄自己實現了一個語言,這就有了ruby語言,但是ruby沒有自舉。

c語言的自舉過程和交叉編譯

我在以前的回答中,曾說過c語言的來歷:

上世紀70年代,為了實現unix,教主Tomphson和Ritchie開發了B語言,但是b語言性能不行,編寫也較繁瑣,所以又在B語言的基礎上開發出了現在的C語言。

第一個C語言編譯器的原型是用B語言或者混合B和匯編語言編寫的。采用部分實現功能,交叉編譯方式實現。

先用B和匯編語言編寫一個C語言的部分必須功能的編譯器,再通過這個編譯器,完成完整的C語言編譯器。詳細過程如下:

1、先編寫一個只有C語言最基本功能編譯器C0語言,用匯編語言編寫出C0的編譯器。

2、接著用C0實現比C0復雜,功能不完整的C語言子集C1語言,用C0編譯出C1語言的編譯器。

3、在C1-〉c2……如此循環直到Cn,Cn功能已經強大到可以實現C。

4、用Cn編譯實現了第一個c語言編輯器,即C實現了自舉。

END,本文到此結束,如果可以幫助到大家,還望關注本站哦!

返回列表
上一篇:
下一篇: