當前位置:首頁 » 編程語言 » c語言高手編程案例
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

c語言高手編程案例

發布時間: 2022-05-14 04:19:55

c語言編程,高手進

#include <stdio.h>

int main()
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);

if(x > y && x > z)
{
printf("最大數:%d\n", x);
if(y > z)
printf("最小數:%d", z);
else
printf("最小數:%d", y);
}
else if(y > x && y > z)
{
printf("最大數:%d\n", y);
if(x > z)
printf("最小數:%d", z);
else
printf("最小數:%d", x);
}
else
{
printf("最大數:%d\n", z);
if(y > x)
printf("最小數:%d", x);
else
printf("最小數:%d", y);
}
return 0;
}

============

#include <stdio.h>

int main()
{
int sum = 0, i;
long prod = 1;

for(i = 1; i < 101; ++i)
{
sum = sum + i;
}

printf("sum = %d\n", sum); /*和*/
return 0;
}

② 十萬火急。一道簡單的C語言的編程,高手必看!

#include<stdio.h>
#include<ctype.h>
#include<string.h>
int main()
{
char input[1024];//用來存放輸入的字元串,定義為1024大小,不夠可以自己增加
int len;//用來保存讀入字元串的長度
int a[1024];//用來保存計算後的整數
int count=0;//保存整數個數
int i=0;//遍歷input用
int sum=0;//每次計算一個整數時用來累加
char c;//每次從input中取來一個字元放到c中
int flag=2;//剛開始設置為2,1代表一個整數已被保存設置為,0代表一個整數還需要保存
scanf("%s",input);//從鍵盤讀入這個字元串
len=strlen(input);
while(i<len)
{
c=input[i];
if(isdigit(c))//如果c是一個數字的話要處理

{
flag=0;//flag置為0,表示如果某次遇到了一個字元那麼sum里的整數需要保存
sum=sum*10+(c-48);/*將c有字元轉換為數字,0的ascii碼為48,故需要減去48,
把記錄在sum里的數*10,在加上這次讀的數
例如28後面如果在有個三那結果就是28*10+3;*/
}
else
{
if(flag==0)/*讀字元串的時候遇到一個字母,那判斷flag是否為0,如果是說明sum里有需要保存的數,
123ab,在這個例子中如果計算完123,那麼遇到a時就保存這個數*/
{
a[count]=sum;//放到數組里
count++;//計數加1
sum=0;//累加和要清0
flag=1;/*123ab這個例子,遇到a需要保存,則遇到b就不需要在保存一次,故flag置為1,表示數已保存完*/
}

}

i++;//讀下一個字元
}
if(flag==0)/*11ab11
因為都是在每次遇到字母的時候保存數字,可能出現最後一個數字沒保存,所以最後判斷flag,看
是否還有最後一個沒保存*/
a[count]=sum;
count++;
printf("共有%d個整數\n",count);
for(i=0;i<count;i++)
printf("%d\n",a[i]);
return 0;
}
夠詳細吧,我可是一句一句的給你注釋

③ 求C語言高手,用簡單的C語言編程,要最簡單!

void main()
{
int max(int x,int y,int z);
int a,b,c,d;
scanf("%d,%d,%d",&a,&b,&d);
c=max(a,b,d);
printf("max=%d\n",c);
}
int max(int x,int y,int z)
{int max,t;
if(x<y)
if(x<z) t=x,x=z,z=t;
if(y<z)

max=x;
return(max);
}

④ 幾個簡單的C語言編程。高手進

#include<iostream.h>
#include<windows.h>

void main(void)
{
char oldpass[8]={"********"};
int a,b;
int s=0;
int p=0;
int q=0;
int r=0;
char c,newpass[7];
cout<<"請您輸入密碼:"<<endl;
cin>>newpass;
if(strcmp(newpass,oldpass)==0)
{
cout<<"請輸入兩個數:(a,b)"<<endl;
cout<<"a=";
cin>>a;
cout<<"b=";
cin>>b;
cout<<"請您選擇一種運算符(+ - * / ):";
cin>>c;
switch(c)
{
case '+':
s=a+b;
cout<<a<<"+"<<b<<"="<<s<<endl;
break;
case '-':
p=a-b;
cout<<a<<"-"<<b<<"="<<p<<endl;
break;
case '*':
q=a*b;
cout<<a<<"*"<<b<<"="<<q<<endl;
break;
case '/':
r=a/b;
cout<<a<<"/"<<b<<"="<<r<<endl;
break;
default:
cout<<"對不起!您的輸入方式有誤!請重新輸入......"<<endl;
system("pause");
}
}
else
exit(0);
}

⑤ C語言經典編程282例的前言

學會站在巨人的肩膀上!
軟體開發的終極目標是完成滿足用戶需求的軟體。一個軟體往往包含復雜的功能,作為一名程序員,需要在有限的時間內實現它們,這對於新手而言並不容易。為什麼富有開發經驗的程序員編程效率非常高呢?答案就是他們做過類似的程序,適當修改以前的代碼,就可以滿足現在的要求。因此,如何快速積累編程經驗就成了新手的當務之急。顯然,單單依靠項目來積累編程經驗是非常慢的。
本書圖文並茂、難易並舉,匯集了282個日常開發中應用廣泛的實例,內容涵蓋了C語言編程的方方面面。每個實例分為實例說明、實現過程和技術要點3部分進行講解。通過對本書的學習,不僅能快速掌握相關知識點,還可以逐步提升編程能力。
本書內容
本書以C語言的基礎知識結構為框架,給出了每部分知識中可能遇到的疑難問題或開發技巧。本書共分17章,主要包括初識C語言、簡單的C程序、演算法入門、常用數據類型、運算符與表達式、數據輸入與輸出函數、選擇和分支結構程序設計、循環結構、數組、函數編程基礎、指針、常用數據結構、位運算操作符、存儲管理、預處理和函數類型、文件讀寫、圖形圖像處理。
為了更清晰地闡述問題和給出問題的解決方案,本書設置了以下欄目。
* 實例說明:詳細描述本實例的用途,並給出實例的運行結果圖。
* 實現過程:逐步講解如何解決本實例的問題,並給出關鍵代碼、注意事項等。
* 技術要點:對本實例使用的關鍵技術進行總結,方便日後使用。
本書特色
* 貼近應用。本書精選的實例都真正來自開發一線。以實例形式進行講解,使其更容易被讀者接受。
* 橫向鏈接。本書知識框架與《C語言開發入門及項目實戰》一書相對應,可以在學習完《C語言開發入門及項目實戰》一書的基礎上使用本書,以提高自己的技能。
* 解析透徹。本書對每個問題的相關知識進行細致地講解,並進行知識拓展,使讀者不僅知其然而且知其所以然。
* 授人以漁。本書在講解技術的同時,還注重對讀者能力的培養,使讀者掌握分析問題與解決問題的能力。
本書配套資源
本書提供了內容豐富的配套資源,包括源程序、素材,以及模塊庫、案例庫、題庫、素材庫等多項輔助內容,讀者朋友可以通過如下方式獲取。
第1種方式:
(1)登錄清華大學出版社的網站,在網頁右上角的搜索文本框中輸入本書書名(注意區分大小寫和留出空格),或者輸入本書關鍵字,或者輸入本書ISBN號(注意去掉ISBN號間隔線「-」),單擊「搜索」按鈕。
(2)找到本書後單擊超鏈接,在該書的網頁下側單擊「網路資源」超鏈接,即可下載。
第2種方式:
訪問本書的新浪微博C語言圖書,找到配套資源的鏈接地址進行下載。
讀者人群
本書非常適合以下人員閱讀:
? C語言編程行業的開發人員
? 有一定語言基礎,想進一步提高技能的人員
? 大中專院校的老師和學生
? 即將走向工作崗位的大學畢業生
? 相關培訓機構的老師和學員
? C語言編程愛好者

⑥ 用C語言編程,高手請進

題目我不會做!但我翻譯了!我想知道翻譯對沒!
翻譯的:
重型貨車
約翰松大卡車公司是一家專業生產大卡車。他們最新的模型,哥斯拉的V12
,這么大的數額運輸貨物可以與它從來都不是有限的卡車本身。只有有限的重量限制,適用於道路沿線的道路要驅動器。
鑒於開始和目的地城市,你的任務是,以決定最高負荷哥斯拉的V12
,因此仍然存在著一條雙方指定城市。
輸入
輸入文件將包含一個或多個測試案例。第一線的每一個測試案例將包含兩個整數:有多少城市ñ

2

ñ

200
)和若幹道部分住宅(
1

r

19900
)決策的街道網路。
則R線會隨之而來,每一個部分描述的一條道路命名的兩個城市連接的部分,並給予重量限制的卡車,使用這一部分。名稱不長於30個字元,不包含空格字元。重量限制的整數范圍0
-
10000
。道路總是可以前往兩個方向。
的最後一行測試用例包含兩個城市名稱:啟動和目的地。
輸入將被終止的兩個值為0的n和河
輸出
對於每一個測試案例,列印三行:
香格里拉線說``情景#
X
「的其中x是一些測試案例
香格里拉線說``
Ÿ噸「
,其中Y是盡可能負荷
升一個空白行
樣本輸入4
3Karlsruhe斯圖加特100Stuttgart烏爾姆80Ulm慕尼黑120Karlsruhe
Muenchen5
5Karlsruhe斯圖加特100Stuttgart烏爾姆80Ulm慕尼黑120Karlsruhe漢堡220Hamburg慕尼黑170Muenchen
Karlsruhe0
0範例輸出情景#
1

80噸情景二一七零噸

⑦ 向高手請教一道C語言的編程題:編寫一個C程序將盡可能多的案例串聯起來,並能逐一演示

在main函數中用 switch{
case a:
案例a可以用函數的形式或者模塊的形式,
baerk;

case b:
案例b同上
:
:
defualt:
break;
}

⑧ 求C語言高手編程

Numerical Recipes in C
一書及所附程序,有完整程序。不過我封裝了它的C++版本,可以對但參數或多參數求極值,完整的頭文件為:

#ifndef __OPTIMIZATION_H__
#define __OPTIMIZATION_H__

//////////////////////////////////////////////////////////////////////////
// class TOptimization
//
// $ 求函數一個或多個參數的最小值
//
// 該類默認對一個參數優化,一般只要輸入優化參數數目
// 優化目標函數就可以使用。
//
// ...主要代碼來自:
// Numerical Recipes in C++
// The Art of Scientific Computing
// Second Edition
// William H. Press Saul A. Teukolsky
// William T. Vetterling Brian P. Flannery
//
// 中譯本:
// C++ 數值演算法(第二版) 胡健偉 趙志勇 薛運華 等譯
// 電子工業出版社 北京 (2005)
//
// Author: Jian Feng
// Email: [email protected]
// Dec. 9, 2006
//
//////////////////////////////////////////////////////////////////////////
//
// 輸入函數:
//
// @MaxIterationStep: 最大迭代次數, 默認 1000
// @ParameterNumbers: 優化參數數目, 默認 1
// @InitMatrix: 初始化矩陣參數(N*N), 默認
// @Tolerance: 容許公差, 默認 1E-7
//
// 執行函數:
//
// @ExecutePowell: 利用powell方法進行多參數優化
// @ExecuteBrent: 利用brent方法進行單參數優化
//
// 輸出函數:
//
// @OptimizatedParameters: 優化結果數據
// @ObjectiveFunctionValue: 目標函數在優化值處的值
//
// 使用示例:
//
// 1. 單參數
// double objfun(double a){
// double sum = 0;
// for(int i = 0; i < DataPoints; ++i)
// sum += SQR(Exps[i] - Theo(a));
// }
// double value
// TOptimization opt;
// if(opt.ExecuteBrent(objfun, -10, -1)) opt.OptimizatedParameters(&value);
//
// 2. 多參數
// double objfun(double *a){
// double sum = 0;
// for(int i = 0; i < DataPoints; ++i)
// sum += SQR(Exps[i] - Theo(a));
// }
// double value[3]
// TOptimization opt(3);
// double ival[3] = {-1, 0, 1};
// if(opt.ExecutePowell(objfun, ival)) opt.OptimizatedParameters(value);
//
namespace{
static int ncom; //公用變數
static double *pcom_p; //公用變數
static double *xicom_p; //公用變數
static double (*nrfunc)(double*); //公用函數指針
}

class TOptimization
{
private:
typedef double (*Reff)(double *);
typedef double (*Ptrf)(double );

public:
TOptimization(int n = 1);
~TOptimization(){ FreeMemory(); }

//主要方法
void ParameterNumbers(int n){ FreeMemory(); num = n; AllocateMemory(); }

//利用powell方法對一個或多個參數優化
bool ExecutePowell(Reff obj, double *a = 0);

//利用brent方法對一個參數優化,需給出參數所在的區間
bool ExecuteBrent(Ptrf obj, double vFrom = 0, double vTo = 1);

void OptimizatedParameters(double *a){ for(int i=0; i<num; ++i) a[i]=coef[i];}

void OptimizatedParameters(double &a){ a = vmin; }

//void OptimizatedParameters(double *a){
// if(method) for(int i=0; i<num; ++i) a[i]=coef[i];
// else *a = vmin;
//}

//其它方法
void InitMatrix(double **m)
{
for(int i=0; i<num; ++i)
for(int j = 0; j<num; ++j)
matx[i][j]=m[i][j];
setm = true;
}

void MaxIterationStep(int s){ ITMAX = s; }

void Tolerance(double eps){ ftol = eps; }

double ObjectiveFunctionValue()const{ return fret; }

private:

double brent(double ax, double bx, double cx, Ptrf f, double tol, double &xmin, int &flag);
void mnbrak(double &ax, double &bx, double &cx, double &fa, double &fb, double &fc, Ptrf func);
void linmin(double *p, double *xi, double &fret, Reff func);
bool powell(double *p, double **xi, double ftol, int &iter, double &fret, Reff func);

void shft2(double &a, double &b, const double c){ a=b; b=c; }

void shft3(double &a, double &b, double &c, const double d){ a=b; b=c; c=d; }

double SQR(double x){ return x * x; }

void SWAP(double &a, double &b){ double m=a; a=b; b=m; }

double SIGN(const double &a, const double &b){return b >= 0?(a>=0?a:-a):(a>=0?-a:a);}

double MAX(const double &a, const double &b){return b > a ? (b) : (a);}

void AllocateMemory();

void FreeMemory();

static double f1dim(double x)
{
int j;
double *xt = new double [ncom];
//Vec_Dp &pcom=*pcom_p,&xicom=*xicom_p;
double *pcom = pcom_p, *xicom = xicom_p;
for (j=0;j<ncom;j++)
xt[j]=pcom[j]+x*xicom[j];
//delete []xt;
double val = nrfunc(xt);
delete []xt;
return val;
}

bool setm; //是否設置優化方向初始矩陣

int num; //優化參數
int ITMAX; //最大迭代數
int iter; //實際迭代步數
int method; //優化方法 0: 1-D brent, 2: M-D Powell

double vmin; //一維優化參數
double ftol; //容許差
double fret; //目標函數值

double *coef; //多維優化參數值
double **matx; //多維優化參數方向的初始值

};

//////////////////////////////////////////////////////////////////////////

inline TOptimization::TOptimization(int n )
{
num = n;
ftol = 1e-7;
ITMAX = 1000;
iter = 0;
fret = 0.;
vmin = 0.;
method = 0;
setm = false;

AllocateMemory();
}

inline void TOptimization::AllocateMemory()
{
pcom_p = new double [num];
xicom_p = new double [num];
coef = new double [num];
matx = new double *[num];
for(int i = 0; i < num; ++i)
{
coef[i] = 0.;
matx[i] = new double [num];
for(int j = 0; j < num; ++j)
matx[i][j]=(i == j ? 1.0 : 0.0);
}
}

inline void TOptimization::FreeMemory()
{
for(int i = 0; i < num; ++i)
{
delete []matx[i];
}
delete []matx;
delete []pcom_p;
delete []xicom_p;
delete []coef;
}

inline bool TOptimization::ExecutePowell(Reff obj, double *a)
{
method = 1;
if(a)
for(int i = 0; i < num; ++i) coef[i] = a[i];
return powell(coef, matx, ftol, iter, fret, obj);
}

inline bool TOptimization::ExecuteBrent(Ptrf obj, double vFrom, double vTo)
{
method = 0;
int flag;
double cx, fa, fb, fc;
mnbrak(vFrom,vTo,cx,fa,fb,fc,obj);
fret = brent(vFrom,vTo,cx,obj, ftol,vmin, flag);
return flag ? true : false;
}

inline void TOptimization::mnbrak(double &ax, double &bx, double &cx, double &fa,
double &fb, double &fc, Ptrf func)
{
const double GOLD=1.618034,GLIMIT=100.0,TINY=1.0e-20;
double ulim,u,r,q,fu;

fa=func(ax);
fb=func(bx);
if (fb > fa) {
SWAP(ax,bx);
SWAP(fb,fa);
}
cx=bx+GOLD*(bx-ax);
fc=func(cx);
while (fb > fc) {
r=(bx-ax)*(fb-fc);
q=(bx-cx)*(fb-fa);
u=bx-((bx-cx)*q-(bx-ax)*r)/
(2.0*SIGN(MAX(fabs(q-r),TINY),q-r));
ulim=bx+GLIMIT*(cx-bx);
if ((bx-u)*(u-cx) > 0.0) {
fu=func(u);
if (fu < fc) {
ax=bx;
bx=u;
fa=fb;
fb=fu;
return;
} else if (fu > fb) {
cx=u;
fc=fu;
return;
}
u=cx+GOLD*(cx-bx);
fu=func(u);
} else if ((cx-u)*(u-ulim) > 0.0) {
fu=func(u);
if (fu < fc) {
shft3(bx,cx,u,cx+GOLD*(cx-bx));
shft3(fb,fc,fu,func(u));
}
} else if ((u-ulim)*(ulim-cx) >= 0.0) {
u=ulim;
fu=func(u);
} else {
u=cx+GOLD*(cx-bx);
fu=func(u);
}
shft3(ax,bx,cx,u);
shft3(fa,fb,fc,fu);
}
}

inline double TOptimization::brent(double ax, double bx, double cx,
Ptrf f, double tol, double &xmin, int &flag)
{
flag = 1;
const double CGOLD=0.3819660;
const double ZEPS=1.0e-20;
int iter;
double a,b,d=0.0,etemp,fu,fv,fw,fx;
double p,q,r,tol1,tol2,u,v,w,x,xm;
double e=0.0;

a=(ax < cx ? ax : cx);
b=(ax > cx ? ax : cx);
x=w=v=bx;
fw=fv=fx=f(x);
for (iter=0;iter<ITMAX;iter++) {
xm=0.5*(a+b);
tol2=2.0*(tol1=tol*fabs(x)+ZEPS);
if (fabs(x-xm) <= (tol2-0.5*(b-a))) {
xmin=x;
return fx;
}
if (fabs(e) > tol1) {
r=(x-w)*(fx-fv);
q=(x-v)*(fx-fw);
p=(x-v)*q-(x-w)*r;
q=2.0*(q-r);
if (q > 0.0) p = -p;
q=fabs(q);
etemp=e;
e=d;
if (fabs(p) >= fabs(0.5*q*etemp) || p <= q*(a-x) || p >= q*(b-x))
d=CGOLD*(e=(x >= xm ? a-x : b-x));
else {
d=p/q;
u=x+d;
if (u-a < tol2 || b-u < tol2)
d=SIGN(tol1,xm-x);
}
} else {
d=CGOLD*(e=(x >= xm ? a-x : b-x));
}
u=(fabs(d) >= tol1 ? x+d : x+SIGN(tol1,d));
fu=f(u);
if (fu <= fx) {
if (u >= x) a=x; else b=x;
shft3(v,w,x,u);
shft3(fv,fw,fx,fu);
} else {
if (u < x) a=u; else b=u;
if (fu <= fw || w == x) {
v=w;
w=u;
fv=fw;
fw=fu;
} else if (fu <= fv || v == x || v == w) {
v=u;
fv=fu;
}
}
}
flag = 0;
xmin=x;
return fx;
}

inline void TOptimization::linmin(double *p, double *xi, double &fret, Reff func)
{
int j, flag;
const double TOL=1.0e-8;
double xx,xmin,fx,fb,fa,bx,ax;

int n=num;
ncom=n;
//pcom_p=new Vec_Dp(n);
//xicom_p=new Vec_Dp(n);
nrfunc=func;
//Vec_Dp &pcom=*pcom_p,&xicom=*xicom_p;
double *pcom = pcom_p, *xicom = xicom_p;
for (j=0;j<n;j++) {
pcom[j]=p[j];
xicom[j]=xi[j];
}
ax=0.0;
xx=1.0;
mnbrak(ax,xx,bx,fa,fx,fb,f1dim);
fret=brent(ax,xx,bx,f1dim,TOL,xmin, flag);
for (j=0;j<n;j++) {
xi[j] *= xmin;
p[j] += xi[j];
}
//delete xicom_p;
//delete pcom_p;
}

inline bool TOptimization::powell(double *p, double **xi, double ftol, int &iter,
double &fret, Reff func)
{
const int ITMAX=500;
const double TINY=1.0e-20;
int i,j,ibig;
double del,fp,fptt,t;

int n=num;
//Vec_Dp pt(n),ptt(n),xit(n);
double *pt, *ptt, *xit;
for(i = 0; i < n; ++i)
{
pt = new double [n];
ptt = new double [n];
xit = new double [n];
}
fret=func(p);
for (j=0;j<n;j++) pt[j]=p[j];
for (iter=0;;++iter) {
fp=fret;
ibig=0;
del=0.0;
for (i=0;i<n;i++) {
for (j=0;j<n;j++) xit[j]=xi[j][i];
fptt=fret;
linmin(p,xit,fret,func);
if (fptt-fret > del) {
del=fptt-fret;
ibig=i+1;
}
}
if (2.0*(fp-fret) <= ftol*(fabs(fp)+fabs(fret))+TINY) {
delete []pt;
delete []ptt;
delete []xit;
return true;
}
if (iter == ITMAX)
{
delete []pt;
delete []ptt;
delete []xit;
return false;
//cerr<<"powell exceeding maximum iterations.";
}
for (j=0;j<n;j++) {
ptt[j]=2.0*p[j]-pt[j];
xit[j]=p[j]-pt[j];
pt[j]=p[j];
}
fptt=func(ptt);
if (fptt < fp) {
t=2.0*(fp-2.0*fret+fptt)*SQR(fp-fret-del)-del*SQR(fp-fptt);
if (t < 0.0) {
linmin(p,xit,fret,func);
for (j=0;j<n;j++) {
xi[j][ibig-1]=xi[j][n-1];
xi[j][n-1]=xit[j];
}
}
}
}
}

#endif

⑨ c語言程序設計實例

#include <stdio.h>
#define N 100
void SortSum(int a[],int i);
void main()
{
int a[N],i,n;
printf("請輸入數組個數:");
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
SortSum(a,n);
}
void SortSum(int a[],int i)
{
int j,k,m,b[N],n,s,tmp;
for(j=0;j<i;j++)
{
n=a[j];
s=0;
while(n!=0)
{
s+=n%10;
n/=10;
}
b[j]=s;
}
printf("轉換後數組如下:\n");
for(j=0;j<i;j++)
{
m=j;
for(k=j+1;k<i;k++)
{
if(b[k]>b[m])
m=k;
}
if(m!=j)
{
tmp=b[j];
b[j]=b[m];
b[m]=tmp;

tmp=a[j];
a[j]=a[m];
a[m]=tmp;
}
}
for(j=0;j<i;j++)
printf("%d ",a[j]);
printf("\n");
}
------------------------------------
呵呵,我用的是選擇法排序,樓上的也不錯啊

⑩ C語言的經典編程例子


程序員》推薦C++ 圖書三人談

主持人:熊節(透明),《程序員》雜志編輯,C-View成員
嘉 賓:孟岩(夢魘),聯想公司掌上設備事業部應用開發處任職,C-View成員。與侯捷先生合譯《C++ Standard Library》一書
金尹(惡魔),上海天宇公司CTO,在《程序員》連載有「自由與繁榮的國度」系列文章

透明:「學C++用哪本書入門」,這是被問得最多的一個問題。但是哪一本書是最好的入門書?似乎很難找到答案。《C++ Primer》太厚,《Effective C++》對讀者要求比較高,《Essential C++》又常常被批評為「太淺」。
其實說穿了:no silver bullet。想從一本書學會C++,那是不可能的。有朋友問我如何學C++,我會建議他先去找本數據結構書,把裡面的習題全部用C++做一遍,然後再去看《Effective C++》。myan經常說「要在學習初期養成好習慣」,我對此頗不以為然。
個人認為,《Essential C++》適合作教材,《C++ Primer》適合作參考書,《Effective C++》適合作課外讀物。

惡魔:很後悔當初買了《C++ Primer》。因為從我個人角度來看,它的功能效用基本是和《The C++ Programming Language》重合。當然對於入門來說,它還是很不錯的。但是《C++ Primer》太厚,一來導致看書極其不方便,二來系統學習需要花比較長的時間。對於目前這個越來越快餐化的時代來說,的確有很多不適合的地方,不過可以作為初學者的參考書。現在我以一塊K3 CPU的代價把它借給了別人,希望我那位同事能夠從中得到一些益處。
如果已經具備了C基礎,我建議看國內的書,例如錢能的《 C++大學教程(第二版) 》。(如果沒有C的基礎還是看譚浩強的C語言)。這本書對C講得還算比較清晰,有很多習題值得一做,特別是最後的struct和union兩個部分。其中的一些演算法比較拖沓和繁瑣(比如樹和鏈表的遍歷演算法),讀者可以嘗試修改這些例子,作為最後對C語言的一些總結測試。

夢魘:這個問題讓我想起四五年前的情形。今天對於C++有一點認識的人,多半是從那幾年就開始學C++了。那時根本沒有品牌觀念。從書店裡找一本C++書,如果看著還算明白,就買下來。我記得那時候宛延闓、張國鋒、麥中凡教授的書都受到很高的贊譽。我個人最早的一本C++書是Greg Perry的一本書,今天想起來,其實是一本打著C++旗號的C語言教程。對我作用最大的一本書是國防科技出版社出版的一本書,書名記不得了,作者叫斯蒂芬·布萊哈。
透明:還記得以前曾批評過一本C++書,是北航出的,整本書就沒有出現過class關鍵字。那本書,說穿了其實只是介紹了C語言和iostream庫的用法,根本不能算C++。而當時我常常推薦的一本書是電子科技大學張松梅老師的C++教程。那本書,直到今天來看也沒有太大的問題,唯一的缺憾就是由於年代久遠,許多東西已經過時了。而對於一本技術書籍來說,「過時」是最不可接受的。
總體來說,那時使用C++的人真是在「盲人摸象」。不過這也有好處,就是對C++的很多細節能搞清楚,以後看到經典好書時比較容易理解;當然壞處就是概念不清,甚至都不知道C++和Visual C++、Borland C++到底有什麼不一樣。

夢魘:整個90年代,其實大部分人對於C++的認識都似是而非。一開始是等同於Borland C++,後來是等同於Visual C++和MFC。所以一般來說,打著BC和VC旗號的書賣得很好,人們覺得這就是C++。而我比較幸運,布萊哈的那本書雖然從現在的眼光來看談不上高超,但基本路子是對的。可能是因為原書是給UNIX程序員的培訓教材,所以沒有讓我一開始就形成「C++ == VC++」的認識。
其實一直到1996年,我們那裡搞計算機的都是唯Borland C++馬首是瞻的,到了VC 4.0出來,一下子格局全變了。1997年VC5推出之後,書店裡MFC書鋪天蓋地,學MFC的人,頭抬得都比別人高一些。不過現在看來,那時候大部分的MFC書都是三流貨色。我曾經有一段時間認為,那一批程序員中間有不少被誤導了。根本原因就是相對的封閉。

透明:我覺得一本書的價值有兩方面:第一,教給你實用的技術;第二,促使你去思考。對於一本介紹VC(或者說MFC)使用方法的書,我根本不希望它能促使我有什麼思考,所以我就一定要求它在技術上精益求精完美無瑕。我剛開始用VC的時候,買的第一本書就是潘愛民老師翻譯的《VC技術內幕》(第四版),沒有受到那些「三流貨色」的誤導,應該說是很幸運的。

夢魘:1999年機械工業出版社開始出版「計算機科學叢書」,其中的《Thinking in C++》第一版受到了廣泛的歡迎。其實我一直不認為這本書很出色,雖然拿過一次大獎。然而我們都得承認,這本書在C++書籍領域里第一次建立了品牌觀念,很多初學者開始知道,不是隨便買哪一本都一樣的。再往後就是2000年的《 深入淺出MFC(第二版) 》第二版,以及侯先生在《程序員》上發表的那一篇《C++/OOP大系》,加上整個大環境的變化,品牌觀念深入人心,C++書籍市場終於開始逐漸與世界同步。
回想往事,我的感覺是,那個需要戰戰兢兢選擇入門書的時代已經過去,今天的C++初學者,大可以放心地買口碑好、自己讀起來思路順暢的書,入門不再是太大的問題。還有一些程序員已經學了幾年C++,但看到今天出版的一些新書,感覺比較陌生,這也不是什麼問題。侯先生經常說「凡走過必留下足跡」,所謂「走彎路」,未必不是一件好事。
至於具體的推薦表,就不好一概而論了。總之在我的印象里,《Essential C++》、《C++ Primer》、錢能教授的C++教程,都不錯。甚至有人一上來就看Bjarne Stroustrup的《The C++ Programming Language》,只要他喜歡,也沒什麼不可以。

透明:我同意你的觀點。不管怎麼說,編程是門實踐性非常強的學問。要想對C++對象模型有深入的了解,最好的辦法就是寫一串程序去看結果;要想學會OOP,也只能從項目中學。對於初學者,最好的學習方法就是不停地寫程序,寫真正有用的程序,寫到有問題的時候就去查書,於是自然就會知道哪本書好哪本書不好。不過我們的教育制度能不能讓大學里的學生們有這樣的學習機會,我表示懷疑。
以我的經驗,學C++有兩個門檻:入門和使用。完全看不懂C++,這是一個門檻,但是只要有一本合適的入門書,很快就能跨過。要想真正用上C++,卻不是件很容易的事情。尤其對於學生來說,接觸到的東西多是「玩具」,很難有實戰的機會。所以經常看見有人問「C++到底能做什麼」,這是C++學習中一個比較麻煩的問題。我們都是做了相當長時間的C++程序之後才看到一些真正經典的書,也正是因為走了相當長的彎路之後才知道這些書的經典之所在。所謂彎路,我想也是一種必須的積累。就算一開始就看《Essential C++》和《C++ Primer》,沒有兩三年的時間恐怕還是難有所得。

惡魔:有兩句十分有道理的話,一是我大學的C語言老師說的「寫程序不如說是抄程序」,另一句是一網友說的「好的設計來自借鑒,天才的設計來自剽竊」。對於我這個理性批判主義者來說,這兩句話的確不太適合。但是無論從哪個角度來講,對於初學者來說,剽竊大師的作品是通向成功的最快捷徑。
我個人認為,對於C++的初學者來說,首先要確定自己專業領域內主要使用的特性的方向。因為C++的特性如此眾多,初學者想貪多基本是不可能成功的。C++的編程範式基本可以分為ADT+PP、GP和OO三個方向。對於ADT+PP範式來說,初學者的主要問題不是學習C++,而是學習C的使用。對於這樣的初學者,國內的幾本書還是寫得比較清楚,符合中國人的習慣,比如譚浩強的《C語言教程》、錢能的《C++語言大學教程》。這兩本書我首推第一本,因為這一本我潛心研究了一年,這本書當中很多程序是可以剽竊的,而且可以對這些程序進行加工和提升。比如結構這一章中,它所給出的用struct來實現鏈表、二叉樹的演算法是相當蹩腳的。學習ADT+PP的初學者將這本書揣摩透以後可以嘗試修改這兩個程序。另外這本書的第二版稍微涉及了一些關於「類」的內容。學習ADT+PP的初學者,可以不被OO中的一些專有特性擾亂自己的思路,對於類層次扁平、無繼承、無多態的程序編寫是有很大好處的。

透明:你好象比較推崇國內教授寫的書。現在社會上有種不好的風氣:一捧就捧上天,一貶就貶下地。就好象對待譚教授的書,前幾年是奉為經典,這幾年又有很多人使勁批評。學C++更是有點「崇洋媚外」,總是覺得初學就應該看《Essential C++》。我看這種觀點也是片面的。

惡魔:當然《Essential C++》也值得看看。但是我個人覺得這本書沒有譚浩強的《C語言教程》來得好。主要原因是:第一,C++的所有特性都點到了,但是不深,看了以後會三心二意沒有方向;第二,可以抄襲借鑒的例子太少。《C語言教程》中有很多有趣的問題,比如猴子吃桃、漢諾塔等等,這些例子對於剛剛涉及C/C++語言編程的人來說是學習編程很好的例子。《Essential C++》只能是前兩本書看透以後,作為學習C++特性的一個過渡性的書籍。讓讀者真正領略到什麼是C++的編程、和C編程的不同點在哪裡。

透明:我發現一個很有趣的現象:初學者往往喜歡問「哪本書比較好」,這讓我很是不解。這有點像一個剛學打籃球的人問「王治郅和科比誰比較厲害」。當然科比更厲害一些。但如果你是想學打籃球,這兩個人都非常非常有資格教你,你跟誰學都能學得很強——關鍵不是在於你選哪個老師,而是在於你自己用多少功夫去學。

透明:回到原來話題。學會了C++的語法,能看懂C++代碼之後,必須有些書來指導進階(或者叫指點迷津)。我覺得《設計模式》很好,能夠讓讀者看到一些精妙的用法。不過正如我經常說的,模式帶來的麻煩和好處一樣多,甚至麻煩還要更多。而且,C++本身的問題使得在C++中使用GoF模式愈加麻煩。

夢魘:《Design Patterns》這本書絕對是不可以沒有的,而且中英文版都不可少。最初我看中文版,說實話看不懂,但是也不覺得人家翻譯得不好,所以就想,大概是原文就很難懂,加上自己水平有限。於是總是想著再找幾本patterns的書來看。後來找到幾本書,口碑還不錯,不過水平高下,一比就出來了,還是那本《Design Patterns》最經典,最耐看。英文版出來之後,兩個版本對照看,明白多了。現在覺得,其實就設計模式來講,把這本看明白了就很不錯了,不用再花費很多心思找其他的書。我現在的包里始終夾著這本書,隨身攜帶,有備無患。
至於說設計模式的副作用,和可能帶來的弊端,我的體會也挺多。不過是這樣,我們想一想,究竟什麼情況下設計模式可以用得很好呢?一種是有經驗豐富的人引導,比如要是Robert Martin帶隊,你在某個地方用錯了設計模式,他就會指出來,說這里不對,將來會產生什麼樣的弊端。對於他來說,豐富的實踐經驗足以支持他進行「預測型」設計。但是大部分人沒這個能力,因此我們只好走第二條路和第三條路,就是「試探型」設計和「重構型」設計。遇到一個問題,你覺得用某種模式挺合適的,就大膽地用了,成功是積累經驗,發現不好,出了問題了,只好改回來,那也是積累教訓。這叫做「試探型」。至於重構,應該算是最有組織、成功率最高的工程化方法。先把問題「quick and dirty」地解決了,所有的暗礁都暴露出來,然後再根據實際情況採用合適的模式優化設計。現在XP和UP都高度重視refactory,UP在Elaboration和Construction階段都鼓勵抽出專門的iterations進行重構。所以說如果組織快速的軟體開發,當然比較傾向於這條路——打成功率嘛。

透明:講到重構,我順便說說《Refactoring》這本書的影響。從工程本身的角度來說,你所謂的「重構型設計」是沒有什麼問題的。但中國的開發者(也包括我在內)往往比較沖動,比較容易相信銀彈的存在。曾經有那麼一段時間,我在Java中嘗試過了重構的方法之後,又拿到C++中去嘗試。結果發現,在Java中速度非常快的重構過程,到C++中就被減慢了。究其原因,就是因為C++和Java的約束條件不同。拿著Java中成功的案例直接套C++,不失敗才怪。
所以,我必須說:《Refactoring》這本書很有價值。但對於C++程序員來說,它的價值是讓你思考,思考這種方法的可行性。如果一個C++程序員沒有打算遷移到Java,那麼我必須告訴他:《Refactoring》這本書不是讓你照著它用的,甚至不是讓你去相信它的。對於C++程序員,《Refactoring》全書可以放心相信的只有第13章,其他的部分,都必須非常謹慎地對待。

夢魘:我還要就「試探型」的方法多說兩句,我覺得對於個人發展來講,「試探」也是必不可少的,撞牆不可怕,高水平的人不都是撞出來的嗎?你失敗了一次,就知道這個模式有什麼潛在的問題,下次再用,就會多看幾步,像下棋似的。撞的多了,路數就出來了。
我不知道你們是否有這個感覺:用錯了模式,吃了虧,再回過頭去翻翻《Design Patterns》,看到人家早就指出來這個問題,不過就是那麼幾句話,原來看上去乾巴巴的,現在覺得句句都講到心坎上,GoF的形象馬上就高大起來,還帶著光環,感覺是既興奮又懊悔。

透明:現在回頭來看,我更欣賞myan推薦給我的《Designing Object-Oriented C++ Applications Using Booch Method》。這本書能夠幫助C++程序員理清思路培養習慣,可惜國內沒有引進。相比後來商業味濃厚的UML系列書籍,我覺得這本書對於面向對象的闡釋精闢獨到,至今未有能出其右者。

夢魘:剛才我們兩人都說到Robert Martin,他可是我的榜樣。那本1995年的《Designing Object Oriented C++ Application》,我覺得是每一個C++軟體工程師都應該反復研讀的書。可惜不僅國內沒有引進,在國外的名氣也不大。如果你覺得面向對象的那些道理你好像都明白,可就是一遇到實際問題就使不上勁,那這本書就是你的最佳導師。
提到理清思路,還有一本書不得不提,就是Andrew Koenig的《Ruminations On C++》。每個人都應該問自己,我學了這么多年的C++,究竟什麼是C++最基本的設計理念?遇到問題我第一個直覺是什麼?第一個試探型的解決方案應該具有那些特點?如果你不能給出明確的答案,就應該認真地去讀這本書,讀完了你就有了「主心骨」。

透明:插一句話,談談「推薦書」的問題。入門書基本上是放之四海而皆準的,所以推薦的意義也不大。而入門後的發展方向,每個人不同,這個時候就需要「高人」的指點。舉個例子:我學C++的時候,myan還不認識我,所以也沒有給我推薦書,我還是學過來了,所以即使你當時向我推薦了《Essential C++》或者《C++ Primer》,我也不會太感謝你;但在我認真研究OO的時候,你推薦Robert Martin那本書給我,對我幫助就特別大,而且我從別的地方也很難找到類似的推薦,所以我就很感謝你。
一個程序員,必須有framework的意識,要學會用framework,還要主動去分析framework(在這方面,《Design Patterns》能有一定的幫助)。但是,真正高質量、成氣候的framework的書恐怕也就只有針對MFC的。從這個角度來說,MFC縱有千般不是,C++程序員都非常有必要先去用它、熟悉它、研究它,甚至藉助《深入淺出MFC》這樣的書來剖析它。不然,很難有framework的意識和感覺。
當然,另一個framework也很好,那就是STL。不管用不用MFC、STL,對這兩個東西的掌握和理解都是極有幫助的。最近我又在看《深入淺出MFC》,雖然已經不用MFC編程了,但幫助是一定有的。

夢魘:MFC和STL方面,我還是比較推崇侯先生的兩本書《深入淺出MFC》和《STL源碼解析》。
《深入淺出MFC》這本書,名氣自然是大得不得了,不過也有不少人批評。其實書也沒有十全十美的,批評當然是少不了的,不過有的時候我看到有人評論這本書,把它跟Inside VC相比,真的是牛頭不對馬嘴。
你剛才其實說得很對,程序員應該有一點framework意識。而這本《深入淺出MFC》與其說是在講MFC編程,不如說通篇是在拿MFC為例分析Application Framework的架構和脈絡。所以無論你對於MFC本身是什麼態度,這本書對每一個C++程序員都有很大的益處。

透明:是的。《VC技術內幕》會告訴你「DYNAMIC_CREATE這個宏怎麼用」,《深入淺出MFC》則告訴你「DYNAMIC_CREATE這個宏是怎麼實現的」。所以,如果你只需要在VC下寫一些小應用程序,《深入淺出MFC》的價值並不太大;但是,如果你需要設計一個稍微大一點的東西(不一定是framework),MFC的設計思想就會有所幫助。

夢魘:另外,我覺得對於MFC也應該有一個公允的評價。過去是吹捧得天上有地下無,書店裡鋪天蓋地都是MFC的書,搞得大家只知有MFC,不知有C++,甚至直到現在還有人問:「我是學MFC呢,還是學C++?VC++是不是比C++更高級的語言?」MFC成了一尊神像,阻礙了人們的視線。所以得把它從神壇上拉下來。這就是過去一兩年有很多人,包括我在內批評MFC的一個目的。可是現在大家視野開闊了,.NET也出來了,MFC不再是神像了,少數人就開始以貶損MFC為樂了。我覺得這種態度是不對的。
什麼叫好的框架?我覺得在十幾年的時間能夠象MFC這樣保持穩定並且不斷進步的框架就是好的框架。可能我們在一些具體的設計問題上有不同看法,覺得「這個地方這么設計不是更漂亮嗎?」很多時候是的,但是這不重要,重要的是MFC成熟穩定、有十幾年的成功經驗,這是最了不起的東西。
另外一點,MFC中間包括著學習Win32 API編程的最佳資料。這是除了其framework方面之外的另一個亮點。我現在使用Win32 API開發,但是經常參考MFC的源代碼,收獲很大。

透明:STL方面,我對於剖析它的源代碼興趣並不大,畢竟裡面源代碼多是演算法問題。所以,《STL源碼剖析》我也只是隨便翻翻就束之高閣了。我覺得這本書用來做計算機系的數據結構和演算法教材不錯,不知道有沒有老師樂意這樣做。
對於STL,我的態度一向都是「應用至上」。不過,我一直認為SGI STL本身就是一本精彩的書,一本數據結構和演算法的經典參考書,同時也是泛型技術的參考書。想知道一個演算法是如何實現的,看看STL源代碼就行;想知道如何使用type traits,STL源代碼裡面也有例子。看別人寫的書,總覺得隔著一層紗,有點撓不到癢處的感覺。SGI STL的代碼寫得非常漂亮,一個C++程序員如果不看看這本書,實在是可惜。

夢魘:至於STL,除了《STL源碼解析》之外,我舉賢不避親,強烈推薦侯先生與我合譯的那本《The C++ Standard Library》。這本書質量之高是無需懷疑的。我現在手邊常備此書,隨時查閱,對我幫助很大。

透明:C++和Java相比,最大的優勢就是它沒有一個專門的公司來管它,最大的弱點也是它沒有一個專門的公司來管它。Java程序員在學會簡單的語法之後,立刻進入SUN提供的framework,一邊用這個現成的framework做實際開發,一邊在開發過程中繼續學習Java一些幽深的特性。而這個時候,C++程序員恐怕還在問「VC和BCB哪個好」呢。這無疑是浪費時間。

夢魘:剛才你說Java和C++的優劣,這個話題已經成了我們這個年代永不消失的聲波了。我也不想再談這個。不過有一點我得說清楚:現在我們很多用C++的人吃了不少苦頭,探過脖子去看看Java,覺得它真是太可愛了,這種印象是不準確的。另外,Java也不簡單,而且會越來越龐大復雜。在很多場合,Java還不具有競爭力。至於將來如何,我看有些Java愛好者也過分樂觀了,似乎計算機科學界幾十年解決不了的問題都可以借著Java的東風解決掉,恐怕沒那麼容易。

透明:那當然。我再次強調:No Silver Bullet。讀書很重要,但古人說「行萬里路,讀萬卷書」,還是把「行路」放在「讀書」前面。尤其對於技術書籍,如果它不能幫我解決問題、不能給我帶來非常實際的利益,那麼我是不會去讀它的。惡魔說得對,我們這個社會很快餐,我們這個行業尤其很快餐,我們也只能努力適應它。