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修饰指针

有三种情况

  1. const修饰指针---常量指针

const int *p = &a;

指针的指向可以修改,指针指向的值不可以改

  1. const修饰常量---指针常量

int * const p = &a;

指针的指向不可以修改,指针指向的值可以改

  1. 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:作为返回值

  1. 不要返回局部变量的引用(还是因为栈会把局部变量删除),解决方法:通过static把局部变量变为静态变量,他存放在全局区
  2. 引用作为返回值可以作为左值(放在等号左边):由于函数返回的是一个引用,所以可以赋值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

可以定义常量

可以定义常量指针

不可以通过常量指针修改其指向的内容,常量指针的指向可以改变

不可以把常量指针赋值给非常量指针(除非使用强转,把常量指针转为非常量指针后再赋值),反之可以

函数参数为常量指针时,可避免函数内部不小心修改了参数指针所指地方的内容(防止自己打代码是犯错误)

可以定义常引用

默认参数(缺省参数)

  1. 如果某个位置已经有了默认参数,那么从这个位置往后,从左到右都必须有默认值
  2. 防止二义性

占位参数

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;//调取对象的属性

函数的分文件编写

  1. 创建 .h 的头文件
  2. 船舰 .cpp的源文件
  3. 在头文件中写函数的编写
  4. 在源文件中写函数的定义

完成后在主文件加入#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一样

  1. 同一作用域下
  2. 函数名字相同
  3. 函数参数类型不同或者个数不同或者顺序不同
  4. 引用可以作为函数重载的条件(引用和常引用时类型不同的)
func(int &a){}
func(const int &a){}

int a=10;
func(a);//调用无const的
func(10);//调用有const的
  1. 函数重载碰到默认参数要防止调用参数可能会有两种结果
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()使用不方便,解决方法:

  1. 使用下面的语句清除回车: while(getchar()!='\n');
  2. 用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 字符串。

该函数返回被分解的第一个子字符串,如果没有可检索的字符串,则返回一个空指针。

  1. 分割处理后原字符串 str 会变,变成第一个子字符串
  2. strtok函数会把分割前的字符串破坏掉,即每次分割后,原来的字符串就会少掉一部分,完整性会被破坏(原字符串的改动是将分割符原位置均更改为 '\0',内容却都还在)
  3. 存在多线程问题,不安全。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()函数
posted @ 2023-01-20 17:37  Zaughter  阅读(33)  评论(0编辑  收藏  举报