首页 > 代码库 > 第一章 C/C++语言概述 【代码手输一遍】

第一章 C/C++语言概述 【代码手输一遍】

前情提要:如果不涉及面向对象的部分,那么C++语言和C语言的语法90%以上是一样的,只不过略有扩充,用起来更为方便而已。

查看gcc版本:

E:\Program Files\MinGW\bin>gcc -v
Reading specs from ./../lib/gcc/mingw32/3.4.5/specs
Configured with: ../gcc-3.4.5-20060117-3/configure --with-gcc --with-gnu-ld --wi
th-gnu-as --host=mingw32 --target=mingw32 --prefix=/mingw --enable-threads --dis
able-nls --enable-languages=c,c++,f77,ada,objc,java --disable-win32-registry --d
isable-shared --enable-sjlj-exceptions --enable-libgcj --disable-java-awt --with
out-x --enable-java-gc=boehm --disable-libgcj-debug --enable-interpreter --enabl
e-hash-synchronization --enable-libstdcxx-debug
Thread model: win32
gcc version 3.4.5 (mingw vista special r3)

所有程序都在gcc 3.4.5下编译运行。

//1.1程序的基本框架
//gcc warning:return type of “main” is not “int”
#include "stdio.h"
int main(){
	printf("hello world\n");
	return 0;
}

//1.3 C/C++语言的数据类型
//说明数据类型之间的自动转换
int main(){
	int n1=1378;
	short n2;
	char c=‘a‘;
	double d1=7.809;
	double d2;
	n2=c;//n2 becaming 97
	printf("c=%c,n2=%d\n",c,n2);
	
	c=n1;
	//char型变量只有一个字节,int型为两个字节
	//1387十六进制为562,char型的c只得到了62,变成十进制即为98
	//故输出c=b
	printf("c=%c,n1=%d\n",c,n1);
	n1=d1;	//n1变为7
	printf("n1=%d\n",n1);
	d2 = n1;
	printf("d2=%f\n",d2);
	return 0;
}

//1.4常量
#define MAPLENGTH 100
#define MAPWIDTH 80
int main(){
	int mapSize;
	mapSize=MAPLENGTH*MAPWIDTH;
	printf("the map size is %d\n",mapSize);
}

//1.5 运算符和表达式
//算术运算符之除法运算符
int main(){
	int a=10;
	int b=3;
	double d=a/b;
	printf("%f\n",d);
	d=5/2;
	printf("%f\n",d);
	d=5/2.0;
	printf("%f\n",d);
	d=(double)a/b;
    printf("%f\n",d);
	return 0;

}

//1.5 运算符和表达式
//算术运算符之自增自减运算符
int main(){
	int n1,n2=5;
	n2++;
	++n2;
	n1=n2++;
	n1=++n2;
	printf("n1=%d,n2=%d\n",n1,n2);
}

//1.5 运算符和表达式
//位运算符之左移运算符
int main(){
	int n1=15;
	short n2=15;
	unsigned short n3=15;
	unsigned char c=15;
	n1<<=15;
	n2<<=15;
	n3<<=15;
	c<<=6;
	printf("n1=%x,n2=%d,n3=%d,c=%x,c<<4=%d",n1,n2,n3,c,c<<4);
	return 0;
}

//1.5 运算符和表达式
//位运算符之右移运算符
#include "stdio.h"
int main(){
	int n1=15;
	short n2=-15;
	unsigned short n3=0xffe0;
	unsigned char c=15;
	n1=n1>>2;
	n2>>=3;
	n3>>=4;
	c>>=3;
	printf("n1=%x,n2=%d,n3=%x,c=%x",n1,n2,n3,c);
	return 0;
}

//1.9 函数
#include "stdio.h"
int multiple(int x,int y); //函数声明
int main(){
	int a=0,b=0;
	scanf("%d%d",&a,&b);
	printf("%d\n",multiple(a,b));
	return 0;
}
int multiple(int x,int y)
	return x*y;
}

//1.12 数组
//我擦,输入100个参数,有没有搞错啊
#include "stdio.h"
#define MAX_NUM 100
int main(){
	int i,j;
	int an[MAX_NUM];
	//下面输入100个整数
	for(i=0;i<MAX_NUM;i++){
		scanf("%d",&an[i]);
	}
	//排序
	for(i=0;i<MAX_NUM-1;i++){
		int nTmpMin=i;
		for(j=i;j<MAX_NUM;j++){
			if(an[j]<an[nTmpMin])
				nTmpMin=j;
		}
		//置换
		int temp=an[i];
		an[i]=an[nTmpMin];
		an[nTmpMin]=temp;
	}
	//输出排序之后的元素
	for(i=0;i<MAX_NUM;i++){
		printf("%d\n",an[i]);
	}
	return 0;
}


//--------------------------------------
//1.13 字符串
//字符串常量&字符串变量,字符串变量包含\0结尾
#include "stdio.h"
#include "string.h"
int main(){
	char szTitle[]="Prison Break";
	char szHero[100]="Michael Scofield";
	char szPrisonName[100];
	char szResponse[100];
	printf("what is the name of the Prison Break in %s\n",szTitle);
	//用scanf输入字符串不能含有空格,可用gets取代之
	scanf("%s",szPrisonName);
	//int strcmp(const char *s1,const char *s2) 比较字符串s1与s2的大小,并返回s1-s2
	if(strcmp(szPrisonName,"Fox-River")==0){
		printf("Yeah! Do you love %s?\n",szHero);
	}
	else{
		strcpy(szResponse,"it seems you have‘t watched it!\n");
		printf(szResponse);
	}
	szTitle[0]=‘t‘;
	szTitle[3]=0;//等效于szTitle[3]=‘\0‘
	printf(szTitle);
	return 0;


}

指针一般规律:若有定义T *p;不论T是什么类型,sizeof(T *)的值都是4.因为指针表示的是地址,而当前流行的cpu内存寻址范围一般都是4GB即2^32,所以一个地址正好用32位,即4个字节表示。

tip1,不同类型的指针,若不经过强制类型转换,是不能互相赋值的,

eg. pn=(int *)p;

tip2,两个类型为T的指针相减的意义:p1-p2=(地址p1-地址p2)/sizeof(T);

tip3,指针和整数相加的定义:n+p意为,地址p+nXsizeof(T);

//1.14 指针
#include "stdio.h"
int main(){
	int *pn1,*pn2;
	char *pc1,*pc2;
	int n=4;
	pn1=(int *)100;
	pn2=(int *)200;
	printf("%d\n",pn2-pn1);//输出25,因为(200-100)/sizeof(int)=100/4=25
	pc1=(char *)pn1;//pc1地址为100
	pc2=(char *)pn2;
	printf("%d\n",pc1-pc2);//(100-200)/sizeof(char)=-100
	printf("%d\n",(pn2+n)-pn1);
	int *pn3=pn2+n;
	printf("%d\n",pn3-pn1);
	printf("%d",(pc2-10)-pc1);
	return 0;
}


//1.14 指针
//指针和数组
#include "stdio.h"
int main(){
	int i,an[200];
	int *p;
	p=an;
	*p=10;
	*(p+1)=20;
	p[0]=30;
	p[4]=40;
	for(i=0;i<10;i++)//循环赋值
		*(p+i)=i;
	p++;
	printf("%d\n",p[0]);
	p=an+6;
	printf("%d\n",*p);
	return 0;
}


//1.14 指针
//bubble sort
#include "stdio.h"
void BubbleSort(int *pa,int nNum){
	int i,j;//在for中定义i,j在gcc下会报错:loop initial declaration used outside c99 mode
	for(i=nNum-1;i>0;i--){
		for(j=0;j<i;j++){
			if(pa[j]>pa[i]){
				int temp=pa[j];
				pa[j]=pa[i];
				pa[i]=temp;
			}
		}
	}
}
#define NUM 5
int main(){
	int an[NUM]={5,4,8,2,1};
	BubbleSort(an,NUM);
	int i;
	for(i=0;i<NUM;i++){
		printf("%d\n",an[i]);

	}
	return 0;
}


//1.14 指针
//字符串和指针
#include "stdio.h"
#include "string.h"
int main(){
	char *p="Tom\n";
	char szName[20];
	char *pName=szName;
	scanf("%s",pName);
	printf(p);
	printf("Name is %s",pName);
	return 0;
}

tip,void指针:主要用于内存复制,将内存中某一块内容复制到另一块去,标准库函数void *memcpy(void *dest,const void *src,unsigned int n);将地址src开始的n字节内容复制到地址dest,返回值是dest

eg. memcpy(a2,a1,10*sizeof(int));

//1.14 指针
//1.14.8 函数指针定义形式:类型名(* 指针变量名)(参数类型1,参数类型2,&middot;&middot;&middot;);
#include "stdio.h"
void PrintMin(int a,int b){
	if(a<b)
		printf("%d",a);
	else 
		printf("%d",b);
}
int main(){
	void (*pf)(int ,int );//定义函数指针pf
	int x=4,y=5;
	pf=PrintMin;
	pf(x,y);
	return 0;
}


//1.14 指针
/* 1.14.8 C/C++中有一个快速排序的标准库函数qsort,使用该函数可对任何类型一维数组排序
void qsort(void *base,int nele,unsigned int width,
	int (*pfCompare)(const void *,const void *));
qsort函数用法规定,“比较函数”原型应该是:int 函数名(const void *elem1,const void *elem2);
自主设置比较规则,*elem1要排在*elem2前面,则函数返回值必须为负整数;
									无所谓,则返回值为0;
									后面,则返回值必须为正整数;
*/
#include "stdio.h"
#include "stdlib.h"
int MyCompare(const void *elem1,const void *elem2){
	unsigned int *p1,*p2;
	p1=(unsigned int *) elem1;
	p2=(unsigned int *) elem2;
	return (*p1%10)-(*p2%10);//按个位数字大小来排序
}
#define NUM 5
int main(){
	unsigned int an[NUM]={8,123,11,10,4};
	qsort(an,NUM,sizeof(unsigned int),MyCompare);
	int i;
	for(i=0;i<NUM;i++){
		printf("%d, ",an[i]);
	}
	return 0;
}

指针tip:1.14.9 指针和动态内存分配,1.14.10 误用无效指针

//1.15 结构体
/* tip 结构体定义一定是以分号结束的,
struct Student {
	...};
Student stu1,stu2;
等价于:
struct Student {
...} stu1,stu2; */
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#define NUM 4
struct Student
{
	unsigned ID;
	char szName[20];
	float fGPA;
};
Student MyClass[NUM]={
	{1234,"Tom",3.78},
	{1238,"Jack",3.25},
	{1232,"Mary",4.00},
	{1234,"Jone",2.78}
};
int CompareID(const void *elem1,const void *elem2){
	Student *p1=(Student *) elem1;
	Student *p2=(Student *) elem2;
	return ps1.ID-ps2.ID;
}
int CompareName(const void *elem1,const void *elem2){
	Student *p1=(Student *) elem1;
	Student *p2=(Student *) elem2;
	return strcmp(ps1.szName,ps2.szName);
}
int main(){
	int i;
	qsort(MyClass,NUM,sizeof(Student),CompareID);
	for(i=0;i<NUM;i++){
		printf("%s",MyClass[i].szName);
		printf("\n");
	}
	qsort(MyClass,NUM,sizeof(Student),CompareName);
	for(i=0;i<NUM;i++){
		printf("%s",MyClass[i].szName);
		printf("\n");
	}
	return 0;
}

P62的代码1.15结构体真是好奇怪,看不出为什么错。。。

Mark:小工具,在线程序编译器http://codepad.org调试结果如下:

Line 19: error: expected ‘=‘, ‘,‘, ‘;‘, ‘asm‘ or ‘__attribute__‘ before ‘MyClass‘
以下略

本地调错信息如下

---------- gcc编译并生成 ----------

sheldon.c:19: error: syntax error before "MyClass"

以下略

问题:明明定义了Student结构体,怎么又说“Student”未声明呢???

Answer:感谢@斯雷波 的关注和解答,以上代码修改两处后可在C++编译环境调试通过。

26、27行修改*p1 *p2为*ps1 *ps2【打错了】,28行修改点号为箭头;

31到33行做类似修改;

若不修改点号为箭头,codepad报错如下

In function ‘int CompareName(const void*, const void*)‘:
Line 33: error: request for member ‘szName‘ in ‘ps1‘, which is of non-class type ‘Student*‘
compilation terminated due to -Wfatal-errors.

在codepad设置为C++语言或者使用VC++6.0都可以调试通过,本地gcc始终对19行报错 error: syntax error before "MyClass";

Tip:28行的修改参考C中指针中点与箭头区别

在c++中I如果是对象,就可以通过"."来调用I中的成员变量。
如果I是指针的话,就不能通过"."来调用,而只能使用"->"来调用。
C语言中不存在对象的概念。
这种情况的出现是因为使用了结构,例如
struct CandyBar{
float weight;
int calorie;
};
在程序中
CandyBar snack={
2.3,
350
};
我们就可以用snack.weight来取得结构中的值。
这时是不能使用"->"来调用的,"->"符号指针指针来说的。
如下情况可以使用"->"
CandyBar* bird;
bird->weight=2.33;
此时bird为一个CandyBar结构的地址指针。所以可以使用"->",而此时就不能使用
"."来操作。因为"." "相当于"对象的成员调用。