c語言程序例子
『壹』 c語言程序設計實例
這是個宏定義,表示後面那個格式化字元串以FORMAT來代替
『貳』 經典C語言程序例子
題目01:在一個已知的字元串中查找最長單詞,假定字元串中只含字母和空格,空格用來分隔不同的單詞。
(2)c語言程序例子擴展閱讀:
C語言是一門通用計算機編程語言,應用廣泛。C語言的設計目標是提供一種能以簡易的方式編譯、處理低級存儲器、產生少量的機器碼以及不需要任何運行環境支持便能運行的編程語言。
盡管C語言提供了許多低級處理的功能,但仍然保持著良好跨平台的特性,以一個標准規格寫出的C語言程序可在許多電腦平台上進行編譯,甚至包含一些嵌入式處理器(單片機或稱MCU)以及超級電腦等作業平台。
『叄』 經典C語言編程30例(二)
【程序31】
題目:請輸入星期幾的第一個字母來判斷一下是星期幾,如果第一個字母一樣,則繼續
判斷第二個字母。
1.程序分析:用情況語句比較好,如果第一個字母一樣,則判斷用情況語句或if語句判斷第二個字母。
2.程序源代碼:
#include
void main()
{
char letter;
printf("please input the first letter of someday\n");
while ((letter=getch())!='Y')/*當所按字母為Y時才結束*/
{ switch (letter)
{case 'S':printf("please input second letter\n");
if((letter=getch())=='a')
printf("saturday\n");
else if ((letter=getch())=='u')
printf("sunday\n");
else printf("data error\n");
break;
case 'F':printf("friday\n");break;
case 'M':printf("monday\n");break;
case 'T':printf("please input second letter\n");
if((letter=getch())=='u')
printf("tuesday\n");
else if ((letter=getch())=='h')
printf("thursday\n");
else printf("data error\n");
break;
case 'W':printf("wednesday\n");break;
default: printf("data error\n");
}
}
}
==============================================================
【程序32】
題目:Press any key to change color, do you want to try it. Please hurry up!
1.程序分析:
2.程序源代碼:
#include
void main(void)
{
int color;
for (color = 0; color < 8; color++)
{
textbackground(color);/*設置文本的背景顏色*/
cprintf("This is color %d\r\n", color);
cprintf("Press any key to continue\r\n");
getch();/*輸入字元看不見*/
}
}
==============================================================
【程序33】
題目:學習gotoxy()與clrscr()函數
1.程序分析:
2.程序源代碼:
#include
void main(void)
{
clrscr();/*清屏函數*/
textbackground(2);
gotoxy(1, 5);/*定位函數*/
cprintf("Output at row 5 column 1\n");
textbackground(3);
gotoxy(20, 10);
cprintf("Output at row 10 column 20\n");
}
==============================================================
【程序34】
題目:練習函數調用
1. 程序分析:
2.程序源代碼:
#include
void hello_world(void)
{
printf("Hello, world!\n");
}
void three_hellos(void)
{
int counter;
for (counter = 1; counter <= 3; counter++)
hello_world();/*調用此函數*/
}
void main(void)
{
three_hellos();/*調用此函數*/
}
==============================================================
【程序35】
題目:文本顏色設置
1.程序分析:
2.程序源代碼:
#include
void main(void)
{
int color;
for (color = 1; color < 16; color++)
{
textcolor(color);/*設置文本顏色*/
cprintf("This is color %d\r\n", color);
}
textcolor(128 + 15);
cprintf("This is blinking\r\n");
}
==============================================================
【程序36】
題目:求100之內的素數
1.程序分析:
2.程序源代碼:
#include
#include "math.h"
#define N 101
main()
{
int i,j,line,a[N];
for(i=2;ifor(i=2;i for(j=i+1;j {
if(a[i]!=0&&a[j]!=0)
if(a[j]%a[i]==0)
a[j]=0;}
printf("\n");
for(i=2,line=0;i{
if(a[i]!=0)
{printf("]",a[i]);
line++;}
if(line==10)
{printf("\n");
line=0;}
}
}
==============================================================
【程序37】
題目:對10個數進行排序
1.程序分析:可以利用選擇法,即從後9個比較過程中,選擇一個最小的與第一個元素交換,
下次類推,即用第二個元素與後8個進行比較,並進行交換。
2.程序源代碼:
#define N 10
main()
{int i,j,min,tem,a[N];
/*input data*/
printf("please input ten num:\n");
for(i=0;i{
printf("a[%d]=",i);
scanf("%d",&a[i]);}
printf("\n");
for(i=0;iprintf("]",a[i]);
printf("\n");
/*sort ten num*/
for(i=0;i{min=i;
for(j=i+1;jif(a[min]>a[j]) min=j;
tem=a[i];
a[i]=a[min];
a[min]=tem;
}
/*output data*/
printf("After sorted \n");
for(i=0;iprintf("]",a[i]);
}
==============================================================
【程序38】
題目:求一個3*3矩陣對角線元素之和
1.程序分析:利用雙重for循環控制輸入二維數組,再將a[i][i]累加後輸出。
2.程序源代碼:
main()
{
float a[3][3],sum=0;
int i,j;
printf("please input rectangle element:\n");
for(i=0;i<3;i++)
for(j=0;j<3;j++)
scanf("%f",&a[i][j]);
for(i=0;i<3;i++)
sum=sum+a[i][i];
printf("ijiaoxian he is %6.2f",sum);
}
==============================================================
【程序39】
題目:有一個已經排好序的數組。現輸入一個數,要求按原來的規律將它插入數組中。
1. 程序分析:首先判斷此數是否大於最後一個數,然後再考慮插入中間的數的情況,插入後
此元素之後的數,依次後移一個位置。
2.程序源代碼:
main()
{
int a[11]={1,4,6,9,13,16,19,28,40,100};
int temp1,temp2,number,end,i,j;
printf("original array is:\n");
for(i=0;i<10;i++)
printf("]",a[i]);
printf("\n");
printf("insert a new number:");
scanf("%d",&number);
end=a[9];
if(number>end)
a[10]=number;
else
{for(i=0;i<10;i++)
{ if(a[i]>number)
{temp1=a[i];
a[i]=number;
for(j=i+1;j<11;j++)
{temp2=a[j];
a[j]=temp1;
temp1=temp2;
}
break;
}
}
}
for(i=0;i<11;i++)
printf("m",a[i]);
}
==============================================================
【程序40】
題目:將一個數組逆序輸出。
1.程序分析:用第一個與最後一個交換。
2.程序源代碼:
#define N 5
main()
{ int a[N]={9,6,5,4,1},i,temp;
printf("\n original array:\n");
for(i=0;i printf("M",a[i]);
for(i=0;i {temp=a[i];
a[i]=a[N-i-1];
a[N-i-1]=temp;
}
printf("\n sorted array:\n");
for(i=0;i printf("M",a[i]);
}
【程序41】
題目:學習static定義靜態變數的用法
1.程序分析:
2.程序源代碼:
#include "stdio.h"
varfunc()
{
int var=0;
static int static_var=0;
printf("\40:var equal %d \n",var);
printf("\40:static var equal %d \n",static_var);
printf("\n");
var++;
static_var++;
}
void main()
{int i;
for(i=0;i<3;i++)
varfunc();
}
==============================================================
【程序42】
題目:學習使用auto定義變數的用法
1.程序分析:
2.程序源代碼:
#include "stdio.h"
main()
{int i,num;
num=2;
for (i=0;i<3;i++)
{ printf("\40: The num equal %d \n",num);
num++;
{
auto int num=1;
printf("\40: The internal block num equal %d \n",num);
num++;
}
}
}
==============================================================
【程序43】
題目:學習使用static的另一用法。
1.程序分析:
2.程序源代碼:
#include "stdio.h"
main()
{
int i,num;
num=2;
for(i=0;i<3;i++)
{
printf("\40: The num equal %d \n",num);
num++;
{
static int num=1;
printf("\40:The internal block num equal %d\n",num);
num++;
}
}
}
==============================================================
【程序44】
題目:學習使用external的用法。
1.程序分析:
2.程序源代碼:
#include "stdio.h"
int a,b,c;
void add()
{ int a;
a=3;
c=a+b;
}
void main()
{ a=b=4;
add();
printf("The value of c is equal to %d\n",c);
}
==============================================================
【程序45】
題目:學習使用register定義變數的方法。
1.程序分析:
2.程序源代碼:
void main()
{
register int i;
int tmp=0;
for(i=1;i<=100;i++)
tmp+=i;
printf("The sum is %d\n",tmp);
}
==============================================================
【程序46】
題目:宏#define命令練習(1)
1.程序分析:
2.程序源代碼:
#include "stdio.h"
#define TRUE 1
#define FALSE 0
#define SQ(x) (x)*(x)
void main()
{
int num;
int again=1;
printf("\40: Program will stop if input value less than 50.\n");
while(again)
{
printf("\40:Please input number==>");
scanf("%d",&num);
printf("\40:The square for this number is %d \n",SQ(num));
if(num>=50)
again=TRUE;
else
again=FALSE;
}
}
==============================================================
【程序47】
題目:宏#define命令練習(2)
1.程序分析:
2.程序源代碼:
#include "stdio.h"
#define exchange(a,b) { \ /*宏定義中允許包含兩道衣裳命令的情形,此時必須在最右邊加上"\"*/
int t;\
t=a;\
a=b;\
b=t;\
}
void main(void)
{
int x=10;
int y=20;
printf("x=%d; y=%d\n",x,y);
exchange(x,y);
printf("x=%d; y=%d\n",x,y);
}
==============================================================
【程序48】
題目:宏#define命令練習(3)
1.程序分析:
2.程序源代碼:
#define LAG >
#define SMA <
#define EQ ==
#include "stdio.h"
void main()
{ int i=10;
int j=20;
if(i LAG j)
printf("\40: %d larger than %d \n",i,j);
else if(i EQ j)
printf("\40: %d equal to %d \n",i,j);
else if(i SMA j)
printf("\40:%d smaller than %d \n",i,j);
else
printf("\40: No such value.\n");
}
==============================================================
【程序49】
題目:#if #ifdef和#ifndef的綜合應用。
1. 程序分析:
2.程序源代碼:
#include "stdio.h"
#define MAX
#define MAXIMUM(x,y) (x>y)?x:y
#define MINIMUM(x,y) (x>y)?y:x
void main()
{ int a=10,b=20;
#ifdef MAX
printf("\40: The larger one is %d\n",MAXIMUM(a,b));
#else
printf("\40: The lower one is %d\n",MINIMUM(a,b));
#endif
#ifndef MIN
printf("\40: The lower one is %d\n",MINIMUM(a,b));
#else
printf("\40: The larger one is %d\n",MAXIMUM(a,b));
#endif
#undef MAX
#ifdef MAX
printf("\40: The larger one is %d\n",MAXIMUM(a,b));
#else
printf("\40: The lower one is %d\n",MINIMUM(a,b));
#endif
#define MIN
#ifndef MIN
printf("\40: The lower one is %d\n",MINIMUM(a,b));
#else
printf("\40: The larger one is %d\n",MAXIMUM(a,b));
#endif
}
==============================================================
【程序50】
題目:#include 的應用練習
1.程序分析:
2.程序源代碼:
test.h 文件如下:
#define LAG >
#define SMA <
#define EQ ==
#include "test.h" /*一個新文件50.c,包含test.h*/
#include "stdio.h"
void main()
{ int i=10;
int j=20;
if(i LAG j)
printf("\40: %d larger than %d \n",i,j);
else if(i EQ j)
printf("\40: %d equal to %d \n",i,j);
else if(i SMA j)
printf("\40:%d smaller than %d \n",i,j);
else
printf("\40: No such value.\n");
}
【程序51】
題目:學習使用按位與 & 。
1.程序分析:0&0=0; 0&1=0; 1&0=0; 1&1=1
2.程序源代碼:
#include "stdio.h"
main()
{
int a,b;
a=077;
b=a&3;
printf("\40: The a & b(decimal) is %d \n",b);
b&=7;
printf("\40: The a & b(decimal) is %d \n",b);
}
==============================================================
【程序52】
題目:學習使用按位或 | 。
1.程序分析:0|0=0; 0|1=1; 1|0=1; 1|1=1
2.程序源代碼:
#include "stdio.h"
main()
{
int a,b;
a=077;
b=a|3;
printf("\40: The a & b(decimal) is %d \n",b);
b|=7;
printf("\40: The a & b(decimal) is %d \n",b);
}
==============================================================
【程序53】
題目:學習使用按位異或 ^ 。
1.程序分析:0^0=0; 0^1=1; 1^0=1; 1^1=0
2.程序源代碼:
#include "stdio.h"
main()
{
int a,b;
a=077;
b=a^3;
printf("\40: The a & b(decimal) is %d \n",b);
b^=7;
printf("\40: The a & b(decimal) is %d \n",b);
}
==============================================================
【程序54】
題目:取一個整數a從右端開始的4~7位。
程序分析:可以這樣考慮:
(1)先使a右移4位。
(2)設置一個低4位全為1,其餘全為0的數。可用~(~0<<4)
(3)將上面二者進行&運算。
2.程序源代碼:
main()
{
unsigned a,b,c,d;
scanf("%o",&a);
b=a>>4;
c=~(~0<<4);
d=b&c;
printf("%o\n%o\n",a,d);
}
==============================================================
【程序55】
題目:學習使用按位取反~。
1.程序分析:~0=1; ~1=0;
2.程序源代碼:
#include "stdio.h"
main()
{
int a,b;
a=234;
b=~a;
printf("\40: The a's 1 complement(decimal) is %d \n",b);
a=~a;
printf("\40: The a's 1 complement(hexidecimal) is %x \n",a);
}
==============================================================
【程序56】
題目:畫圖,學用circle畫圓形。
1.程序分析:
2.程序源代碼:
/*circle*/
#include "graphics.h"
main()
{int driver,mode,i;
float j=1,k=1;
driver=VGA;mode=VGAHI;
initgraph(&driver,&mode,"");
setbkcolor(YELLOW);
for(i=0;i<=25;i++)
{
setcolor(8);
circle(310,250,k);
k=k+j;
j=j+0.3;
}
}
==============================================================
【程序57】
題目:畫圖,學用line畫直線。
1.程序分析:
2.程序源代碼:
#include "graphics.h"
main()
{int driver,mode,i;
float x0,y0,y1,x1;
float j=12,k;
driver=VGA;mode=VGAHI;
initgraph(&driver,&mode,"");
setbkcolor(GREEN);
x0=263;y0=263;y1=275;x1=275;
for(i=0;i<=18;i++)
{
setcolor(5);
line(x0,y0,x0,y1);
x0=x0-5;
y0=y0-5;
x1=x1+5;
y1=y1+5;
j=j+10;
}
x0=263;y1=275;y0=263;
for(i=0;i<=20;i++)
{
setcolor(5);
line(x0,y0,x0,y1);
x0=x0+5;
y0=y0+5;
y1=y1-5;
}
}
==============================================================
【程序58】
題目:畫圖,學用rectangle畫方形。
1.程序分析:利用for循環控制100-999個數,每個數分解出個位,十位,百位。
2.程序源代碼:
#include "graphics.h"
main()
{int x0,y0,y1,x1,driver,mode,i;
driver=VGA;mode=VGAHI;
initgraph(&driver,&mode,"");
setbkcolor(YELLOW);
x0=263;y0=263;y1=275;x1=275;
for(i=0;i<=18;i++)
{
setcolor(1);
rectangle(x0,y0,x1,y1);
x0=x0-5;
y0=y0-5;
x1=x1+5;
y1=y1+5;
}
settextstyle(DEFAULT_FONT,HORIZ_DIR,2);
outtextxy(150,40,"How beautiful it is!");
line(130,60,480,60);
setcolor(2);
circle(269,269,137);
}
==============================================================
【程序59】
題目:畫圖,綜合例子。
1.程序分析:
2.程序源代碼:
# define PAI 3.1415926
# define B 0.809
# include "graphics.h"
#include "math.h"
main()
{
int i,j,k,x0,y0,x,y,driver,mode;
float a;
driver=CGA;mode=CGAC0;
initgraph(&driver,&mode,"");
setcolor(3);
setbkcolor(GREEN);
x0=150;y0=100;
circle(x0,y0,10);
circle(x0,y0,20);
circle(x0,y0,50);
for(i=0;i<16;i++)
{
a=(2*PAI/16)*i;
x=ceil(x0+48*cos(a));
y=ceil(y0+48*sin(a)*B);
setcolor(2); line(x0,y0,x,y);}
setcolor(3);circle(x0,y0,60);
/* Make 0 time normal size letters */
settextstyle(DEFAULT_FONT,HORIZ_DIR,0);
outtextxy(10,170,"press a key");
getch();
setfillstyle(HATCH_FILL,YELLOW);
floodfill(202,100,WHITE);
getch();
for(k=0;k<=500;k++)
{
setcolor(3);
for(i=0;i<=16;i++)
{
a=(2*PAI/16)*i+(2*PAI/180)*k;
x=ceil(x0+48*cos(a));
y=ceil(y0+48+sin(a)*B);
setcolor(2); line(x0,y0,x,y);
}
for(j=1;j<=50;j++)
{
a=(2*PAI/16)*i+(2*PAI/180)*k-1;
x=ceil(x0+48*cos(a));
y=ceil(y0+48*sin(a)*B);
line(x0,y0,x,y);
}
}
restorecrtmode();
}
==============================================================
【程序60】
題目:畫圖,綜合例子。
1.程序分析:
2.程序源代碼:
#include "graphics.h"
#define LEFT 0
#define TOP 0
#define RIGHT 639
#define BOTTOM 479
#define LINES 400
#define MAXCOLOR 15
main()
{
int driver,mode,error;
int x1,y1;
int x2,y2;
int dx1,dy1,dx2,dy2,i=1;
int count=0;
int color=0;
driver=VGA;
mode=VGAHI;
initgraph(&driver,&mode,"");
x1=x2=y1=y2=10;
dx1=dy1=2;
dx2=dy2=3;
while(!kbhit())
{
line(x1,y1,x2,y2);
x1+=dx1;y1+=dy1;
x2+=dx2;y2+dy2;
if(x1<=LEFT||x1>=RIGHT)
dx1=-dx1;
if(y1<=TOP||y1>=BOTTOM)
dy1=-dy1;
if(x2<=LEFT||x2>=RIGHT)
dx2=-dx2;
if(y2<=TOP||y2>=BOTTOM)
dy2=-dy2;
if(++count>LINES)
{
setcolor(color);
color=(color>=MAXCOLOR)?0:++color;
}
}
closegraph();
}
『肆』 C語言編寫程序。要運行實例
#include"stdio.h"
intmain(intargc,char*argv[]){
inta[11]={2,4,7,9,13,15,20,22,25,36},i,n;
printf("Pleaseenteraninteger... ");
scanf("%d",&n);
for(i=10;i>0;i--)
if(n>a[i-1])
break;
else
a[i]=a[i-1];
a[i]=n;
for(i=0;i<11;printf("%d",a[i++]));
printf(" ");
return0;
}
運行樣例:
『伍』 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。讀書很重要,但古人說「行萬里路,讀萬卷書」,還是把「行路」放在「讀書」前面。尤其對於技術書籍,如果它不能幫我解決問題、不能給我帶來非常實際的利益,那麼我是不會去讀它的。惡魔說得對,我們這個社會很快餐,我們這個行業尤其很快餐,我們也只能努力適應它。
『陸』 C語言編程實例
#define後面的FORMAT
來代表"%d\n%s\n%f\n........"
如果在程序中出現FORMAT
就會被替換成"%d\n%s\n%f\n........「
,給你舉個簡單的例子.
#define
N
10
就相當於
定義一個變數N=10
,程序中出現的N
都會給替換成10.
希望對你有所幫助
!
『柒』 C語言實例
#include
<stdio.h>
#define
N
50
//
排隊人數(可任意更改)
#define
CAL
3
//凡報3的人出列(可任意更改)
//下面是排隊編號函數:從h
開始的n個人依次編號1到n
void
stdline(int
*h,int
n)
{
int
i;
for(i=1;i<n+1;i++)
*(h+i-1)=i;
}
/*下面函數表示從指針h處開始的人數為boy個人排隊,從1報數,每報到call的人出列*/
void
outline(int
*h,int
boy,int
call)
{
int
*p,
chu,
callnum;
/*說明:
p
工作指針,表示從頭依次指向每個元素,點名
chu
計數器,記錄出列的人數
callnum
計數器,記錄點名次序
*/
chu=0;
callnum=0;//各計數器清零
p=h;
//開始時,工作指針指向數組首
printf("出列順序是:\n");
while(chu<boy)
{
if(*p!=0)
callnum++;
//每次加報數
if(callnum==call)
//如果某一個人報到出列數call...
{
printf("%5d",*p);
//列印編號,表示出列
chu++;
//出列人數加1
if(chu==boy)//如果全部出列....
{
*h=*p;
//把最後一個出列人的編號記入地址開始處
return;
//結束
}
if(chu%10==0)printf("\n");//每輸出10個換行
callnum=0;
//出列後,重新報數
*p=0;
//出列後,將其編號賦零,以示區別
}
p++;
//工作指針移向下一個人,即下一個數組元素
if(p>h+boy-1)p=h;/*如果移到最後一個元素的後面,則讓指向地址開頭繼續報數*/
}
}
void
main()
{
int
a[N];
//用數組模擬隊列,每個元素代表一個人
stdline(a,N);//編號
outline(a,N,CAL);//計算並列印出列順序
printf("\n最後留下來的是
%d
號\n",*a);/*在函數中,已經把最後一個人的編號寫入了數組首地址處,
這里輸出就可以了*/
}
『捌』 c語言程序舉例
printf();就是輸出函數
只有在引號里的內容才會被輸出
第四行輸出x y的目的是為了顯示你輸入的數據
讓你知道這兩個數要交換
t=x;x=y;y=t;
是交換x y的數據
printf("x=%d y=%d\n",x,y);
是顯示交換後的結果
『玖』 200行以上C語言程序舉例
無聊,粘著玩 657行
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdarg.h>
#include <ctype.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <Winsock2.h>
#include <ws2tcpip.h>
#include <io.h>
int raw2iframe(char *rawfile, char *ifile );
int Ts_pes(const char *src, const char *des ,unsigned short pid);
int pes_raw( char *pesfile, char *rawfile );
int es_pes(char *src, char *des);
int pes_ts(char *tsfile, char *pesfile);
static unsigned char m_buf[188 * 1024];
static unsigned char buf[188*1024];
/* 設置Dts時間戳(90khz) */
unsigned int SetDtsTimeStamp( unsigned char *buf, unsigned int time_stemp)
{
buf[0] = ((time_stemp >> 29) | 0x11 ) & 0x1f;
buf[1] = time_stemp >> 22;
buf[2] = (time_stemp >> 14) | 0x01;
buf[3] = time_stemp >> 7;
buf[4] = (time_stemp << 1) | 0x01;
return 0;
}
/* 設置Pts時間戳(90khz) */
unsigned int SetPtsTimeStamp( unsigned char *buf, unsigned int time_stemp)
{
buf[0] = ((time_stemp >> 29) | 0x31 ) & 0x3f;
buf[1] = time_stemp >> 22;
buf[2] = (time_stemp >> 14) | 0x01;
buf[3] = time_stemp >> 7;
buf[4] = (time_stemp << 1) | 0x01;
return 0;
}
/* 讀取時戳(45khz) */
unsigned int GetTimeStamp( unsigned char *buf )
{
unsigned int ts;
unsigned char *p = buf;
ts = ((*p>>1) & 0x7) << 30;
p++;
ts += (*p) << 22;
p++;
ts += ((*p)>>1) << 15;
p++;
ts += (*p) << 7;
p++;
ts += (*p) >> 1;
p++;
return ts;
}
/*主函數*/
int main(void)
{
Ts_pes("shoes.ts", "641.pes", 641); //提取PES
pes_raw("641.pes","641.raw"); //提取ES
raw2iframe( "641.raw", "641.iframe" ); //提取I幀
es_pes("641.iframe", "es.pes"); //打包成PES
pes_ts("pes.ts","es.pes"); //打包成TS
return 0;
}
/*從視頻中提取PES*/
int Ts_pes(const char *src, const char *des ,unsigned short pid)
{
unsigned char *p;
FILE *fpr, *fpw;
int size;
int ret;
unsigned short vpid;
unsigned char adaptation_field_control;
unsigned char continuity_counter;
unsigned char adaptation_field_length;
unsigned char *payload;
unsigned char payload_unit_start_indicator;
unsigned char last_counter = 0xff;
int start = 0;
fpr = fopen(src, "rb"); //打開文件
fpw = fopen(des, "wb"); //寫入文件
if(NULL == fpr || NULL == fpw)
{
return -1;
}
size = sizeof(m_buf);
while(!feof(fpr))
{
ret = fread(m_buf, 1, size, fpr ); //讀取文件
p = m_buf;
while(p < m_buf + ret)
{
vpid = (p[1] & 0x1f) << 8 | p[2];
if(pid == vpid)
{
adaptation_field_control = (p[3]>>4)&0x3; //判斷是否有可調整欄位
continuity_counter = p[3] & 0xf;
payload_unit_start_indicator = (p[1]>>6) & 0x1;
payload = NULL;
adaptation_field_length = p[4];
switch(adaptation_field_control)
{
case 0:
case 2:
break; /*0為保留,2為只有調整無負載*/
case 1:
payload = p + 4; /*無調整欄位*/
break;
case 3:
payload = p + 5 + p[4];/*凈荷*/
break;
}
if(1 == payload_unit_start_indicator)
{
start = 1;
}
if(start && payload)
{
fwrite(payload, 1, p + 188 - payload, fpw); //寫入文件
}
if( last_counter!= 0xff && ((last_counter +1 )&0xf) != continuity_counter )
{
printf( "data lost\n" );
}
last_counter = continuity_counter;
}
p = p + 188;
}
}
printf("ts_pes_END\n");
fclose(fpr); //關閉
fclose(fpw);
return 0;
}
/*從PES中提取ES*/
int pes_raw( char *pesfile, char *rawfile )
{
FILE *fpd, *fp;
unsigned char *p, *payload, *tmp;
int size, num, rdsize;
unsigned int last = 0;
__int64 total = 0, wrsize = 0;
fp = fopen( pesfile, "rb" );
fpd = fopen( rawfile, "wb" );
if( fp == NULL || fpd == NULL )
return -1;
num = 0;
size = 0;
p = m_buf;
while( true )
{
REDO:
if( m_buf + size <= p )
{
p = m_buf;
size = 0;
}
else if( m_buf < p && p < m_buf + size )
{
size -= p - m_buf;
memmove( m_buf, p, size );
p = m_buf;
}
if( !feof(fp) && size < sizeof(m_buf) )
{
rdsize = fread( m_buf+size, 1, sizeof(m_buf)-size, fp );
size += rdsize;
total += rdsize;
}
if( size <= 0 )
break;
tmp = p;
/* 尋找PES-HEADER: 0X000001E0 */
while( p[0] != 0 || p[1] != 0 || p[2] != 0x01 ||
( ( p[3] & 0xe0 ) != 0xe0 && ( p[3] & 0xe0 ) != 0xc0 ) )
{
p++;
if( m_buf + size <= p )
goto REDO;
}
if( p != tmp )
{
printf( "pes skip size=%d\n", p - tmp );
}
/* PES_packet_length */
unsigned short len = (p[4]<<8) | p[5];
if( len == 0 )
{
unsigned char *end = p + 6;
while( end[0] != 0 || end[1] != 0 || end[2] != 0x01 ||
( ( end[3] & 0xe0 ) != 0xe0 && ( end[3] & 0xc0 ) != 0xc0 ) )
{
if( m_buf + size <= end )
{
if( feof(fp) )
break;
goto REDO;
}
end++;
}
len = end - p - 6;
}
if( m_buf + size < p + 6 + len )
{
if( feof(fp) )
break;
continue;
}
p += 6;
{
unsigned char PES_scrambling_control = (*p>>4)&0x3;
unsigned char PES_priority = (*p>>3)&0x1;
unsigned char data_alignment_indicator = (*p>>2)&0x1;
unsigned char right = (*p>>1)&0x1;
unsigned char original_or_ = (*p)&0x1;
p++;
unsigned char PTS_DTS_flags = (*p>>6)&0x3;
unsigned char ESCR_flag = (*p>>5)&0x1;
unsigned char ES_rate_flag = (*p>>4)&0x1;
unsigned char DSM_trick_mode_flag = (*p>>3)&0x1;
unsigned char additional__info_flag = (*p>>2)&0x1;
unsigned char PES_CRC_flag = (*p>>1)&0x1;
unsigned char PES_extension_flag = (*p)&0x1;
p++;
unsigned char PES_header_data_length = *p;
p++;
payload = p + PES_header_data_length;
if (PTS_DTS_flags == 0x2 )
{
unsigned int pts;
pts = (*p>>1) & 0x7;
pts = pts << 30;
p++;
pts += (*p)<<22;
p++;
pts += ((*p)>>1)<<15;
p++;
pts += (*p)<<7;
p++;
pts += (*p)>>1;
p++;
p -= 5;
if( pts < last )
{
printf( "?\n" );
}
last = pts;
}
else if( PTS_DTS_flags == 0x3 )
{
unsigned int pts, dts;
pts = (*p>>1) & 0x7;
pts = pts << 30;
p++;
pts += (*p)<<22;
p++;
pts += ((*p)>>1)<<15;
p++;
pts += (*p)<<7;
p++;
pts += (*p)>>1;
p++;
dts = (*p>>1) & 0x7;
dts = dts << 30;
p++;
dts += (*p)<<22;
p++;
dts += ((*p)>>1)<<15;
p++;
dts += (*p)<<7;
p++;
dts += (*p)>>1;
p++;
p -= 10;
printf( "num=%d ra=%d size=%d pts-dts=%d\n", num, pts - last, len-3-PES_header_data_length, (int)(pts-dts) );
if( pts < last )
{
printf( "?\n" );
}
last = pts;
}
else if( PTS_DTS_flags != 0 )
{
printf( "error\n" );
}
if( fpd )
{
fwrite( p + PES_header_data_length, 1, len - 3 - PES_header_data_length, fpd );
wrsize += len - 3 - PES_header_data_length;
}
num++;
p += len - 3;
}
payload = p;
size -= p - m_buf;
memmove( m_buf, p, size );
p = m_buf;
}
fclose( fp );
fclose( fpd );
printf("pes_raw_END\n");
return 0;
}
/*提取I幀*/
int raw2iframe(char *rawfile, char *ifile )
{
unsigned char *temp_p;
unsigned char *p;
unsigned char picture_coding_type;
unsigned char buf[188*1024] = {0};
unsigned char pes_buf[32*1024] = {0};
unsigned short pid = 641;
unsigned short t_pid = 0;
int i = 0;
int j = 0;
int size = 0;
int iLen = 0;
int wiLen = 0;
int temp_queue = 0;
int temp_ifrem = 0;
void *fps = CreateFile(rawfile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); //打開讀文件
void *fpd = CreateFile(ifile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0 , NULL); //打開寫文件
temp_p = NULL;
while(1)
{
if (0 == ReadFile(fps, buf+size, sizeof(buf)-size, (unsigned long *)&iLen, NULL)) //讀取文件內容
{
CloseHandle((HANDLE)fps);
return -1;
}
if (0 == iLen)
{
break;
}
p = buf;
while( p + 6 < buf + iLen +size)
{
if (p[0] == 0x0 && p[1] == 0x0 && p[2] == 0x1) //是頭進入
{
if (p[3] == 0x0 || p[3] == 0xB3 )
{
if ( (NULL != temp_p) && ((1 == temp_queue) || (1 == temp_ifrem)))
{
WriteFile(fpd, temp_p, p-temp_p, (unsigned long *)&wiLen, NULL); //寫文件,先寫序列頭,再寫I幀
temp_queue = 0;
temp_ifrem = 0;
temp_p = NULL;
}
}
if (p[3] == 0xB3) //判斷是視頻序列,則初始化
{
temp_queue = 1;
temp_p = p;
}
picture_coding_type = (p[5]>>3) & 0x7;
if (p[3] == 0x0 && 1 == picture_coding_type) //判斷是I幀,則初始化
{
temp_ifrem = 1;
temp_p = p;
}
}
p++;
}
/*把多出來的內容寫入下個BUF*/
if(NULL != temp_p)
{
size = buf + iLen + size - temp_p;
memmove(buf, temp_p, size);
}
else
{
size = buf + iLen + size - p;
memmove(buf, p, size);
}
temp_p = NULL;
}
CloseHandle((HANDLE)fps);
CloseHandle((HANDLE)fpd);
printf("raw_iframe_END\n");
return 0;
}
/*打包成PES*/
int es_pes(char *src, char *des)
{
FILE *iframe_fp, *pes_fp;
unsigned char *p;
unsigned char *temp_p = NULL;
unsigned char buf[188*1024] = {0};
unsigned char pes_header[19];
unsigned short int pes_packet_length = 0;
unsigned int framecnt = 0;
unsigned char flag = 0;
unsigned int Pts = 0;
unsigned int Dts = 0;
int i = 0;
int size = 0;
int iLen = 0;
int wiLen = 0;
int temp_que = 0;
iframe_fp = fopen( src, "rb" );
pes_fp = fopen( des, "wb" );
if( iframe_fp == NULL || pes_fp == NULL )
{
return -1;
}
while(!feof(iframe_fp))
{
iLen = fread(buf + size, 1, sizeof(buf) - size, iframe_fp);
p = buf;
while( p + 3 < buf + iLen +size)
{
memset(pes_header, 0, sizeof(pes_header));
if (p[0] == 0x0 && p[1] == 0x0 && p[2] == 0x1 && 0xB3 == p[3])
{
if ((NULL != temp_p) && (1 == temp_que))
{
LAST_I:
pes_packet_length = p - temp_p + 13;
pes_header[4] = (pes_packet_length&0xff00) >> 8;
pes_header[5] = pes_packet_length&0x00ff;
/*PES包頭的相關數據*/
pes_header[0] = 0;
pes_header[1] = 0;
pes_header[2] = 0x01;
pes_header[3] = 0xE0;
pes_header[6] = 0x81;
pes_header[7] = 0xC0;
pes_header[8] = 0x0A;
Dts = (framecnt + 1) * 40 * 90;
Pts = framecnt * 40 * 90;
SetPtsTimeStamp(&pes_header[9], Pts); //設置時間戳 PTS
SetDtsTimeStamp(&pes_header[14], Dts); //設置時間戳 DTS
framecnt++;
if (0 == flag)
{
fwrite(pes_header, 1, sizeof(pes_header), pes_fp); //把PES包頭寫入文件
fwrite(temp_p, 1, p-temp_p, pes_fp); //把I幀寫入文件
}
else
{
fwrite(pes_header, 1, sizeof(pes_header), pes_fp); //把PES包頭寫入文件
fwrite(temp_p, 1, p-temp_p+3, pes_fp); //把I幀寫入文件
}
temp_p = NULL;
}
if (p[3] == 0xB3) //判斷是否到了下一個序列頭
{
temp_p = p;
temp_que = 1;
}
}
p++;
}
/*把多出來的內容寫入下個BUF*/
if(NULL != temp_p)
{
if (feof(iframe_fp)) //把最後一幀寫入文件
{
// flag = 1;
goto LAST_I;
}
size = buf + iLen + size - temp_p;
memmove(buf, temp_p, size);
}
else
{
size = buf + iLen + size - p;
memmove(buf, p, size);
}
temp_p = NULL;
}
printf("es_pes_END\n");
fclose(iframe_fp);
fclose(pes_fp);
return 0;
}
/*打包成TS包*/
int pes_ts(char *tsfile, char *pesfile)
{
FILE *ts_fp, *pes_fp;
int flag = 0;
int iLen = 0;
int size = 0;
int temp_pes = 0;
int pes_packet_len = 0;
unsigned char *p;
unsigned char counter = 0;
unsigned char *temp_p = NULL;
unsigned char ts_buf[188] = {0};
unsigned char start_indicator_flag = 0;
pes_fp = fopen(pesfile, "rb");
ts_fp = fopen(tsfile, "wb");
if( ts_fp == NULL || pes_fp == NULL )
{
return -1;
}
/*設ts參數*/
ts_buf[0] = 0x47;
ts_buf[1] = 0x62;
ts_buf[2] = 0x81;
while(!feof(pes_fp))
{
iLen = fread(buf+size, 1, sizeof(buf)-size, pes_fp); //讀文件
p = buf;
while( p + 6 < buf + iLen +size)
{
if (0 == p[0] && 0 == p[1] && 0x01 == p[2] && 0xE0 == p[3]) //進入
{
if (flag == 0) //第一次找到PES包
{
temp_p = p;
flag = 1;
}
else
{
pes_packet_len = p - temp_p; //pes包長度
start_indicator_flag = 0;
while (1)
{
ts_buf[3] = counter;
if (1 != start_indicator_flag)
{
ts_buf[1] = ts_buf[1] | 0x40; //payload_unit_start_indicator置為1
start_indicator_flag = 1;
}
else
{
ts_buf[1] = ts_buf[1] & 0xBF; //payload_unit_start_indicator置為0
}
if (pes_packet_len > 184) //打包成TS包(188)
{
ts_buf[3] = ts_buf[3] & 0xDF;
ts_buf[3] = ts_buf[3] | 0x10;
memcpy(&ts_buf[4], temp_p, 184);
fwrite(ts_buf, 1, 188, ts_fp); //寫文件
pes_packet_len -=184;
temp_p += 184;
}
else //不夠184B的加入調整欄位,為空
{
ts_buf[3] = ts_buf[3] | 0x30;
ts_buf[4] = 183 - pes_packet_len;
memcpy(&ts_buf[4] + 1 + ts_buf[4], temp_p, pes_packet_len);
fwrite(ts_buf, 1, 188, ts_fp); //寫文件
break;
}
counter = (counter + 1) % 0x10; //ts包計數
}
}
temp_p = p;
}
p++;
}
if (1 == flag)
{
size = buf + iLen + size - temp_p;
memmove(buf, temp_p, size);
temp_p = NULL;
flag = 0;
}
else
{
size =buf + iLen + size - p;
memmove(m_buf , p , size);
}
}
printf("pes_ts_END\n");
fclose(pes_fp);
fclose(ts_fp);
return 0;
}