string.h裏面幾個安全函數的比較snprintf strncpy strncat

在字符串處理過程當中會經常使用到如下幾個函數
strcpy() sprintf() strcat() 
但它們都存在必定的安全隱患,相對應用的安全版本爲:
strncpy() snprintf() strncat()

int sprintf( char *buffer, const char *format, [ argument] … ) ;
int snprintf(char *str, size_t size, const char *format, ...);

此兩函數功能:把格式化的數據寫入某個字符串.
返回值:字符串長度( strlen )

首先讓咱們來看下 sprintf()函數
Example
/* sprintf example */
#include <stdio.h>

int main (int argc, char *argv[])
{
	char buffer [50];
	int n, a=5, b=3;
	n=sprintf (buffer, "%d plus %d is %d", a, b, a+b);
	printf ("[%s] is a %d char long string\n",buffer,n);
	return 0;
}
Example Output:
[5 plus 3 is 8] is a 13 char long string 

關於 sprintf() 不安全問題,主要由其參數決定,
(1) 緩衝區溢出,char *buffer多大多小難以預測.
(2) printf習慣形成的忘記第一個參數
(3) 參數對應問題,相對容易檢查

snprintf();
函數說明:最多從源串中拷貝n-1個字符到目標串中,而後再在後面加一個0。因此若是目標串的大小爲n的話,是不會溢出。
函數返回值:若成功則返回欲寫入的字符串長度,若出錯則返回負值。
#include <stdio.h>

int main()
{
     char str[10]={0,};
     snprintf(str, sizeof(str), "0123456789012345678");	//若是使用sprintf()將會出錯
	 printf("str=%s\n", str);
	 //snprintf(str, 18, "0123456789012345678");		//也能成功,可是不推薦使用
     printf("str=%s\n", str);
     return 0;
}
Example Output:
str=123456789
str=12345678901234567


提到sprintf()不得不說到在格式化時間的時候還有 sprintf 的孿生兄弟 strftime.
size_t strftime ( char * ptr, size_t maxsize, const char * format, const struct tm * timeptr );
Example:
/* strftime example */
#include <stdio.h>
#include <time.h>

int main (int argc, char *argv[])
{
	time_t rawtime;
	struct tm * timeinfo;
	char buffer [80];

	time (&rawtime);
	timeinfo = localtime ( &rawtime );

	strftime(buffer,80,"Now it's %Y%m%d%H%M%S",timeinfo);
	puts(buffer);

	return 0;
}
Example output:
Now it's 20120701170808

extern char *strcat(char *dest,char *src);
函數說明:把src所指字符串添加到dest結尾處(覆蓋dest結尾處的'\0')並添加'\0'.
src和dest所指內存區域不能夠重疊且dest必須有足夠的空間來容納src的字符串.
函數返回值:返回指向dest的指針。

extern char *strncat(char *dest,char *src,size_t n);
函數說明:把src所指字符串前n個字符添加添加到dest結尾處(覆蓋dest結尾處的'\0')並添加'\0'.
src和dest所指內存區域不能夠重疊且dest必須有足夠的空間來容納src的字符串.
函數返回值:返回指向dest的指針。

char* strncat(char *dest,char *src,size_t n)
{
	size_t dest_len = strlen(dest);
	size_t i;
	for (i = 0; i < n && src[i] != '\0' ; i++ )
	{
		dest[dest_len + i] = src[i];
	}
	dest[dest_len + i] = '\0';

	return dest;
}

char *strcat(char *strDest, const char *strSrc)
{
	char *address = strDest; 
	assert((strDest != NULL) && (strSrc != NULL)); 
	while(*strDest) 
	{ 
		strDest++; 
	} 
	while(*strDest++ = *strSrc++)
	{
		NULL; 
	}
	return address;
}


char *strcpy(char *dest, char *src);
char *strncpy(char *dest, char *src, size_t n);

strcpy只用來拷貝字符串,它遇到'\0'就結束拷貝。
strncpy將字符串src中最多n個字符複製到字符數組dest中,與strcpy不一樣只有遇到NULL才中止複製
而是多了一個條件中止,就是說若是複製到第n個字符還未遇到NULL,也中止,返回指向dest的指針
可是如n>strlen(dest)的長度,dest棧空間溢出產生崩潰異常
char *strcpy(char *dest, const char *src)
{
	char *p = dest;

	while (*src)
		*dest++ = *src++;

	*dest = '/0';
	return p;
}
strncpy 標準用法
strncpy(path,src,sizeof(path)-1);
path[sizeof(path)-1] = '\0';
len = strlen(path);
相關文章
相關標籤/搜索