注释:
ctrl+shift+c 注释
ctrl+shift+x 取消注释
位:"位(bit)"是电子计算机中最小的数据单位。每一位的状态只能是0或1。
字节:8个二进制位构成1个"字节(Byte)",它是存储空间的基本计量单位。1个字节可以储存1个英文字母或者半个汉字,换句话说,1个汉字占据2个字节的存储空间。
字:"字"由若干个字节构成,字的位数叫做字长,不同档次的机器有不同的字长。例如一台8位机,它的1个字就等于1个字节,字长为8位。如果是一台16位机,那么,它的1个字就由2个字节构成,字长为16位。字是计算机进行数据处理和运算的单位。
KB:在一般的计量单位中,通常K表示1000。例如:1公里= 1000米,经常被写为1km;1公斤=1000克,写为1kg。同样K在二进制中也有类似的含义。只是这时K表示1024,也就是2的10次方。1KB表示1K个Byte,也就是1024个字节。
MB: 计量单位中的M(兆)是10的6次方,见到M自然想起要在该数值的后边续上六个0,即扩大一百万倍。在二进制中,MB也表示到了百万级的数量级,但1MB 不正好等于1000000字节,而是1048576字节,即 1MB = 2E+20 Bytes =1048576Bytes。
MB就是通常说的兆
KB 1KB=1024B
MB 1MB=1024KB
GB 1GB=1024MB
TB 1TB=1024GB
Const
1.为什么引入const?
为了取代预编译指令,消除它的缺点,同时继承它的优点。
(预编译指令:常见有#include指令,#define指令)
2.例子:
Const int a; a是一个常整型数
Int const a; 等价于上面
Const int *a; 指针a指向的整型数不可修改,但指针可以
Int *const a; 指向整型数的常指针,也就是说指针不能被修改
(const在谁的后面谁就不可修改,若const在最前面则将其后移一位即可)
3.const关键字的作用:
(1)欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了;
(2)对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const;
(3)在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;
(4)对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量;
(5)对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为“左值”。例如:
const classA operator*(const classA& a1,const classA& a2);
operator*的返回结果必须是一个const对象。如果不是,这样的变态代码也不会编译出错:
classA a, b, c;
(a * b) = c; // 对a*b的结果赋值
操作(a * b) = c显然不符合编程者的初衷,也没有任何意义。
为什么要在函数后面加const?
任何不会修改数据成员的函数都应该声明为const类型。如果在编写const成员函数时,不慎修改了数据成员,或者调用了其他非const成员函数,编译器将指出错误,这可以提高程序的健壮性。
为什么函数参数要加const?
不希望改变形参
函数参数传递时尽量使用const引用传参
C++存储类(定义C++ 程序中变量/函数的范围(可见性)和生命周期。这些说明符放置在它们所修饰的类型之前)
auto: 所有局部变量(只能用在函数里)默认的存储类 auto int mouth
register: 这意味着变量的最大尺寸等于寄存器的大小),且不能对它应用一元的 '&' 运算符(因为它没有内存位置)。 Register int miles
static: 指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。static 修饰符也可以应用于全局变量。当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内。
static作用:1.在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
2.在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所有函数访问,但不能被模块外函数访问,他是一个本地的全局变量
3.在模块内,一个被声明为静态的函数被限制在声明他的模块的本地范围内使用
extern: extern存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当您使用 'extern' 时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。
当您有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用 extern 来得到已定义的变量或函数的引用。可以这么理解,extern 是用来在另一个文件中声明一个全局变量或函数。
extern 修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候
逻辑运算符:
&& || !
位运算符:
A = 0011 1100
B = 0000 1101
-----------------
A&B = 0000 1100
A|B = 0011 1101
A^B = 0011 0001
~A = 1100 0011
& | ^ ~ << >>
C++成员运算符
访问结构体的成员时使用点运算符,而通过指针访问结构的成员时,则使用箭头运算符。
struct Employee {
char first_name[16];
int age;
} emp;
下面的代码把值 "zara" 赋给对象 emp 的 first_name 成员:
strcpy(emp.first_name, "zara");
如果 p_emp 是一个指针,指向类型为Employee 的对象,则要把值 "zara" 赋给对象 emp 的 first_name 成员,需要编写如下代码:
strcpy(p_emp->first_name, "zara");
for循环
for ( init; condition; increment )
{
statement(s);
}
1. init()被执行,初始化各值
2. 判断condition,如果为真,则执行循环体,如果为假,跳出循环
3. 执行完循环体后,控制流会跳回increment语句,进行循环更新控制变量
4. 条件再次被判断
Cin:
>>是会过滤掉不可见字符的(如空格,回车,TAB等)
Cin.get()
1.可以用来接收字符
#include <iostream>
Using namespace std;
Int main()
{
char ch;
Ch=cin.get(); //或者cin.get(ch)
Cout<<ch<<endl;
}
2.Cin.get(字符数组名,接收字符数目)用来接收一行字符,可以接受空格
#include <iostream>
using namespace std;
int main ()
{
char a[20];
cin.get(a,20);
cout<<a<<endl;
}
输入:jkl jkl jkl
输出:jkl jkl jkl
输入:abcdeabcdebcdeabcdeabcde (输入25个字符)
输出:abcdeabcdeabcdeabcd (输出19个字符+1个‘\0’)
Cin.getline() 接收一个字符串,可以接受空格并且输出。属于istream流
#include <iostream>
using namespace std;
int main ()
{
char m[20];
cin.getline(m,5);
cout<<m<<endl;
}
输入:jkljkljkl
输出:jklj
接收5个字符到m中,其中最后一个为‘\0’,所以只看到4个字符输出
延伸:
//Cin.getline()实际上有三个参数,cin.getline(接收字符串名字,接收个数,结束字符)
//当第三个参数省略的时候,系统默认为‘\0’
//若把例子中的cin.getline(m,5)改成cin.getline(m,5,‘a’),当输入jkljkljkl时输出jklj,输入jkaljkljkl时,输出jk
getline 可以接收空格并且输出,需要包含“#include <string>”属于string流
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str;
getline(cin,str);
cout<<str<<endl;
}
输入:jkl jkl jkl
输出: jkl jkl jkl
gets()函数从缓冲区中读取字符串,直到出现换行符或读到文件尾为止
#include <iostream>
#include <stdio.h>
using namespace std;
int main ()
{
char str[10];
cout<<"input astring.\n"<<endl;
gets(str);
cout<<"thestring you input is :"<<str<<endl;
}
若输入123 45 则输出123 45
若输入12345678901234567890(长度大于10)则系统会崩溃
C++随机数
在许多情况下,需要生成随机数,关于随机生成器,有两个相关的函数,一个是rand(),该函数只返回一个伪随机数,生成随机数之前必须先调用srand()函数。使用time()函数来获取系统时间的秒数,调用rand()函数来生成随机数。
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
int main ()
{
int i,j;
srand((unsigned)time(NULL));
for (i=0; i<10; i++)
{
j=rand();
cout<<"随机数:"<<j<<endl;
}
}
C++字符串:c风格字符串,c++引入的string类型
C风格字符串:使用null字符‘\0’终止的一维字符数组
Char greeting[6]={‘h’,‘e’,‘l’,‘l’,‘o’,‘\0’}
óChar greeting[6]=“hello”;
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
int main ()
{
chargreeting[6]={'H','e','l','l','o','\0'};
cout<<"greeting message:"<<greeting<<endl;
}
直接操作字符串的函数:
strcpy(s1,s2)复制字符串s2到s1
strcat(s1,s2)连接字符串s2到s1末尾
strlen(s1)返回s1的长度
#include <iostream>
#include <cstring>
using namespace std;
int main ()
{
charstr1[10]="hello";
charstr2[10]="world";
char str3[10];
int len;
strcpy(str3,str1);
cout<<str3<<endl;
strcat(str1,str2);
cout<<str1<<endl;
len=strlen(str1);
cout<<len<<endl;
}
string类
#include <iostream>
#include <ctime>
#include <stdio.h>
#include <cstdlib>
#include <cstring>
using namespace std;
int main ()
{
stringstr1="hello";
stringstr2="world";
string str3;
int len;
str3=str1;
cout<<str3<<endl;
str3=str1+str2;
cout<<str3<<endl;
len=str3.size();
cout<<len<<endl;
}
c++函数
1. 参数传值调用:向函数传递参数的传值调用方法,把参数的实际值复制给函数的形式参数。在这种情况下,修改函数内的形式参数不会影响实际参数。
2. 指针调用:向函数传递参数的指针调用方法,把参数的地址复制给形式参数。在函数内,该地址用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。
#include <iostream>
using namespace std;
void swap(int *x,int *y)
{
int temp;
temp=*x; //保存地址x的值
*x=*y; //把y赋值给x
*y=temp; //把x赋值给y
return;
}
int main ()
{
int a=100,b=200;
cout<<a<<""<<b<<endl;
/*
调用函数来交换值
&a表示指向a的指针,即a的地址
&b表示指向b的指针,即b的地址
*/
swap(&a,&b);
cout<<a<<""<<b<<endl;
}
3.引用调用:向函数传递参数的引用调用方法,把参数的地址复制给形式参数。在函数内,该引用用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。
#include <iostream>
using namespace std;
void swap(int &x,int &y)
{
int temp;
temp=x;
x=y;
y=temp;
return;
}
int main ()
{
int a=100,b=200;
cout<<a<<" "<<b<<endl;
swap(a,b);
cout<<a<<" "<<b<<endl;
}
指针(是一个变量,其值是另一个变量的地址,即内存位置的直接地址)
问题:
char a='A';
char *p=&a;
cout<<p<<endl;
输出结果为什么会有汉字、乱码,而不是字符的地址?
解:这里有一个特殊的处理,虽然这里的p的内容确实是一个地址,但是cout操作字符指针的话,它遇到地址,就会直接去寻找这个地址所指向的内容,并把它空间里的机器数按照字符的规则转化成字符输出,直到遇到‘\0’这个操作符才停止。所以我们直接输出p的时候,它会先输出‘A’,然后再继续读取后面的内存空间直到遇到‘\0’,显示结果是“A+乱码”。如果要输出指针指向的地址,可以这样输出:cout<<(void *)ptr<<endl;
比如我们第一个字符串数组char a[]=“mantou”,a[]在内存中占7个字节,而不是6个,因为在mantou字符串后面还隐藏有一个“\0”,这时我们用char*p=a;(这里不用&a是因为,a[]是一个数组,数组名a本身就是一个指针常量)输出操作cout<<p<<endl可以直接输出整个mantou字符串,如果我们cout<<*p<<endl,结果显示的是m,因为p是指向数组的首元素的地址。
*(ptr++)!=*(ptr+1)
#include<stdio.h>;
void main()
{
char *ptr = "csdn";
printf( "%c\n",*(ptr++) );
}
输出c,ptr++是在语句执行完后才执行++操作的,有没有括号都一样。
但是*(ptr+1)确实由于括号的原因改变了优先级,应该输出s
内存溢出:申请了10个字节的空间,却在这个空间写入了11或以上字节的数据
内存泄露:用new或malloc申请了一块内存,但是没有通过free或delete将内存释放,导致这块内存一直处于占用状态。重启计算机可以解决
1. NULL指针:可以避免使用空指针
在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个NULL值是一个良好的编程习惯。赋为NULL值的指针称为空指针。
NULL指针是一个定义在标准库中的值为零的常量。
#include <iostream>
using namespace std;
int main ()
{
int *ptr=NULL;
cout<<"ptr的值为:"<<ptr;
}
输出:ptr的值为:0
在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。然而,内存地址 0 有特别重要的意义,它表明该指针不指向一个可访问的内存位置。但按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。
如需检查一个空指针,您可以使用 if 语句,如下所示:
if(ptr) /* 如果 p 非空,则完成 */
if(!ptr) /* 如果 p 为空,则完成 */
1.指向数组的指针(数组名是指向数组中第一个元素的常量指针,即第一个。)
#include <iostream>
using namespace std;
int main()
{
double balance[5]={100,20,2,3,1};
double *p;
p=balance;
for (int i=0; i<5;i++)
{
cout<<i<<" "<<*(p+i)<<endl;
}
for (int i=0; i<5;i++)
{
cout<<i<<" "<<*(balance+i)<<endl;
}
}
2.传递数组给函数
方式一:
形式参数是一个指针:
void myfunction(int *param)
{
}
方式二:
void myfunction(int param[])
{
}
#include <iostream>
using namespace std;
double getaverage(int arr[],int size)
{
int i,sum=0;
double avg;
for (i=0; i<size;i++)
{
sum+=arr[i];
}
avg=double(sum)/size;
return avg;
}
int main()
{
int balance[5]={10,2,3,4,1};
double avg;
avg=getaverage(balance,5);
cout<<"平均值是:"<<avg<<endl;
}
c++从函数返回数组(C++ 不允许返回一个完整的数组作为函数的参数。但是,您可以通过指定不带索引的数组名来返回一个指向数组的指针。)
如果您想要从函数返回一个一维数组,您必须声明一个返回指针的函数
int *myfunction()
{
}
另外,C++ 不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量。
#include <iostream>
#include <ctime>
#include <stdlib.h> //用到了srand函数,所以要有这个头文件
using namespace std;
int *getrandom()
{
static int r[10];
srand((unsigned)time(NULL));
for (int i=0; i<10;i++)
{
r[i]=rand();
cout<<r[i]<<endl;
}
return r;
}
int main()
{
int *p;
p=getrandom();
for (int i=0; i<10;i++)
{
cout<<*(p+i)<<endl;
}
}
”不要返回一个局部变量的地址“,这是C/C++的金科玉律。
#include <iostream>
#include <ctime>
#include <stdlib.h>
using namespace std;
int *w(int a)
{
int b=a+5;
return &b;
}
int main()
{
int a=2;
int *p;
p=w(a);
cout<<*p<<endl;
cout<<*p<<endl;
}
输出:7 0
原因:p指向的地方已经不可靠了,第一次结果正确是因为p指向的地方凑巧没被修改
一个函数结束后,该函数内所有的自动变量所占用的内存空间都被释放,释放的含义是:通知系统,这些内存已经是自由的了,可以被其他代码改写了。没有被改写前,这些内存中还是原来的值,至于什么时候改写,那谁也不知道。所以返回它们的地址是没有任何意义的。
类
私有(private)成员:私有成员变量或函数在类的外部是不可访问的,甚至是不可查看的。只有类和友元函数可以访问私有成员。
默认情况下,类的所有成员都是私有的。
保护(protected)成员:保护成员变量或函数与私有成员十分相似,但有一点不同,保护成员在派生类(即子类)中是可访问的。
#include <iostream>
#include <ctime>
#include <stdlib.h>
using namespace std;
class box
{
protected:
double width;
};
class smallbox:box
{
public:
voidsetsmallwidth(double wid);
doublegetsmallwidth(void);
};
double smallbox::getsmallwidth(void)
{
return width;
}
void smallbox::setsmallwidth(double wid)
{
width=wid;
}
int main()
{
smallbox box;
box.setsmallwidth(12);
cout<<"width ofbox:"<<box.getsmallwidth()<<endl;
}
析构函数
在每次删除所创建的对象时执行
析构函数不会返回返回任何值,也不能带任何参数,它有助于跳出程序(比如关闭文件,释放内存等)前释放资源。
拷贝构造函数
用于:1.通过使用另一个同类型的对象来初始化新创建的对象
2.复制对象把他作为参数传递给对象
3.复制对象,并从函数返回这个对象
如果在类中没有定义拷贝构造函数,编译器会自行定义一个,如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数。
#include <iostream>
using namespace std;
class line
{
public:
int getlength(void);
line(int len);
line(const line &obj);
~line();
private:
int *ptr;
};
line::line(int len)
{
cout<<"normal constructorallocating ptr."<<endl;
ptr=new int;
*ptr=len;
}
line::line(constline &obj)
{
cout<<"copy constructorallocatinf ptr."<<endl;
ptr=new int;
*ptr=*obj.ptr; //此处应该赋值而不是赋地址
}
line::~line()
{
cout<<"freeingmemory."<<endl;
delete ptr;
}
int line::getlength()
{
return *ptr;
}
void display(line obj)
{
cout<<"length ofline"<<obj.getlength()<<endl;
}
int main()
{
line a(10);
line b=a;
display(a);
display(b);
}
友元函数(使用关键字friend声明)
类的友元函数是定义在类外部,但有权访问类的private和protected成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。
友元可以是一个函数,该函数被称为友元函数,友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有的成员都是友元。
#include <iostream>
using namespace std;
class box
{
double width;
public:
friend voidprintwidth(box a);
void setwidth(doublewid);
};
void box::setwidth(double wid)
{
width=wid;
}
void printwidth(box a) //printwidth()不是任何类的成员函数
{
cout<<"width of box"<<a.width<<endl; //因为printwidth()是box的友元,它可以直接访问类的任何成员。
}
int main()
{
box a;
a.setwidth(12);
printwidth(a);
}
this指针
在c++中,每一个对象都能通过this指针来访问自己的地址,this指针是所有成员函数的隐含参数。因此,在成员函数内部,他可以用来指向调用对象。
友元函数没有this指针,因为友元不是类的成员。只有成员函数才有this指针。
指向类的指针
一个指向c++类的指针与指向结构的指针类似,访问指向类的指针的成员,需要使用成员访问运算符->,就像访问指向结构的指针一样。
类的静态成员
我们可以用static来把类成员定义为静态的。当我们声明类的成员为静态时,这意味着无论创建多少个类的对象,静态成员都只有一个副本。
静态成员在类的所有对象中是共享的。
我们不能把静态成员放置在类的定义中,但是可以在类的外部通过使用::来重新声明静态变量从而进行初始化。
#include <iostream>
using namespace std;
class box
{
public:
static int objectcount;
box (double l=2,doubleb=2,double h=2)
{
length=l;
breadth=b;
height=h;
objectcount++;
}
double volume()
{
returnlength*breadth*height;
}
private:
doubleheight,breadth,length;
};
int box::objectcount=0; //初始化类box的静态成员对象
int main()
{
box a(2,3,4);
box b(1,2,3);
cout<<box::objectcount<<endl;
}
静态函数成员
如果把函数成员声明为静态的,就可以把函数与累的任何特定对象独立开来。静态函数成员即使在类对象不存在的情况下也能被调用,静态函数只要使用::就能访问。
静态成员函数只能访问静态数据成员,不能访问其他静态成员函数和类外部的其它函数。静态成员函数有一个类范围,他们不能访问类的this指针。可以使用静态成员函数来判断类的某些对象是否已被创建。
#include <iostream>
using namespace std;
class box
{
public:
static intobjectcount;
box (double l=2,doubleb=2,double h=2)
{
length=l;
breadth=b;
height=h;
objectcount++;
}
double volume()
{
returnlength*breadth*height;
}
static int getcount()
{
returnobjectcount;
}
private:
doubleheight,breadth,length;
};
int box::objectcount=0;
int main()
{
box a(2,3,4);
box b(1,2,3);
cout<<box::objectcount<<endl;
cout<<box::getcount()<<endl;
}
重载
1.重载一元运算符(对一个操作数进行操作)
#include <iostream>
using namespace std;
class distance_
{
private:
int feet,inches;
public:
distance_()
{
feet=0;
inches=0;
}
distance_(int f,int i)
{
feet=f;
inches=i;
}
void display()
{
cout<<feet<<" "<<inches<<endl;
}
distance_ operator- () //重载负运算符(-)
{
feet=-feet;
inches=-inches;
returndistance_(feet,inches);
}
};
int main()
{
distance_a(1,2),b(-3,4);
-a;
a.display();
-b;
b.display();
}
2.重载二元运算符(二元运算符需要两个参数)
#include <iostream>
using namespace std;
class box
{
doublelength,breadth,height;
public:
double getvolume()
{
returnlength*breadth*height;
}
void setlength(doublelen)
{
length=len;
}
void setbreadth(doublebre)
{
breadth=bre;
}
void setheight(doublehei)
{
height=hei;
}
box operator+(const box &b)
{
box a;
a.length=this->length+b.length;
a.breadth=this->breadth+b.breadth;
a.height=this->height+b.height;
returna;
}
};
int main()
{
box a,b,c;
double volume=0;
a.setbreadth(3);
a.setheight(2);
a.setlength(1);
b.setbreadth(8);
b.setheight(6);
b.setlength(9);
volume=a.getvolume();
cout<<"volume of a:"<<volume<<endl;
volume=b.getvolume();
cout<<"volume of b:"<<volume<<endl;
c=a+b;
volume=c.getvolume();
cout<<"volume of c:"<<volume<<endl;
}
3.关系运算符重载
#include <iostream>
using namespace std;
class distance_
{
private:
int feet,inches;
public:
distance_()
{
feet=0;
inches=0;
}
distance_(int f,int i)
{
feet=f;
inches=i;
}
void display()
{
cout<<feet<<" "<<inches<<endl;
}
distance_ operator -()
{
feet=-feet;
inches=-inches;
returndistance_(feet,inches);
}
bool operator<(const distance_ &d)
{
if (feet<d.feet)
{
return true;
}
if(feet==d.feet&&inches==d.inches)
{
return true;
}
return false;
}
};
int main()
{
distance_a(11,10),b(2,3);
if (a<b)
{
cout<<"a is less than b"<<endl;
}
else
{
cout<<"b is less than a"<<endl;
}
}
++和--运算符重载
#include <iostream>
using namespace std;
class time
{
private:
int hours,minutes;
public:
time()
{
hours=0,minutes=0;
}
time(int h,int m)
{
hours=h;
minutes=m;
}
void display()
{
cout<<hours<<" "<<minutes<<endl;
}
time operator++()
{
++minutes;
if(minutes>=60)
{
++hours;
minutes-=60;
}
returntime(hours,minutes);
}
timeoperator++(int)
{
timea(hours,minutes);
++minutes;
if(minutes>=60)
{
++hours;
minutes-=60;
}
returna;
}
};
int main()
{
time a(11,59),b(2,59);
++a;
a.display();
++a;
a.display();
b++;
b.display();
b++;
b.display();
}
赋值运算符重载
#include <iostream>
using namespace std;
class distance_
{
private:
int feet,inches;
public:
distance_()
{
feet=0;
inches=0;
}
distance_(int f,int i)
{
feet=f;
inches=i;
}
void display()
{
cout<<feet<<" "<<inches<<endl;
}
void operator=(constdistance_ &d)
{
feet=d.feet;
inches=d.inches;
}
};
int main()
{
distance_a(11,10),b(2,3);
a.display();
b.display();
a=b;
a.display();
b.display();
}
文件和流
#include <fstream>
#include <iostream>
using namespace std;
int main ()
{
char data[100];
// 以写模式打开文件
ofstream outfile;
outfile.open("afile.dat");
cout <<"Writing to the file" << endl;
cout <<"Enter your name: ";
cin.getline(data,100);
// 向文件写入用户输入的数据
outfile << data<< endl;
cout <<"Enter your age: ";
cin >> data;
cin.ignore();
// 再次向文件写入用户输入的数据
outfile << data<< endl;
// 关闭打开的文件
outfile.close();
// 以读模式打开文件
ifstream infile;
infile.open("afile.dat");
cout <<"Reading from the file" << endl;
infile >> data;
// 在屏幕上写入数据
cout << data<< endl;
// 再次从文件读取数据,并显示它
infile >> data;
cout << data<< endl;
// 关闭打开的文件
infile.close();
return 0;
}
cin.ignore()
cin.ignore(a,ch)方法是从输入流(cin)中提取字符,提取的字符被忽略(ignore),不被使用。每抛弃一个字符,它都要计数和比较字符:如果计数值达到a或者被抛弃的字符是ch,则cin.ignore()函数执行终止;否则,它继续等待。它的一个常用功能就是用来清除以回车结束的输入缓冲区的内容,消除上一次输入对下一次输入的影响。比如可以这么用:cin.ignore(1024,'\n'),通常把第一个参数设置得足够大,这样实际上总是只有第二个参数'\n'起作用,所以这一句就是把回车(包括回车)之前的所以字符从输入缓冲(流)中清除出去。
如果cin.ignore()不给参数,则默认参数为cin.ignore(1,EOF),即把EOF前的1个字符清掉,没有遇到EOF就清掉一个字符然后结束,会导致不正确的结果,因为EOF是文件结束标识.
例:
#include<iostream>
using namespace std;
int main()
{
char str1[30],str2[30],str3[30];
cout << "请输入你的姓名:";
cin>>str1;
cout<<"请输入你的住址:";
cin.ignore();
cin.getline(str2,30,'a');
cout << "请输入你的籍贯:";
cin.ignore();
cin.getline(str3,30);
cout<<str3;
}
如果在地址那里输入bcdabcd那么此时流里面剩的是bcd\n,此时cin.ignore();吃掉的就是b了,这是流里还剩下cd\n直接交给cin.getline(str3,30);因为有个\n所以这里getline就直接返回 .
异常处理
1.抛出异常(throw)
以下尝试除以零时抛出异常的实例
double division(int a,int b)
{if (b==0)
throw“division byzero condition!”;
return a/b;
}
2.捕获异常(catch)
try
{
//保护代码
}catch(exceptionname e)
{
//处理exceptionname异常的代码
}
处理try抛出的任何类型的异常
try
{
}catch(…)
{
}
#include <iostream>
using namespace std;
double division(int a,int b)
{
if (b==0)
throw"division by zero condition!";
return a/b;
}
int main()
{
int a,b;
cin>>a>>b;
try
{
double z;
z=division(a,b);
cout<<z<<endl;
}catch(const char*msg)
{
cerr<<msg<<endl;
}
}
new和delete运算符
#include <iostream>
using namespace std;
int main()
{
double *pvalue=NULL;
pvalue=new double;
*pvalue=29494.99;
cout<<"value ofpvalue:"<<*pvalue<<endl;
delete pvalue;
}
数组的动态内存分配
char *pvalue=NULL;
pvalue=new char[20];
delete []pvalue;
#include <iostream>
using namespace std;
class box
{
public:
box()
{
cout<<"调用构造函数!"<<endl;
}
~box()
{
cout<<"调用析构函数!"<<endl;
}
};
int main()
{
box *myboxarray=newbox[4];
delete[]myboxarray;
}
一般构建一个win32工程里面都会有这几个文件夹
include //放头文件.h
resource //图片什么的资源文件
source //放cpp文件
外部依赖项
cpp:做一些类里面的函数的具体实现
.h:叫做头文件,不能被编译。定义类的声明(成员与方法的声明),函数原型,#define常数等
#include:叫做编译预处理指令。可以简单地理解成,在1.cpp中的#include“1.h”指令把1.h中的代码在编译前添加到了1.cpp的头部。每个.cpp文件会被编译,生成.obj文件,然后所有的.obj文件链接起来你的可执行程序就算生成了。
至于.h和.cpp同样的主文件名,对于编译器是没有意义的,编译器是不会去匹配二者的主文件名,他只认#include等语句。
exit(0):正常运行程序并退出程序; 头文件为stdlib.h
exit(1):非正常运行导致退出程序;
return:返回函数,若在主函数中,则会退出函数并返回一值。
cerr和cout的区别:
cerr:错误输出流。无缓冲,不可以重定向。输出的数据不经过缓冲区,直接放在指定的目标中。其目的,就是在你最需要它的紧急情况下,还能得到输出功能的支持。
cout:标准输出流。有缓冲,可重定向。把要输出的数据先放到缓冲区中,然后再从缓冲区到你指定的设备中。当cout流插入一个endl,不论缓冲区是否满了,都立即输出流中所有的数据,然后插入一个换行符。
什么是缓冲区?
缓冲区又叫缓存,是内存空间的一部分。也就是说,在内存空间预留了一定的存储空间,用来缓冲输入输出的数据。
缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。
为什么要引入缓冲区?
比如我们从磁盘里取信息,先把读出的数据放在缓冲区,计算机再直接从缓冲区取数据,等缓冲区的数据取完后再去磁盘读取。这样可以减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度。
又比如,我们使用打印机打印文档,由于打印机的打印速度相对较慢,我们先把文档输出到打印机相应的缓冲区,打印机再自行逐步打印,这时我们的CPU可以处理别的事情。
现在您基本明白了吧,缓冲区就是一块内存区,它用在输入输出设备和CPU之间,用来缓存数据。它使得低速的输入输出设备和高速的CPU能够协调工作,避免低速的输入输出设备占用CPU,解放出CPU,使其能够高效率工作。
缓冲区的目的,就是减少刷屏的次数——比如,你的程序输出圣经中的一篇文章。不带缓冲的话,就会每写一个字母,就输出一个字母,然后刷屏。有了缓冲,你将看到若干句子“同时”就出现在了屏幕上(由内存翻新到显存,然后刷新屏幕)。
缓冲区的类型:
1.全缓冲
当填满标准I/O缓存后才进行实际I/O操作。全缓冲的典型代表是对磁盘文件的读写。
2.行缓冲
在这种情况下,当在输入和输出中遇到换行符时,执行真正的I/O操作。这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O操作。典型代表是键盘输入数据。
3.不带缓冲
也就是不进行缓冲,标准出错情况stderr是典型代表,这使得出错信息可以直接尽快地显示出来。如错误输出时使用,cerr<<”错误,请检查输入的参数!”;
缓冲区的刷新
下列情况会引发缓冲区的刷新:
1、缓冲区满时;
2、执行flush语句;
3、执行endl语句;
4、关闭文件。
cout<<endl; ó cout<<”/n”<<flush;
键盘操作演示行缓冲
getchar()函数
当程序调用getchar()函数时,程序就等着用户按键,并等用户按下回车键返回。期间按下的字符存放在缓冲区,第一个字符作为函数返回值。继续调用getchar()函数,将不再等用户按键,而是返回您刚才输入的第2个字符;继续调用,返回第3个字符,直到缓冲区中的字符读完后,才等待用户按键。
例如:
#include <iostream>
#include<stdlib.h>
#include<cstring>
#include<stdio.h>
usingnamespace std;
intmain()
{
char c;
//第一次调用getchar()函数
//程序执行时,您可以输入一串字符并按下回车键,按下回车键后该函数才返回
c=getchar();
//显示getchar()函数的返回值
cout<<c<<endl;
//暂停
system("PAUSE");
//循环多次调用getchar()函数
//将每次调用getchar()函数的返回值显示出来
//直到遇到回车符才结束
while((c=getchar())!='/n')
{
cout<<c;
}
}
getchar()函数的执行就是采用了行缓冲。第一次调用getchar()函数,会让程序使用者输入一行字符并直至按下回车键才返回。此时用户输入的字符和回车符都存放在行缓冲区。
再次调用getchar(),会逐步输出行缓冲区的内容。
system(“pause”);
包含在“stdlib.h”头文件里。
就是从程序里调用“pause”命令,而pause这个系统命令的功能很简单,就是在命令行上输出一行类似于“press any key to exit ”的字,等待用户按一个键然后返回。
比如:在编写的c++程序中,如果是窗口,有时会一闪就消失了,如果不想让其消失,在程序结尾处添加:
system("pause");
内存泄露:
1.内存分配未成功,却使用了它。
2.内存分配虽然成功,但是未初始化就引用了它。
3.内存分配成功而且已经初始化,但操作越过了内存的边界。
4.忘记了释放内存,造成内存泄露。
5.释放了内存却继续使用它。
有人对某一只在函数内使用的指针动态分配了内存,用完后不释放。其理由是:函数运行结束后,函数内所有的变量全部消亡,这是错误的,动态分配的内存在“堆”里,并不随着函数结束而消亡。
就算赋值为NULL,也是需要释放的。
给指针赋值有两种情况:
1.在堆上分配一块内存(即动态分配内存),让指针指向这块内存
2.指针指向栈上的一块内存(一般是定义一个非指针变量)
#include <iostream>
#include <stdio.h>
#include <cstdio>
#include <malloc.h>
using namespace std;
int main()
{
//第一种
int*p1=(int *)malloc(sizeof(int)); //动态在堆上分配一块内存(手动分配)
cin>>*p1;
cout<<*p1<<endl;
free(p1); //释放内存
//第二种
inti; //由系统自动在栈上分配一块内存
int*p2=NULL;
cin>>i;
p2=&i; //将p2指向栈上i的内存
cout<<*p2<<endl;
}
为什么不在第二种情况后面也加上free(p2)?
如果加了free(p2)编译器会报内存错误。因为p2指向的是i内存,i的内存是在栈上,栈上的内存是由系统管理,如分配和释放,不需要手动管理,这里使用free(p2)是在释放i的内存,这块内存不用你管你却使用free()管理当然会报错。
#include <iostream>
#include <stdio.h>
#include <cstdio>
#include <malloc.h>
using namespace std;
int main()
{
int*p2=new int[3]; //分配3块int类型大小的内存空间
inti=0;
while(i<3)
{
cin>>p2[i];
i++;
}
delete[]p2; //注意这个释放方式
int*p3=new int(45); //分配一块内存,并将45存放在这块内存中
cout<<*p3<<endl;
deletep3;
}
第二种方式依次输入56,78,23
下图是p2的存储方式:
|
P2 |
0x00152e30 |
|
P2[0] |
56 |
|
P2[1] |
78 |
|
P2[2] |
23 |
createNode(BinNode *tree,char *p)
{
tree = (BinNode *) malloc(sizeof(BinNode));
tree->data = *p;
}
该代码段的意图是通过一个函数创建一个二叉树的节点,然而在,调用该函数后,试图访问该节点结构体的成员时候,却发生了内存访问错误。
原因:[如果函数的参数是一个指针,不要指望用该指针去申请动态内存]
原来问题出在C编译器原理上:编译器总是要为函数的每个参数制作临时副本,指针参数tree的副本是 _tree,编译器使 _tree = tree。如果函数体内的程序修改了_tree的内容,就导致参数tree的内容作相应的修改。这就是指针可以用作输出参数的原因。
即上面的函数代码经过编译后成为:
createNode(BinNode *tree,char *p)
{
BinNode *_tree;
_tree = tree;
_tree = (BinNode *) malloc(sizeof(BinNode));
_tree->data = *p;
}
如果没有
_tree = (BinNode *) malloc(sizeof(BinNode));
这个语句,在函数体内修改了_tree的内容,将会导致参数tree的内容作相应的修改,因为它们指向相同的内存地址。而
_tree = (BinNode *) malloc(sizeof(BinNode));
这句,系统重新分配内存给_tree指针,_tree指针指向了系统分配的新地址,函数体内修改的只是_tree的内容,对原tree所指的地址的内容没有任何影响。因此,函数的参数是一个指针时,不要在函数体内部改变指针所指的地址,那样毫无作用,需要修改的只能是指针所指向的内容。即应当把指针当作常量。
函数传参:
1.传值:把实参的值赋给形参,那么对形参进行修改,不会影响实参的值
2.传地址:实参和形参都指向同一个对象、
3.传引用:形参和实参都是同一个对象
传递指针时不能改变指针本身的地址,传递指针引用可以改变指针本身的地址。

6万+

被折叠的 条评论
为什么被折叠?



