C++基础
I/O
cout保留有效数字问题
C++中cout默认保留六位有效数字,并且进行四舍五入
修改保留数的方法
cout.precision(2); //用这个来改变默认保留几位小数
cout<<"保留两位有效:"<<endl;
cout中可以不写endl,endl属于换行符。
cout字符串输出
对于字符中间可以不使用<< 换行也没有影响 而变量由于变量名不能合并所以要用<<,相当于多个cout叠加
解释 cout<<"hello\nworld"; 或者cout<<"hello\n""world";
两种I/O方式
cin>>a; cout<<a;
scanf(“%d%d%d”,&a,&b,&c); printf(“%d”,b);
scanf printf相对于cin cout速度更快,处理数据范围更大,并且更多样化
输出整数
输出时要求为整数,可以使用int输出整形,也可以用double后用%.0lf %.x就是保留小数点后x位
小数
小数要用double(最好不用float)。输入时对于double变量使用lf。输出时float与double都使用f
整形/整形==整形
t=ceil(s/v)+10;//此处如果s与v采用int,则结果为整数
如果t,s改为整数型,则s/t实际上进行的是整除 如 17/8=2;单让s为double也可以,即 17.0/8;
直接输出判断01
printf("%d",(year%4==0&&year%100!=0)||year%400==0);//直接输出判断0,1时不能用cout
输入输出控制符
%x 以16进制读入或输出整形变量
%nd 以n宽度输出整数,不足用空格填充
%0nd 以以n宽度输出整数,不足用0填充
%.nf 输出浮点数,保留小数
%e 以科学计数法形式输出 可以使用%.0e让double类型以整数形式输出科学计数法
%g(%G) 浮点数不显无意义的零"0"
%s 字符串
%o以八进制数形式输出整数
%u以十进制数输出unsigned型数据
格式字符串(格式)
〔标志〕〔输出最少宽度〕〔.精度〕〔长度〕类型
"%-md" : 左对齐,若m比实际少时,按实际输出。
"%m.ns" : 输出m位,取字符串(左起)n位,左补空格,当n>m or m省略时m=n
"%m.nf" : 输出浮点数,m为宽度,n为小数点右边数位
"%3.1f" : 输入3852.99 输出3853.0
char
输入字符时,不会跳过空格。可以通过在scanf中添加非控制字符解决
三个跳转语句
break:打破循环
continue:打破此次循环,进入下一个循环
goto
先标记,后跳转
标记语句: goto 大写单词;(分号)
跳转语句: 大写单词:(冒号)
程序跑到标记语句后会直接跳转到跳转语句
数组
数组要在main方法外定义,不然可能会出现问题
数组越界
- 可能会引起意外修改其他变量的值,导致程序运算结果不正确
- 可能试图访问不该访问的内存区域,导致程序崩溃
- 数组越界的程序,某些编译器可能会正常运行,有的不能
求数组长度
字符串数组
strlen( )
数字数组
sizeof()函数可以返回数组所占的内存,而sizeof(a[0])返回的是数组第一个元素所占的内存 比如int类型的单个所占内存是4
也就是写成sizeof( ) / sizeof(a[0])
位运算
用于对整数类型(int,char,long等)变量中的某一位(bit),或者若干为进行操作
六种位运算符
& //按位与(双目)
| //按位或(双目)
^ //按位异或(双目)
~ //按位非(取反)(单目)
<< //左移(双目)
>> //右移(双目)
指针
也称为指针变量,大小为4(32位)或8个字节,其内容代表一个内存地址
指针的定义 : 类型名 * 指针变量名
理解
int*p = (int *) 40000;//把40000写入p所在的内存空间里面
*p=5000;//往地址40000处起始的若干个字节的内存空间中写入5000
int n = *p;//将地址40000处起始的若干个字节的内容赋值给n
p代表一个数据;而*p则是指向地址p所在的内存空间;
*p赋值给n,相当于是把p所指向的地址的内容赋给n
T*p
p的类型是T*
*p的类型是T
通过*p,可以读写从地址p开始的sizeof( T )
*p等价于存放在地址p处的一个T类型的变量
*是间接引用运算符
sizeof( T* )是4字节(64位计算机上可能是8个字节)
实际用法
让指针指向某一变量的地址:
char ch1 ='A';
char*pc=&ch1;//使pc指向变量ch1
&:取地址运算符
指针的运算
指针的比大小比的是地址,而不是地址里的内容
p1 - p2=(地址p1 - 地址p2) / sizeof(T)代表p1,p2之间能存放多少个T类型的数据
p+n = 地址p + n*sizeof(T) 最后还是一个地址,减法同理
p[ n ]等价于 *(p + n)
空指针
可以用NULL对于任意类型的指针赋值
空指针指向内存中编号为0的空间
用来初始化指针变量
空指针指向的内存是不可以访问的
指针可以作为条件表达式使用,if(p)等价于if(p!=NULL)
野指针
指针变量指向非法的内存空间
const修饰指针
有三种情况
- const修饰指针---常量指针
const int *p = &a;
指针的指向可以修改,指针指向的值不可以改
- const修饰常量---指针常量
int * const p = &a;
指针的指向不可以修改,指针指向的值可以改
- const即修饰指针,又修饰常量
const int * const p =&a
指针指向和指针指向的值都不可以修改
指针与数组
数组的名字是一个指针常量(一个地址),指向数组的起始位置。可以用名字给相同类型的指针赋值
int *p = arr;//arr就是数组的首地址
p++;//实际上地址加了4字节(每次加的都是这个指针类型的长度),指向了数组的第二位
作为函数形参时,T*p和T P[ ]等价
p[ n ]等价于 *(p + n)
指针和二维数组
对于二维数组a[ 3 ] [ 4 ],a[ i ]可以作为他的指针,他是一个一维数组
sizeof(a[i])=sizeof(T)*4
a[i]指向的地址是a的起始地址+i * N * sizeof(a[i])=sizeof(T)*4,也就是指向a数列第i行的第一列
指针和字符串
字符串常量的类型就是char*
字符数组名的类型也是char*
指针与函数
void swap(int *p1,int *P2){
int temp=*p1;
*p1=*p2;
*p2=temp;
}
swap(&a,&b);//传入两个地址
//指针是地址传递,可以修饰实参
引用
类型名 & 引用名 = 某变量名
int n = 4;
int & r = n;//r引用了n,r的类型是int &
某个变量的引用等价于这个变量,相当于这个变量的一个别名
引用必须要初始化
引用只能引用变量,不能引用变量和表达式。一旦初始化后,不能改变引用对象
用法1:作为形参
通过引用做函数参数可以让形参修饰实参(可以不用指针了)
最经典的就是自定义swap正常情况下是形参改变并没有使实参交换
可以作为函数的输入值void swap(int & a){ }
用法2:作为返回值
- 不要返回局部变量的引用(还是因为栈会把局部变量删除),解决方法:通过static把局部变量变为静态变量,他存放在全局区
- 引用作为返回值可以作为左值(放在等号左边):由于函数返回的是一个引用,所以可以赋值
test02()=1000;
可以作为函数的返回值int & SetValue( ) { return n; } 返回值是一个int的引用,引用名为n
常引用
const 类型名 & 引用名 = 某变量名
常引用不能被赋值,相当于只能使用被引用变量的值而不能改变它
主要用来修饰形参,防止误操作
int &ref = 10;//由于10不是一个变量所以会报错,引用必须引一块合法的内存空间
const int &ref = 10;//系统会用一个临时变量来储存10,然后让ref作为这个临时变量的引用
ref = 20;//报错,常引用不可修改
const T &和T&是不同的类型
T&类型的引用或者T类型的变量可以用来初始化const T &l类型的引用。反之则需要强制转换
本质
本质是指针常量:这也是引用不可以改变方向的原因
const
可以定义常量
可以定义常量指针
不可以通过常量指针修改其指向的内容,常量指针的指向可以改变
不可以把常量指针赋值给非常量指针(除非使用强转,把常量指针转为非常量指针后再赋值),反之可以
函数参数为常量指针时,可避免函数内部不小心修改了参数指针所指地方的内容(防止自己打代码是犯错误)
可以定义常引用
默认参数(缺省参数)
- 如果某个位置已经有了默认参数,那么从这个位置往后,从左到右都必须有默认值
- 防止二义性
占位参数
void func(int a,int);
//调用函数时必须输入两个int数才可以调用
头文件
iostream
iostream(iostream.h)用于输入输出,老版C++需要输入扩展名.h
namespace
using namespace std为名称空间,可以使用多个版本的同一函数
cmath
用于数学计算
int abs(int x) //求整形数绝对值
double cos(double x) //求余弦
double fabs(double x) //求浮点数绝对值
int ceil(double x) //求不小于x的最小值
double sin(doubel x) //求正弦
double sqrt(double x) //求平方根
ctype
用于字符处理
输入参数为int或者char(int和char是兼容的,可以通过ascii码相互转换)
isalnum() // 判断是否为字母或者数字
iscntrl() // 判断是否为控制字符
isgraph() // 判断是否为除空格外的打印字符
islower() // 判断是否为小写字符
isprint() // 判断是否为打印字符
ispunct() // 判断是否为标点符号
isspace() // 判断是否为空格
isupper() // 判断是否为大写字母
isdigit() // 判断是否为数字字符
isxdigit() // 如果参数是十六进制数字,0~9、a~f、A~F,返回true
tolower() // 如果参数是大写字符,返回其小写
toupper() // 如果参数是小写字符,返回其大写
结构体
语法:struct 结构体名 {结构体成员列表}
创建具体对象: struct 结构体名 对象名 ={挨个赋值},也可以在创建后再赋值。struct可以省略
结构体数组
定义结构体后可以创建结构体数组struct 结构体名 结构体数组名[长度]
结构体指针
student s;//创建对象
student *p = &s;//指针指向这个对象那个
p ->name;//调取对象的属性
函数的分文件编写
- 创建 .h 的头文件
- 船舰 .cpp的源文件
- 在头文件中写函数的编写
- 在源文件中写函数的定义
完成后在主文件加入#include "xxx.h" (引号是优先从该文件所在目录查找头文件)
============================================
内存分区模型
代码区:存放函数体的二进制代码,由操作系统进行管理的
全局区:存放全局变量和静态变量以及常量
栈区:由编译器自动分配释放,存放函数的参数值,局部变量等
堆区:由程序员分配和释放若程序员不释放程序结束时由操作系统回收
栈区
不要返回局部变量的地址
int *func(){
int a = 10;
return &a;
/*用new解决
int *p = new int(10);//new后会返回一个地址,用指针来接收
return p;
*/
}
int main(){
int *p=func();
cout<<*p<<endl;
cout<<*p<<endl;
}
//第一次输出为10,第二次数据错误
//局部变量在使用过后会清除,但是编译器会保留一次,所以第一次输出是局部变量还在
局部变量存放在栈区,但是可以通过new在堆区开辟数据防止上述情况发生
动态内存分配new
分配一个变量或分配一个数组
P = new T
int *p = new int(10);//给数据10开辟空间
int *arr = new int[10];//给一个[10]的数组创建空间
T是任意类型名,P是类型为T*的指针
动态分配出一片大小为sizeof (T) 字节的内存空间,并且该内存空间的其实地址赋值给P
释放动态内存
用delete来释放动态分配的内存,删除动态分配的数组,要在delete后面加上[ ]
delete p;
delete[] arr;
内联函数
可以减少函数调用的开销,针对于只有几条语句的函数,他们执行的很快,执行很多次。编译器处理内联函数时将整个函数的代码插入到调用语句处,而不会产生调用函数的语句
在函数定义前面加inline就可以定义内联函数
函数重载
跟java一样
- 同一作用域下
- 函数名字相同
- 函数参数类型不同或者个数不同或者顺序不同
- 引用可以作为函数重载的条件(引用和常引用时类型不同的)
func(int &a){}
func(const int &a){}
int a=10;
func(a);//调用无const的
func(10);//调用有const的
- 函数重载碰到默认参数要防止调用参数可能会有两种结果
void(int a,int b=10){
}
void(int a){
}
void(10);//上面两个都可以调用,所以报错
类
写法
class CRectangle{
public:
int n;
void Init(int n_){
n = n_;//初始化,类似于this.name=name
}
.....
//属性和函数
};//最后必须有分号
//使用时(实例化)
CRectangle r;//r是对象
//用法1
r.Init(n);//调用函数
//用法2 指针
CRectangle * p = & r;
p -> Init(5);
//用法3 引用
CRectangle &rr = r;
rr.w=5;
sizeof(CRectangle)的大小就是所有成员变量的大小之和
声明
现在类里声明而不写具体内容
在外面写声明的函数
int CRectangle::Area( ){
......
}
//这样可以表明Area函数是属于CRectangle类的,不是全局函数
类成员可访问范围
公共权限 public 成员类内可以访问 类外可以访问
保护权限protected 成员类内可以访问 类外不可以访问 儿子可以访问父亲中的保护内容
私有权限private 成员类内可以访问 类外不可以访问 儿子不可以访问父亲中的保护内容
如果没有写改成员的关键词,缺省的认为他是私有成员
类中也可以重载
int x;
void value(int val=0){x=val0}//
int value() {return x;}
注意防止二义性
void value(int val=0){x=val;}
int value(){ return x; }
//调用A.value()无法判断是哪一个,因为第一个是缺省参数,不输入也可以
struct和class区别
唯一的区别就是默认的访问权限不同(在不表明权限时,内部成员的默认权限):
struct默认权限为公共
class默认权限为私有
构造函数
class Complex{
Complex(int n){
}//在内部构造
};
Complex::Complex(double r){
}//在外面构造函数,这个最后不用加分号
函数与数组
CSample array1[2] //array数组中的2个元素都是CSample的对象 用的都是无参构造函数
Test(int n)[{} (1)
Test(int n,int m)[{} (2)
Test()[{} (2)
Test array1[3]={1,Test(1,2)}//第三个元素方式省略,所以用无参构造函数
//三个元素分别用(1)(2)(3)初始话
复制构造函数
一定存在
只有一个参数,即对同类对象的引用
形如X : : X( X& )或X : : X( const X & ),二者选一,后者能以常量对象作为参数(括号里的是引用,不是对象)
如果没有定义复制构造函数,那么编译器生成默认复制构造函数。默认的复制构造函数完成复制功能。
Complex c1;//调用无参构造生成对象
Complex c2(c1);//运用默认的复制构造函数复制c1,初始化与c1一样
起作用的三种情况
1)当用一个对象去初始化同类的另一个对象时
Complex c2(c1);
Complex c2 = c1;//初始化语句,非赋值语句,与上面等价
c2=c1;//这是赋值,不导致复制构造函数被调用,
2 ) 如果某函数有一个参数是类A的对象,
那么该函数被调用时,类A的复制构造函数将被调用
一个函数的参数如果是对象的话,一定是用复制构造函数初始化的
3 )如果函数的返回值是类A的对象时,则函数返回时A的复制构造函数被调用
注意:对象间赋值并不导致复制构造函数被调用
常量引用参数的使用
void fun(CMYclass obj_){
cout<<"fun"<<endl;
}
- 这样的函数,调用时生成形参会引发复制构造函数调用,开销比较大
- 所以可以考虑使用CMyclass&引用类型作为参数
- 如果希望确保实参的值在函数中不应被改变,那么可以加上const关键字(引用会影响本体)
===========================================
有意思的事情
各种长度求法统计
字符串长度
str.length( )
str.size( )
strlen( )
字符数组长度
strlen( a )获取实际长度
sizeof( a )获取申明的数组所占的字节
数组长度
sizeof(a)/sizeof(a[0]) 先得出所占字节,再除该类型数组每一单位所占字节
if中进行赋值
a = b = 3;
printf("a = %d, b = %d.\n",a,b);
if (a=4)
printf("a is equal to 4.");
else
printf("a is not equal to 4.");
//(a=4)对于编译器而言,是完全正确的表达。这个表达式除了将4赋值给变量a之外,还会返回整数4作为表达式的值。对于if条件语句,非零即真,因此,(a=4)被视为逻辑真
a++与++a
int x=7,y=8;
int z1=y-(x++);//在x被使用后使其自加1,z1计算出来后x=8
int z2=y-(++x);//在x被使用前使其自加1,z2计算前x先变成9(上一次运算已经使x=8)
++a,在表达式中返回的值是加1后的
a++,在表达式中返回的值是加1前的,即原来的a
cin与scanf不混用,输出也是
溢出
printf("%d",(2147483646+6)/2)//结果溢出,结果错误
printf("%d",2147483646/2+6/2)//结果正常
逻辑表达式是短路计算
如果逻辑符前面已经可以判断出整体的对错,那么后面的表达式就不再进行计算
大小写转换
根据ASCII表 小写字母=大写字母+32,则大写字母=小写字母-32
for括号内不写东西
for括号中三种内容都可以不写,但是;;必须保留
for( ; ; )是死循环,可以用break跳出
scanf有返回值
scanf()返回值为int,表示成功读入的变量个数
EOF
EOF是直接可以用的符号常量,值为-1
常用来做对错判断
无限输入
通过ctrl+z回车解决
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
cout<<n+m;
}
//可以无线输入,回车也不会结束进程。按下ctrl+Z后再按回车才会暂停
通过回车解决
int s[10001];
int i = 0;
while(cin >> s[i]){
i++;
if(cin.get() == '\n'){
break;
}
}
freopen
在主函数开头输入freopen("c:\\temp\\test.test","r",stdin);
可以程序读取c:\temp\test.test中的数据,不用用键盘敲了(代码中地址要写双斜杠)
定义常量
define NUM 100(C的用法)
const int MAX_VAL = 23;(C++的用法)
不让double四舍五入
double a=6.6666;
a=(int)(a*100)/100.0;//将6.6666乘100变为666.66然后通过强转int改为666,最后再用100.0转回double
printf("%.2lf",a);
//如果保留三位小数,就把100改为1000
while(i++)与while(++i)
前者是先将 i 用于判断,在使 i +1
后者是先使 i +1,在将 i 用于判断
unsigned long
unsigned long long这个比longlong范围还要大
打印的时候用%u
unsigned long long,没有符号,表示范围是0到264-1
long long 表示范围是-263-1到263-1
VS软件提示没有找到exe文件
可能是因为程序出现错误,所以说无法构建
传入的参数为对象的地址
当参数传入的是地址的时候,指向它的成员用的不是点,而是箭头->
如果传入的是对象,则正常用.
char类型的指针可以存放一个字符串
char类型的指针实际上是存储了字符串首字符的地址
字符串又是连续存储的,char类型的大小也可以确定,所以一个指针就可以代表这个字符串了。
在字符串中输入双引号
正常情况下在定义字符串的双引号中写下双引号,\n等会影响字符串输出形式
在“前输入\可以告诉程序这个是字符串的一部分,其他同理
char与int对于数字的转换
实验结果:
char a='9';//赋值为字符9,以整形输出为57
int c=int(a);//c为57
char b=57;//赋值为ascii的数值57,以整形输出为57,以字符输出为9
用int直接转换得到的是ascii的值
所以用char-'0'
==================
函数使用
自定义函数
某一函数需要调用A函数,则A函数应该写在这个函数前面
如果A调B,B调A,哪个写在前面?:运用声明语句,即不写函数体内容
char
char用来定义字符变量,其关联的还有getchar等
getchar读取缓冲区方法
在控制台中通过键盘输入数据时,以回车键作为结束标志。当输入结束后,键盘输入的数据连同回车键一起被输入到输入缓冲区中。在程序中第一次调用getchar()函数从输入缓冲区中读取一个字节的数据。需要注意的是,如果此时在程序中第二次调用getchar()函数,因为此时输入缓冲区中还有回车键的数据没有被读出,第二个getchar()函数读出的是回车符。(/n)
例:输入a然后回车结束,用两次getchar( ),第一次是a,第二次是回车符
cin.get可以获得输入的所有字符,包括空格回车。返回值是int型
int c;
while((c = cin.get())!=EOF){//在while中输入执行语句
cout<<(char) c;
}
//也可以用scanf("%c",%c);
解决方法1
可以使用rewind()函数来清理输入缓冲区中的数据
void rewind( FILE* stream );
//参数stream表示指向FILE结构的指针,即为指定的流。该函数的作用是将文件指针移动到文件的起始位置处。
//getchar是从标准的输入stdin中读取字符,所以用stdin
//学长说一般rewind都是配合stdin使用的,另外几个配合fflush
假设输入是a,回车,b,回车。代码采用getchar,rewind,getchar,rewind可以使读入的两个字符为a,b。
解释:输入a回车,a与回车符会进入缓冲区,getchar读取a后清空缓存区,接着上b回车,读的就是b
其他解决方法
getchar()使用不方便,解决方法:
- 使用下面的语句清除回车: while(getchar()!='\n');
- 用getche()或getch()代替getchar(),其作用是从键盘读入一个字符(不用按回车),注意要包含头文件<conio.h>
getch getche getchar
getchar()
函数名:getchar()
头文件:stdio.h
功 能:从I/O流中读字符
原 型:int getchar(void);
getchar()函数是输入流读入一个字符, 并带回显。它与后面两个函数的区别在于: getchar()函数等待输入直到按回车才结束, 回车前的所有输入字符都会逐个显示在屏幕上。但只有第一个字符作为函数的返回值。getchar不忽略空白符。
getch( )
函数名: getch()
头文件:conio.h
功 能:从控制台读取一个字符,但不显示在屏幕上
原 型:int getch(void)
返回值:读取的字符
getche()
函数名:getche()
头文件:conio.h
功 能:从控制台取字符(带回显)
用 法:int getche(void);
输入带空格的字符串
- cin:当遇到空白字符(空格或者回车键)即停止,并且会把空白字符留在缓冲区,容易造成数据的输入错误。
- cin.get():接收缓冲区的第一个字符,通常用来接收由cin产生的空白字符(比如空格)
- getline(cin,str (string变量名) ):可以输入一行,能接收空格,用string来接收。遇到回车结束输入。
- scanf:%s输入的字符串不能有[空格]或[换行],否则直接结束输入
排序函数sort
sort用于数列排序
sort(a,a+4); 默认升序
次方pow
pow(a,b);
a的b次方,a为double类型,b为int类型
system("pause");
输入在return之前,执行到该语句时会暂停,程序会显示输入任意键继续
system("cls");
清空面板
string的compare比较函数
可以使用 compare()
函数比较 char*
类型和 string
类型字符串
大小比较通常与字典顺序一致
如果两个字符串相等,返回0
调用字符串小与被调用字符串,返回-1
调用字符串大于被调用字符串,返回1
compare()比较时逐字符比较的,一旦能比较出结果,就不再比较了
strcmp
可以使用 strcmp()
函数比较 char*
类型
strcmp(const char *s1,const char * s2)
如果两个字符串相等,返回0
如果为小于,返回-1
如果为大于,返回1
字符串比较 <
在 C++ 中,我们还可以使用比较运算符比string
类型字符串的字典序
sort
sort(起始地址,结束地址,比较器)
比较器可以是自己写的函数,其返回值为bool
当比较器返回true时,第一个参数放在前面,第二个参数放在后面,即位置不变
当比较器返回false时,为两元素交换位置
比较器的值可以使用引用类型,节省空间开销
strtok
strtok(char s[], const char *delim);
- str – 要被分解成一组小字符串的字符串。
- delim – 包含分隔符的 C 字符串。
该函数返回被分解的第一个子字符串,如果没有可检索的字符串,则返回一个空指针。
- 分割处理后原字符串 str 会变,变成第一个子字符串
- strtok函数会把分割前的字符串破坏掉,即每次分割后,原来的字符串就会少掉一部分,完整性会被破坏(原字符串的改动是将分割符原位置均更改为 '\0',内容却都还在)
- 存在多线程问题,不安全。VS要求使用strtok_s
char str[80] = "this is - CSDN - blog";
const char s[2] = "-";
char *token;
/* 获取第一个子字符串 */
token = strtok(str, s);
/* 继续获取其他的子字符串 */
while( token != NULL ) {
printf( "%s\n", token );
token = strtok(NULL, s);
}
/*
对于strtok(NULL, s);的解释
这个函数strtok(OriginalString,Seps)涉及到两个指针。
第一个指针pointer_a用来指向函数返回的字符串,这个字符串是被原字符串OriginalString被seps中的字符截断后的第一个字符串。
第二个指针pointer_b用来指向OriginalString中,匹配截断字串seps的位置。
NULL的作用只是为了使得每次调用时,都不是从头开始,而是从上次调用时查找所停止的位置开始
*/
安全strtok_s
char *strtok_s( char *strToken, const char *strDelimit, char **buf);
这个函数将剩余的字符串存储在buf变量中,而不是静态变量中,从而保证了安全性。
strcpy_s
也是为了安全
用途:
char *p=new char[10];
p="hello";
delete p[];//此步释放时将报错
//在C++中,字符串常量"hello"被保存在常量存储区,而p="hello"操作是改变了指针的指向,使得指针p指向了常量存储区的"hello",造成了初始在堆上开辟的内存泄露,而delete无法释放常量存储区的内存,导致出错。
char *p=new char[10];
strcpy(p,"hello");
delete p[];//正确
函数功能把含有\0'结束符的字符串复制到另一个地址空间。(\0是字符串结束的标志)
strcpy_s(str, len+1,s);
//将s中字符串复制到str,最后一个空间为'\0'结束符
第一个参数:目标字符串指针
第二个参数:字符串长度,可使用strlen()函数直接求出,切记,在使用strlen()求出字符串长度时,勿忘+1
第三个参数:输入字符串指针
string转为char数组
string str1 = "ABCDEFG";
char a[20];
strcpy(a,str1.c_str());//用到 c_str()函数