talk about string,char
【1】.关于sprintf和snprintf的正确使用
考虑以下有缺陷的例子:
void f(const char *p)
{
char buf[11]={0};
sprintf(buf,"%10s",p); // very dangerous
printf("%sn",buf);
}
不要让格式标记“%10s”误导你。如果p的长度大于10个字符,那么sprintf() 的写操作就会越过buf的边界,从而产生一个缓冲区溢出。
检测这类缺陷并不容易,因为它们只在 p 的长度大于10个字符的时候才会发生。黑客通常利用这类脆弱的代码来入侵看上去安全的系统。
要修正这一缺陷,可以使用函数snprintf()代替函数sprintf()。
函数原型:int snprintf(char *dest, size_t n, const char *fmt, ...);
函数说明: 最多从源串中拷贝n-1个字符到目标串中,然后再在后面加一个0。所以如果目标串的大小为n的话,将不会溢出。
函数返回值: 若成功则返回存入数组的字符数,若编码出错则返回负值。
推荐的用法:
void f(const char *p)
{
char buf[11]={0};
snprintf(buf, sizeof(buf), "%10s", p); // 注意:这里第2个参数应当用sizeof(str),而不要使用硬编码11,也不应当使用sizeof(str)-1或10
printf("%sn",buf);
}
【转载】http://kapok.blog.51cto.com/517862/113471
【2】.返回值、缓冲区问题
snprintf函数的返回值
sprintf函数返回的是实际输出到字符串缓冲中的字符个数,包括null结束符。而snprintf函数返回的是应该输出到字符串缓冲的字符个数,所以snprintf的返回值可能大于给定的可用缓冲大小以及最终得到的字符串长度。看代码最清楚不过了:
char tlist_3[10] = {0};
int len_3 = 0;
len_3 = snprintf(tlist_3,10,"this is a overflow test!\n");
printf("len_3 = %d,tlist_3 = %s\n",len_3,tlist_3);
上述代码段的输出结果如下:
//////////////////////////////////////////////
// 输出的数据:"25", "this is a".
len_3 = 25, tlist_3 = this is a
所以在使用snprintf函数的返回值时,需要小心慎重,避免人为造成的缓冲区溢出,不然得不偿失。
snprintf函数的字符串缓冲
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
上面的函数原型大家都非常熟悉,我一直以为snprintf除了多一个缓冲区大小参数外,表现行为都和sprintf一致,直到今天遇上的bug。在此之前我把下面的代码段的两个输出视为一致。
char tlist_1[1024] = {0},tlist_2[1024]={0};
char fname[7][8] = {"a1","b1","c1","d1","e1","f1","g1"};
int i = 0, len_1,len_2 = 0;
len_1 = snprintf(tlist_1,1024,"%s;",fname[0]);
len_2 = snprintf(tlist_2,1024,"%s;",fname[0]);
for(i=1;i<7;i++)
{
len_1 = snprintf(tlist_1,1024,"%s%s;",tlist_1,fname[i]);
len_2 = sprintf(tlist_2,"%s%s;",tlist_2,fname[i]);
}
printf("tlist_1: %s\n",tlist_1);
printf("tlist_2: %s\n",tlist_2);
可实际上得到的输出结果却是:
////////////////////////////////////////////
// snprintf()会清除缓冲区,sprintf()不会清除缓冲区;
tlist_1: g1;
tlist_2: a1;b1;c1;d1;e1;f1;g1;
【转载】http://my.oschina.net/shelllife/blog/177279
【3】.三个打印函数printf()/sprintf()/snprintf()区别
先贴上其函数原型
printf( const char *format, ...) 格式化输出字符串,默认输出到终端-----stdout
sprintf(char *dest, const char *format,...) 格式化输出字符串到指定的缓冲区
snprintf(char *dest, size_t size,const char *format,...) 按指定的SIZE格式化输出字符串到指定的缓冲区
printf()函数在这就不再讨论,这里主要讨论sprintf()与snprintf()的用法及区别,
#include "stdafx.h"
#include <stdio.h>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
char *p1="China";
char a[20];
sprintf(a,"%s",p1);
printf("%s\n",a);
//////////////////////////
memset(a,0,sizeof(a));
_snprintf(a,3,"%s",p1);
printf("%s\n",a);
printf("%d\n",strlen(a));
return 0;
}
结果输出:
China
Chi
3
分析:
sprintf(a,"%s",p1) 把p1字符串拷贝到数组a中('\0'也拷贝过去了)。
snprintf(a,3,"%s",p1) 拷贝P1中前3个字符到数组a中,并在末尾自动添加'\0'。
sprintf属于I/O库函数,snprintf函数并不是标准c/c++中规定的函数,但是在许多编译器中,厂商提供了其实现的版本。在gcc中,该函数名称就snprintf,而在VC中称为_snprintf。 如果你在VC中使用snprintf(),会提示此函数未声明,改成_snprintf()即可。
注意点:
1 sprintf是一个不安全函数,src串的长度应该小于dest缓冲区的大小,(如果src串的长度大于或等于dest缓冲区的大小,将会出现内存溢出。)
2 snprintf中源串长度应该小于目标dest缓冲区的大小,且size等于目标dest缓冲区的大小。(如果源串长度大于或等于目标dest缓冲区的大小,且size等于目标dest缓冲区的大小,则只会拷贝目标dest缓冲区的大小减1个字符,后加'\0';该情况下,如果size大于目标dest缓冲区的大小则溢出。)
3 snprintf ()函数返回值问题, 如果输出因为size的限制而被截断,返回值将是“如果有足够空间存储,所应能输出的字符数(不包括字符串结尾的'\0')”,这个值和size相等或者比size大!也就是说,如果可以写入的字符串是"0123456789ABCDEF"共16位,但是size限制了是10,这样 snprintf() 的返回值将会是16 而不是10!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
【转载】http://www.cnblogs.com/ningskyer/articles/4037964.html
【4】. <string.h> 、<string>
<string.h> 是C语言的一个【头文件】,里
面有 定义了 很多操作字符串的【方法】,例如:
strcpy(), strncpy(),
strcat(), stncat(),
strcmp(), strncmp(),
// 找子串
strstr()
strlen()
memset()
<string> 里面定义了一个 string 类,其功能和一容器类似。
string类的方法有:
at(), append(), assign(), begin(), end(),
earse(), find(), insert(),
clear(), length(), c_str(),
// Returns whether the string is empty
empty(),
push_back(),
size(),
string 类定义的对象,可以直接加上字符串。
要访问string类对象中保存的字符串,需要调用类的c_str()方法。
----------------------------------------------------------------------------
-----------------------------------------------------
strlen,sizeof()
char mystr[100]="test string";
defines an array of characters with a size of 100 chars, but the C string with which mystr has ben initialized has a length of only 11 characters.
Therefore, while sizeof(mystr) evaluates to 100,
strlen(mystr) returns 11.
【5】.C里操作字符串很高效,但也很麻烦。
1. char * strcpy ( char * destination, const char * source );
最常用的函数,但是却不安全,原因在于,一是要destination有足够的空间,二是要保证source和destination指向的空间没有overlap。
2. int sprintf ( char * str, const char * format, ... );
也许要问,这个怎么用于字符串拷贝呢?可以这么用 sprintf(dest, "%s", src); 但是要调用者保证dest有足够的内存存放src。
3. char * strncpy ( char * destination, const char * source, size_t num );
比起strcpy,多了个长度的控制。从source拷贝num个字符到destination。如果source里不够num字符怎么办呢?会补充0。
一个典型的用法是:
char buf[MAX];
strncpy(buf, src, MAX-1);
这段代码的本意是,一个长为MAX的buf,最多也就放MAX-1个字符,最后一个位置放‘\0'。因此最多能从src里拷贝MAX-1个字符,如果src里没这么多,剩余的填充0就是了。
但是这样做就安全了么?不是,如果src刚好MAX-1个字符。注意到strncpy只复制了MAX-1个字符,最后一个位置未知,有潜在的隐患。下段代码可以诠释:
#define MAX 4
char buf[MAX];
char* src="123";
memset(buf, 'x', MAX);
// solution 1. memset(buf, 0, MAX);
strncpy(buf, src, MAX-1);
// solution 2. buf[MAX-1] = '\0';
printf("%s\n", buf);
有两个办法可以解决:
1.调用strncpy之前memset为0,有点浪费。
2.在strncpy之后对最后一个字符赋值为0。
都可以,但不够优雅。
4. int snprintf( char *buffer, int buff_size, const char *format, ... );
用作字符串拷贝的用法:
char buf[MAX];
snprintf(buf, sizeof(buf), "%s", src);
即安全,又简洁。
你可能会关心:如果src的长度大于dest(buf)呢?这个是另外一个问题,这里需要的是安全的字符串拷贝,在C语言里,如果一个字符串指针指向的内存没有结尾字符'\0',是非常危险的。
snprintf会把buf的最后一个位置保留为'\0'。
关于返回值:如果当前buf够用,返回实际写入的字符数;如果不够用,返回将要写入的字符数。换句话说,返回值就是传入的字符数目。
假设当前的buf[4].
待写入 实际写入 返回值
12 12 2 够用
123 123 3 够用
1234 123 4 不够用
12345 123 5 不够用
sprintf/snprintf的另外一个用法:
itoa不是ANSI C或C++的一部分,可以变相的用sprintf来代替:
sprintf(str,"%d",value) 转换为十进制数值。
sprintf(str,"%x",value) 转换为十六进制数值。
sprintf(str,"%o",value) 转换为八进制数值。
【转载】http://blog.csdn.net/kadwf123/article/details/7819439
【6】.C++危险的函数 strcpy strncpy
1.strcpy
函数原型为char *strcpy(char *dest,const char *src);
函数说明:strcpy函数会将参数src字符串拷贝至参数dest所指的地址。
参数说明:dest,我们说的出参,最终得到的字符串。src,入参,因为其有const修饰。表示在此函数中不会也不能修改src的值。
返回值:返回dest字符串的起始地址。
附加说明:如果参数dest所指的内存空间不够大,可能会造成缓冲溢出的错误情况。
特别强调:此函数很好用,可是它也很危险。如果在用的时候加上相关的长度判断,则会大大降低出此错误的危险。此函数还有一个特点,就是它在把字符串b拷贝到字符串a的时候,会在拷贝的a字符串的末尾加上一个\0结束标志。这个不同于strncpy()函数。
例如:
#include<string.h>
main(){
char a[30]="string(1)";
char b[]="string(2)";
printf("before strcpy():%s\n",a);
if(strlen(b)<strlen(a))
{
printf("after strcpy():%s\n",strcpy(a,b));
}
}
2.strncpy
函数原型为:char *strncpy(char *dest,const char *src ,size_t n);
函数说明:strncpy会将参数src字符串拷贝前n个字符至参数dest所指的地址。
返回值:返回参数dest的字符串起始地址。
特别强调:不要以为这个函数是个好东西,往往在定位问题时,它是罪魁祸首,到顶了,它是静态的容值函数,程序跑起来你就等着dbug吧。
strncpy的正确用法:
strncpy(dest, src, sizeof(dest));
dest[sizeof(dest)-1] = ‘\0’;
size一定要用sizeof(dest)或sizeof(dest)-1,不可误用sizeof(src).
手工填0. 务必要把dest的最后一个字节手工设置为0. 因为strncpy仅在src的长度小于dest时,对剩余的字节填0.
性能问题。当dest长度远大于src时,由于strncpy会对多余的每个字节填0,会有很大的性能损失。
返回值。strncpy返回dest,因而无法知道拷贝了多少个字节。
【转载】http://blog.csdn.net/kadwf123/article/details/7819052
strcpy
char * strcpy ( char * destination, const char * source );
Copy string
Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).
To avoid overflows, the size of the array pointed by destination shall be long enough to contain the same C string as source (including the terminating null character), and should not overlap in memory with source.
/* strcpy example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[]="Sample string";
char str2[40];
char str3[40];
// 拷贝的时候,包含了最后的字符串结束符
strcpy (str2,str1);
strcpy (str3,"copy successful");
printf ("str1: %s\nstr2: %s\nstr3: %s\n",str1,str2,str3);
return 0;
}
--------------------------------------------------------------------------------
strncpy
char * strncpy ( char * destination, const char * source, size_t num );
Copy characters from string
Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.
No null-character is implicitly appended at the end of destination if source is longer than num. Thus, in this case, destination shall not be considered a null terminated C string (reading it as such would overflow).
destination and source shall not overlap (see memmove for a safer alternative when overlapping).
/* strncpy example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[]= "To be or not to be";
char str2[40];
char str3[40];
/* copy to sized buffer (overflow safe): */
strncpy ( str2, str1, sizeof(str2) );
/* partial copy (only 5 chars): */
strncpy ( str3, str2, 5 );
// 需要你手动添加字符串结束符!!!!!
str3[5] = '\0'; /* null character manually added */
puts (str1);
puts (str2);
puts (str3);
return 0;
}
Output:
To be or not to be
To be or not to be
To be
talk about string,char的更多相关文章
- C++中int,float,string,char*的转换(待续)
//float转string char a[100]; float b = 1.234; sprintf(a, "%f", b); string result(a); //int转 ...
- C#入门篇6-6:字符串操作 StringBiulder string char[]之间的转化
//StringBiulder string char[]之间的转化 public static void Fun3() { StringBuilder sb = new StringBuilder( ...
- CString string char* char 之间的字符转换(多种方法)
在写程序的时候,我们经常遇到各种各样的类型转换,比如 char* CString string 之间的互相转换.首先解释下三者的含义. CString 是一种很有用的数据类型.它们很大程度上简化了MF ...
- C++ wstring string char* wchar_t相互转换
标签: stringwstringwchar_tcharc++2013-12-19 00:29 3721人阅读 评论(0) 收藏 举报本文章已收录于: C++知识库 分类: C/C++(50) 1. ...
- string,char*,int 之间的转化
c++中经常遇到string,char*,int之间的相互转化,今天就来整理一下. 以下是转载并修改的内容: 以下是常用的几种类型互相之间的转换 string 转 int先转换为char*,再使用at ...
- 【转】CString,string,char*综合比较
(一) 概述 1.string和CString均是字符串模a板类: 2.string为标准模板类(STL)定义的字符串类,已经纳入C++标准之中: 3.CString(typedef CString ...
- mfc CString,string,char* 之间的转换
知识点: CString转char*,string string转char*,CString char* 转CString,string 一.CString转char*,string //字串转换测试 ...
- (c++) int 转 string,char*,const char*和string的相互转换
一.int 和string的相互转换 1 int 转化为 string c++ //char *itoa( int value, char *string,int radix); // 原型说明: / ...
- (C/C++) string / *char / int 基本轉換
網路上有許 string / *char / integer 基本轉換方式 string 與 *char 互相轉換的方法 /* string to *char */ string ssbuf1 = & ...
- string char * const char *之间的互相转换
string -> const char * 用str的c_str()方法或者data()方法均可,这个两个方法返回值为cong char * string str = "hel ...
随机推荐
- 接口interface实现与显示实现
接口实现: interface IMath { void Add(int x, int y); } public class MathClass : IMath { public void Add(i ...
- vertx-mysql-client/java/
Reactive MySQL Client是MySQL的客户端,它具有直接的API,专注于可伸缩性和低开销. 特征 事件驱动 轻巧的 内置连接池 准备查询缓存 游标支持 行流 RxJava 1和RxJ ...
- OpenJDK下SpringBoot使用HttpSession时页面打开卡住
近期将一个老项目向ARM版的CentOS7移植时,遇到了SpringBoot启动顺利,但访问页面卡住的问题.由于是aarch64架构,因此使用了openjdk,这个项目之前在x86_64环境下一直是用 ...
- MySql数据库中正则表达式
命令 说明 ^ 在字符的开启处进行匹配 $ 在字符的末尾处进行匹配 . 匹配任何字符(包括回车和新行) [-.] 匹配括号内的任意单个字符 [m-n] 匹配m到n之间的任意单个字符,例如[0-9],[ ...
- pycharm工具设置py模板
直接上截图把,更加明确清晰 (a)shebang行 #!/usr/bin/python3 (b)预定义的变量要扩展为格式为$ {<variable_name>}的相应值. 可用的预定义文件 ...
- QT4.8.7和VS2010环境搭建及使用
(一)环境搭建 首先下载QT4.8.7的安装包.QT Addin 1.11插件和VS2010安装包.第一步:安装好VS2010第二步:安装QT4.8.7(qt-opensource-windows-x ...
- java多线程执行时主线程的等待
1.通过thread.join()方式,注意:如果有多个子线程,需要将全部的线程先start,然后再join.代码示例如下: public class Main { public static ...
- 对Quene中的队列的状态进行操作
查看队列的状态(包括队列的满状态.空.元素个数等等) import multiprocessing quene = multiprocessing.Queue(3) quene.put(12) que ...
- 201777010217-金云馨《面向对象程序设计(Java)》第十二周学习总结
内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p/ ...
- 201777010217-金云馨《面向对象程序设计Java》第四周总结学习
2019面向对象程序设计(Java)第4周学习指导及要求 项目 内容 这个作业属于哪个课程 <任课教师博客主页链接>https://www.cnblogs.com/nwnu-daizh/ ...