当前位置:首页 » 编程语言 » 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。读书很重要,但古人说“行万里路,读万卷书”,还是把“行路”放在“读书”前面。尤其对于技术书籍,如果它不能帮我解决问题、不能给我带来非常实际的利益,那么我是不会去读它的。恶魔说得对,我们这个社会很快餐,我们这个行业尤其很快餐,我们也只能努力适应它。