学习C++使用到的工具是Visual Studio,Visual Studio 2010旗舰版下载链接:点此跳转,提取码:m145。
Visual Studio的安装包是一个以.iso为后缀的镜像文件,下载完成后其安装过程可以参考文章VS2010详细安装步骤。
打开软件后,先点击新建项目,如下图所示。
按照下图的顺序依次点击,新建一个Visual C++的空项目,名称自己设置,解决方案的名称和名称是同步变化的,给项目找一个存放的位置,点击确定即可。
项目就建立成功了,在源文件上右击,选择添加,新建项,弹出下图所示的窗口,选择C++文件,然后给文件命名,添加即可。
接下来在.cpp文件中写入如下C++代码。
#include //头文件不加.h
using namespace std; //namespace是标识符的各种可见范围,std是C++标准程序库中定义所有标识符的namespace
int main()
{
cout<<"Hello World!"<<endl; //cout是输出,endl是结束行,即换行,中间的"Hello World!"就是要输出的内容
system("pause"); //让程序执行框不退出
return 0;
}
点击运行按钮后,只要代码没有错误就会输出"Hello World!",如下图所示。
可以看到上面代码的编辑窗口中,字体有点小,来把它设置的大一些。
在菜单栏点击工具,找到选项,弹出下面的设置窗口,然后在环境下找到字体和颜色,设置字体的大小即可。
设置好以后点击确定,编辑器中的字体大小就改变了!
同样在工具的选项中,找到键盘,显示的命令这里输入注释,选择编辑.注释选定的内容,然后将光标放到按快捷键框中,在键盘上按下你想自定义的快捷键即可,然后点击分配,确定即可。
同样的方法可以设置编辑.取消注释选定的内容。
这样设置之后,以后选择编辑器中的代码,按下"Ctrl+/"就会注释选定的内容,按下"Ctrl+Shift+/"就会取消注释。
要让代码显示行号,同样在工具——选项下设置,找到文本编辑器——所有语言——常规,勾选行号即可。
C++中很多基础知识和C语言一样。
注释和C语言一样,单行注释用双斜线//,多行注释用/**/。
main函数是程序的入口函数,一个程序有且仅能有一个main函数。
变量是给一段指定的内存空间起名,方便我们操作这段内存,定义变量时要指明变量类型,变量类型的存在意义就是规定分配内存的大小。
常量用于记录程序中不可更改的数据。常量可以通过#define来定义,也可以通过const关键字来修饰变量为常量,不可对其更改。
C++中标识符的命名规则:不能使用关键字;只能包含数字、字母或者下划线,且第一个字符不能是数字;标识符的字母区分大小写。标识符的命名一般要做到见名知意。
整型包括short(2字节)、int(4字节)、long(Windows、Linux32位系统是4字节,Linux64位系统是8字节)、long long(8字节)类型。
字符型即char类型,占一个字节,给字符变量赋值时要用单引号将字符括起来,且单引号内只能有一个字符。字符型变量并不是把字符本身放到内存空间中,而是将其对应的ASCII编码放到相应的存储单元中。
实型也称浮点型,有单精度的float类型和双精度的double类型,float类型占4字节,double类型占8字节。用float定义变量时一般在变量的后面加一个字母"f",明确告诉编译器这个小数是单精度,否则编译器默认小数是双精度,然后在运行时多做一步从双精度到单精度的转换。科学计数法用e表示,e后必须为整数,e前为小数的有效位。
关键字是C++中预先保留的标识符,在定义变量或者常量的时候,变量或常量名不能为关键字。
sizeof关键字可以计算数据类型或者变量的字节数,sizeof()括号中写入数据类型或者变量都可。
转移字符一般用于表示一些不能显示出来的ASCII,常用的转移字符有:换行"\n"、水平制表符"\t"、斜杠"\“、问号”?“。换行符”\n"和"<
水平制表符"\t"主要作用是对齐,运行结果如下图所示。
字符串型在C语言中使用的是数组类型定义的,字符串用双引号括起来。
char str[] = "abcd";
C++中与C语言中定义字符串有所不同,采用string关键字直接定义字符串。
#include //C++中使用string定义的字符串要引入头文件
string str = "abcd";
上面的两种定义字符串的方式在C++中都是可以使用的。
布尔类型代表真或假的值,真是true,用1表示,假为false,用0表示。布尔类型占1个字节大小,给布尔类型变量赋非0值代表真,赋0值代表假。
C语言中的输入输出采用的是scanf和printf,其在C++中仍然可用。
数据的输出前面已经提到了,使用的关键字是cout,语法为:cout<<变量。
数据的输入使用的关键字是cin,语法为:cin>>变量。
加减乘除、取余、赋值、比较、逻辑运算符等和C语言一样,注意除数不能为0。
小数不能做取模操作,取模的两数需为整数。
前置递增或递减,变量先执行递增或递减操作,然后执行表达式运算;后置递增或递减,先执行执行表达式运算,然后变量再执行递增或递减操作。
三目运算符的语法—— 表达式1?表达式2:表达式3
如果表达式1的值为真,执行表达式2并返回表达式2的结果;如果表达式1的值为假,执行表达式3并返回表达式3的结果。
三目运算符返回的是变量,可以继续赋值。
int a = 10;
int b = 20;
(a > b ? a : b) = 30; //运行后b = 30
C/C++基本的三种程序结构:顺序结构、选择结构和循环结构。
顺序结构是指程序按照顺序执行,不发生跳转;选择结构依据条件是否满足有选择的执行相应的功能;循环结构依据条件是否满足,循环多次执行某段代码。
选择结构
如果在if语句后面加了分号,表示条件满足时没有要执行的语句,而跟在后面满足条件后才执行的语句也会被顺序执行。
if(x>10)
cout<<"x大于10"<<endl; //x>10时该语句执行
if(x>10);
cout<<"x大于10"<<endl; //这种情况下,条件满足与否该语句都执行
switch语句执行多条件分支语句,case代表的每个分支执行完以后要有break,代表结束该分支。如果分支后面没有break,该分支执行完后顺序执行下一个分支。
default语句在其他分支条件不满足时执行,相当于if-else if-else语句中的else语句。
switch语句判断的时候只能是整型或者字符型,不能是一个区间。
循环结构
do…while循环先执行一次循环,再进行条件判断。
for循环语句:for(起始表达式;条件表达式;循环体表达式),for循环语句中的表达式可以根据条件全写或全不写,起始表达式只执行一次。
对于嵌套循环,外层执行一次,内层执行一周。
用while循环实现猜数字游戏。
#include
#include
using namespace std;
int main()
{
srand((unsigned int)time(NULL)); //随机数种子,根据时间生成随机数
int num;
num = rand()%100 +1; //生成一个1-100之间的随机数
int guess_num;
while(1)
{
cout << "请输入猜测的数字:";
cin >>guess_num;
if(guess_num > num)
{
cout << "猜大了!" << endl;
}
else if(guess_num < num)
{
cout << "猜小了!" << endl;
}
else
{
cout << "猜对了!" << endl;
break;
}
}
system("pause");
return 0;
}
运行结果如下图所示。
3位的水仙花数:3位数的每个位上的数字的3次幂之和等于它本身。例如:153= 1 3 1^3 13+ 5 3 5^3 53+ 3 3 3^3 33
#include
using namespace std;
int main()
{
int num = 100;
int a = 0;
int b = 0;
int c = 0;
while(num < 1000)
{
a = num/100; //百位
b = num/10%10; //十位
c = num%10; //个位
if(num == a*a*a + b*b*b +c*c*c)
cout << num <<endl;
num++;
}
system("pause");
return 0;
}
程序的运行结果如下图所示。
C++中幂次的表示不能用,表示的是异或,可以用函数pow(a,b)来表示a的b次幂,不过a的类型要定义为double。
敲桌子游戏:将1-100数字中,7的倍数或者含有7的数字进行输出。
#include
using namespace std;
int main()
{
int i,j=0;
for(i=1;i<=100;i++)
{
if(i%7 == 0 || i%10 == 7 || i/10 ==7)
{
cout << i << " ";
j++;
}
if(j == 5)
{
cout << endl;
j = 0;
}
}
system("pause");
return 0;
}
#include
using namespace std;
int main()
{
int i,j;
for(i=1;i<=9;i++)
{
for(j=1;j<=i;j++)
cout << j <<"*"<< i << "=" << j*i << "\t";
cout << endl;
}
system("pause");
return 0;
}
跳转语句有关键字break、continue、goto。
break语句用于跳出选择结构或者循环结构,在switch语句中用于终止case并跳出switch,在嵌套语句中的内层循环中使用用于结束内层循环。
continue在循环语句中的作用是跳出本次循环中尚未执行的语句,继续执行下一次循环。在循环体中,代码执行到continue语句后,后面的语句不再执行,但是不退出循环,而是继续执行下一次的循环。
continue语句的使用,打印1-10中的偶数。
goto可以无条件的跳转语句,它会跳过某些代码而不执行。
语法为:goto 标记
如果标记的名称存在,执行到goto语句时,就会跳到标记的位置。
数组是一个集合,里面存放了相同类型的数据元素,其内存是连续的。数组元素的下标是从0开始索引的。
一维数组
一维数组定义的三种方式:
方式一:数据类型 数组名[数组长度];
方式二:数据类型 数组名[数组长度] = {value1,value2,…};
方式三:数据类型 数组名[] = {value1,value2,…};
数组名是常量,不可以进行赋值操作。
一维数组名称的用途:可以统计整个数组在内存中的长度;获取数组在内存中的首地址。
在Debug模式下运行代码,两个int型的变量之间相差12个字节,这是因为在int变量的前后各增加了4个字节,用于存储调试信息,将Debug改为Release模式就正常了。
把一个数组的元素逆置。
#include
using namespace std;
int main()
{
int a[] = {1,2,3,4,5};
int temp = 0;
int length = sizeof(a)/sizeof(a[0]);
for(int i=0;i<length/2;i++)
{
temp = a[i];
a[i] = a[length-1-i];
a[length-1-i] = temp;
}
for(int i=0;i<sizeof(a)/sizeof(a[0]);i++)
cout << a[i] << " ";
cout << endl;
system("pause");
return 0;
}
冒泡排序的实现。
#include
using namespace std;
int main()
{
int a[] = {4,2,8,0,5,7,1,3,9};
int i,j,temp = 0;
int length = sizeof(a)/sizeof(a[0]);
for(i=0;i<length-1;i++)
{
for(j=0;j<length-i-1;j++)
{
if(a[j] > a[j+1])
{
temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
for(i=0;i<length;i++)
cout << a[i] << " ";
cout << endl;
system("pause");
return 0;
}
二维数组
二维数组定义的四种方式:
方式一:数据类型 数组名[行数][列数];
方式二:数据类型 数组名[行数][列数] = {{value11,value12,…},{value21,value22,…},…};
方式三:数据类型 数组名[行数][列数] = {value1,value2,value3,value4,…};
方式四:数据类型 数组名[ ][列数] = {value1,value2,value3,value4,…};
二维数组在定义时必须指明列数,其中方式二比较直观,建议在代码中使用。
二维数组的数组名同样可以查看二维数组占用的内存空间,获取二维数组的首地址。
函数的作用就是将一段经常使用的代码封装起来,在程序中需要使用的时候直接调用即可。
函数的定义一般要包括:返回值类型、函数名、参数列表、函数体语句和return表达式。
返回值类型 函数名(参数列表)
{
函数体语句
return表达式
}
函数常见的形式有:无参数无返回值、有参数无返回值、无参数有返回值、有参数有返回值。
函数声明的作用是告诉编译器函数的名称以及调用的样式,函数的主体可以单独定义。函数声明可以多次,但是函数的定义只能有一次。
函数在调用的时候,实参会传递给形参。值传递时,函数的形参发生变化,并不会影响到实参,因为实参内存和形参内存空间不同,交换发生在形参内存空间中,所以对实参没有影响。
要想真正的交换实参的两个值,就不能进行值传递,而要传入地址,交换的时候就通过地址交换了实参的值。
函数的分文件编写:创建.h头文件,在该头文件中进行函数的声明,并且引入必要的头文件;创建.cpp源文件,在里面定义函数,并且将创建的.h头文件以双引号的形式加以引用,将函数与头文件关联起来;最后在需要调用的程序文件中引入.h头文件,调用函数即可。
可以通过指针来保存一个地址,然后间接的访问内存。
指针说到底就是一个地址,在指针变量前面加*号代表解引用,也就找到了指针地址里存放的数据。
指针变量和同类型变量之间建立关系通过取址符&实现。
空指针:指针变量指向内存中编号为0的地址空间。一般将指针变量初始化为空指针,但是空指针指向的内存是不可以访问的。0-255之间的内存空间是系统占用的,不可以访问。
野指针:指针变量指向非法的内存空间。未经申请就访问的地址空间,比如给指针直接指向一个0x1100的地址,然后访问就会出错。
const修饰指针——常量指针,归根结底是指针,指针的指向可以修改,但是指针指向的值不可以修改。最典型的就是指针指向字符串常量,指针可以指向不同地址的字符串常量,但是字符串的值不能被修改。
int a=10;
int b=20;
const int *p;
p = &a;
p = &b; //可以
*p = 30; //不可以
const修饰常量——指针常量,归根结底是一个地址常量,因此指针的指向不可以修改,但是指针指向的值可以修改。比较典型的是某些硬件,其地址是固定的,不能被修改,但是其存放的值是可以修改的。
int a=10;
int b=20;
int * const p = &a;
*p = 30; //可以
p = &b; //不可以
简单总结一下常量指针和指针常量的区别,const修饰啥,啥就不能修改。
const int *p; //const修饰*p,*p不能改变
int * const p; //const修饰p,p不能改变
const既修饰指针,又修饰常量,指针的指向和指针指向的值都不可以被修改。某些硬件地址里面的值被写死了,这种情况下就啥也不能修改了。
在32位操作系统下,任何类型的指针变量的大小都是4个字节,因为其存放的是地址。在64位操作系统下,指针变量的大小都是8个字节。
指针、数组、函数的综合应用例子,写一个函数对一个数组进行冒泡排序。
#include
using namespace std;
void BubbleSort(int *a,int len)
{
int i,j,temp;
for(i=0;i<len-1;i++)
{
for(j=0;j<len-i-1;j++)
{
if(a[j]>a[j+1])
{
temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
}
int main()
{
int a[] = {4,2,8,6,0,5,7,1,3,9};
int len = sizeof(a)/sizeof(a[0]);
BubbleSort(a,len);
for(int i=0;i<len;i++)
cout << a[i] << " ";
cout << endl;
system("pause");
return 0;
}
结构体属于用户自定义的数据类型,允许用户存储不同的数据类型,结构体就是不同数据类型的集合。
语法:struct 结构体名 {结构体成员列表};
定义结构体的时关键字struct不可省略;创建结构体变量的时候关键字struct可以省略;结构体变量利用操作符"."访问结构体成员。
结构体定义变量的三种方式。
#include
#include
using namespace std;
struct student
{
string name;
int age;
int score;
}s3; //方式三
int main()
{
//方式一
struct student s1; //可以省略struct关键字,但是定义结构体的时候不可以省略
s1.name = "aaa";
s1.age = 20;
s1.score = 90;
//方式二
student s2 = {"bbb",21,96}; //可以省略struct关键字
//方式三
s3.name = "ccc";
s3.age = 22;
s3.score = 98;
cout <<"姓名:"<<s1.name<<" 年龄:"<<s1.age<<" 分数:"<<s1.score<<endl;
cout <<"姓名:"<<s2.name<<" 年龄:"<<s2.age<<" 分数:"<<s2.score<<endl;
cout <<"姓名:"<<s3.name<<" 年龄:"<<s3.age<<" 分数:"<<s3.score<<endl;
system("pause");
return 0;
}
程序运行结果如下图所示。
结构体数组的语法:struct 结构体名 数组名[元素个数] = {{},{},…};
将上面的例子表示成结构体数组的形式如下。
#include
#include
using namespace std;
struct student
{
string name;
int age;
int score;
};
int main()
{
struct student arr[3]= //可以省略struct关键字
{
{"aaa",20,90},
{"bbb",21,96},
{"ccc",22,98}
};
for(int i=0;i<3;i++)
{
cout <<"姓名:"<<arr[i].name<<" 年龄:"<<arr[i].age<<" 分数:"<<arr[i].score<<endl;
}
system("pause");
return 0;
}
结构体指针的作用是通过指针访问结构体中的成员,指针访问结构体成员需要通过"->"符号实现。
#include
#include
using namespace std;
struct student
{
string name;
int age;
int score;
};
int main()
{
struct student arr[3]=
{
{"aaa",20,90},
{"bbb",21,96},
{"ccc",22,98}
};
struct student *p;
p = arr;
for(int i=0;i<3;i++)
{
cout <<"姓名:"<<p->name<<" 年龄:"<<p->age<<" 分数:"<<p->score<<endl;
p++;
}
system("pause");
return 0;
}
结构体嵌套结构体:结构体中成员变量可以是另外一个结构体。
#include
#include
using namespace std;
struct student
{
string name;
int age;
int score;
};
struct teacher
{
string name;
int age;
struct student stu;
};
int main()
{
struct teacher t1;
t1.name = "taaa";
t1.age = 50;
t1.stu.name = "aaa";
t1.stu.age = 20;
t1.stu.score = 90;
struct teacher t2 = {"tbbb",53,{"bbb",22,96}};
cout <<"老师姓名:"<<t1.name<<" 年龄:"<<t1.age<<
" 学生姓名:"<<t1.stu.name<<" 学生年龄:"<<t1.stu.age<<" 学生成绩:"<<t1.stu.score<<endl;
cout <<"老师姓名:"<<t2.name<<" 年龄:"<<t2.age<<
" 学生姓名:"<<t2.stu.name<<" 学生年龄:"<<t2.stu.age<<" 学生成绩:"<<t2.stu.score<<endl;
system("pause");
return 0;
}
#include
#include
using namespace std;
struct student
{
string name;
int age;
int score;
};
void print_info1(struct student stu)
{
stu.score = 91;
cout <<"1."<<"姓名:"<<stu.name<<" 年龄:"<<stu.age<<" 分数:"<<stu.score<<endl;
}
void print_info2(struct student *stu)
{
stu->score = 96;
cout <<"3."<<"姓名:"<<stu->name<<" 年龄:"<<stu->age<<" 分数:"<<stu->score<<endl;
}
int main()
{
struct student stu={"aaa",20,90};
print_info1(stu); //值传递
cout <<"2."<<"姓名:"<<stu.name<<" 年龄:"<<stu.age<<" 分数:"<<stu.score<<endl;
print_info2(&stu); //地址传递
cout <<"4."<<"姓名:"<<stu.name<<" 年龄:"<<stu.age<<" 分数:"<<stu.score<<endl;
system("pause");
return 0;
}
上述程序的运行结果如下图所示。
函数值传递不改变实参的值,函数中地址传递会改变实参的值。如果是值传递,形参中会拷贝一份实参中的值,这在数据量很大的时候不太可行,因此进行地址传递,但是要确保某些数据不被修改,需要加关键字const。
上面的例子中就在函数中对结构体成员的值进行了修改,为了让函数只读结构体而不改变结构体成员的值,在形参前面加const。
void print_info2(const struct student *stu)
{
cout <<"3."<<"姓名:"<<stu->name<<" 年龄:"<<stu->age<<" 分数:"<<stu->score<<endl;
}
这样修改函数后,如果尝试修改结构体成员的值,会直接报错。
结构体的综合应用案例一:
设计学生和老师的结构体,老师的结构体中包含老师的姓名和一个存放5名学生的数组成员,学生的结构体中有姓名和成绩,创建数组存放3名老师,通过函数来给每个老师及所带的学生赋值,并打印老师数据以及老师所带学生的数据。
#include
#include
using namespace std;
struct student
{
string sname;
int score;
};
struct teacher
{
string tname;
struct student stu[5];
};
void get_value(struct teacher *t,int len)
{
string nameseed = "ABCDE";
for(int i=0;i<len;i++)
{
t[i].tname = "Teacher_";
t[i].tname += nameseed[i]; //拼接字符串
cout << t[i].tname << "老师带的学生:" << endl;
for(int j=0;j<5;j++)
{
t[i].stu[j].sname = nameseed[i];
t[i].stu[j].sname += "_Student_";
t[i].stu[j].sname += nameseed[j];
cout << "输入第"<<j+1<<"个学生的成绩:";
cin >> t[i].stu[j].score;
}
}
}
int main()
{
struct teacher t[3];
int len = sizeof(t)/sizeof(t[0]);
get_value(t,len);
for(int i=0;i<len;i++)
{
cout <<t[i].tname<<"老师带的学生及成绩:"<<endl;
cout <<"学生姓名 "<<" 成绩"<<endl;
for(int j=0;j<5;j++)
cout <<t[i].stu[j].sname<<" "<<t[i].stu[j].score<<endl;
}
cout <<endl;
system("pause");
return 0;
}
上面程序的运行结果如下图所示。
结构体的综合应用案例二:
设计一个英雄结构体,结构体包括成员的姓名、年龄、性别,创建结构体数组,数组中存放5名英雄,通过冒泡排序的算法,将数组中存放的英雄按照年龄进行升序排列,并打印排序后的结果。
#include
#include
using namespace std;
struct hero
{
string name;
int age;
string sex;
};
void BubbleSort(struct hero *h,int len)
{
struct hero temp;
for(int i=0;i<len-1;i++)
{
for(int j=0;j<len-i-1;j++)
{
if(h[j].age > h[j+1].age)
{
temp = h[j];
h[j] = h[j+1];
h[j+1] = temp;
}
}
}
}
void print_info(struct hero *h,int len)
{
cout<< "姓名 "<<"年龄 "<<"性别"<<endl;
for(int i=0;i<len;i++)
{
cout<<h[i].name<<" "<<h[i].age<<" "<<h[i].sex<<endl;
}
}
int main()
{
struct hero h[5]=
{
{"刘备",23,"男"},
{"关羽",22,"男"},
{"张飞",20,"男"},
{"赵云",21,"男"},
{"貂蝉",19,"女"}
};
int len = sizeof(h)/sizeof(h[0]);
cout<< "排序前:"<<endl;
print_info(h,len);
BubbleSort(h,len);
cout<< "排序后:"<<endl;
print_info(h,len);
system("pause");
return 0;
}
本文参考视频:
黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难