在linux c編程中,拷貝函數(shù)可以說是無處不用,結(jié)合我最近的一些實(shí)踐,簡單研究一下這幾個(gè)函數(shù)。說說實(shí)際使用中容易出錯(cuò)的地方。
strcpy: 最常用的字符串拷貝函數(shù),但是要注意這個(gè)函數(shù)不會(huì)自己判斷源字符串是否比目標(biāo)空間大,必須要程序員自己檢查,否則很容易造成拷貝越界,下面是幾個(gè)例子:
char *a = “0123456789”, *b = “abcdefghijk”;
char c[5];
輸出: strcpy(c,a)=0123456789 //數(shù)組c只有5個(gè)字節(jié)的空間,但是經(jīng)過strcpy后a的剩余字符也拷貝過去了,如果c后面是系統(tǒng)程序空間,那就要出問題了。
strncpy:strcpy的改進(jìn)版本,多了一個(gè)拷貝長度的參數(shù)。需要注意的是長度參數(shù)應(yīng)該為目的空間的大小,并且這個(gè)函數(shù)不會(huì)自己附加字符串結(jié)束符‘\0’,要自己加。看下面的例子:
strncpy(c,b,strlen(b))=abcdefghijkw //拷貝長度不對(duì),還是越界
strncpy(c,a,sizeof(c))=01234fghijkw //拷貝長度正確,但是因?yàn)榭截愰L度內(nèi)不包括‘\0’,所以輸出的時(shí)候還是會(huì)把原本的空間內(nèi)容輸出,知道遇到一個(gè)結(jié)束符‘\0’。
所以正確的做法應(yīng)該是: strncpy(c, a, sizeof(c)-1); c[5] = ‘\0’;
memcpy: 最后說一下這個(gè)函數(shù),這個(gè)函數(shù)是個(gè)很強(qiáng)大的工具,因?yàn)樗梢院唵蔚母鶕?jù)字節(jié)數(shù)拷貝內(nèi)存空間內(nèi)容,所以經(jīng)常被用于結(jié)構(gòu)體的拷貝。需要注意兩點(diǎn):1、memcpy拷貝的時(shí)候源空間的長度和目標(biāo)空間的長度都需要程序員自己考慮,如果按照源空間的長度拷貝,要注意是否會(huì)寫溢出,如果按照目標(biāo)空間的長度拷貝,則要考慮是否造成讀溢出(把不該拷貝的內(nèi)容也拷貝過去了),而讀溢出在某些系統(tǒng)環(huán)境下(比如AIX),可能會(huì)造成coredump(當(dāng)讀到不該讀的地址);2、源空間和目標(biāo)空間不能重疊。如下例:
char src1[] = “src1”, src2[]=“source2, this is a long src”;
char dest[] = “destination”;
輸出:
memcpy(dest, src1, strlen(dest)) = src1 //讀越界
memcpy(dest, src2, strlen(src2)) = source2, this is a long srcis is a long src //寫越界
memcpy(dest, dest+2, strlen(dest2) = stination // 重疊,結(jié)果是混亂
copy函數(shù)的使用細(xì)節(jié)
strcpy是拷貝字符串,以\0為標(biāo)志結(jié)束(即一旦遇到數(shù)據(jù)值為0的內(nèi)存地址拷貝過程即停止)
strcpy的原型為
char *strcpy(char *dest, const char *src)
而memcpy是給定來源和目標(biāo)后,拷貝指定大小n的內(nèi)存數(shù)據(jù),而不管拷貝的內(nèi)容是什么(不僅限于字符)
memcpy的原型為
void *memcpy(void *dest, const void *src, size_t n);
C語言中的exit()函數(shù),括號(hào)中有時(shí)為1,有時(shí)為0在main函數(shù)中我們通常使用return (0);這樣的方式返回一個(gè)值。
但這是限定在非void情況下的也就是void main()這樣的形式。
exit()通常是用在子程序中用來終結(jié)程序用的,使用后程序自動(dòng)結(jié)束跳會(huì)操作系統(tǒng)。
但在如果把exit用在main內(nèi)的時(shí)候無論main是否定義成void返回的值都是有效的,并且exit不需要考慮。括號(hào)中有時(shí)為1,有時(shí)為0
遇到1 就代表出錯(cuò)后結(jié)束程序~其實(shí)不一定是1的~非0值也可以!遇到0就表示正常退出~~
例如:
你定義一個(gè)文件的指針fp
if (fp=fopen (“c:\\abc.txt”,“r”))==NULL)
{
printf(“Can not open the file.\n”);
exit(1);
}
如果文件不存在那么就跳出程序了 如果用struct的話,注意以下幾點(diǎn):
1.盡量使用占為少的類型,如,在可能的時(shí)候使用short代替int
2.按數(shù)據(jù)類型本身占用的位置從大到小排列
例如
struct{
int a;
char b;
int c;
char d;
}
應(yīng)該寫為:
struct{
int a;
int c;
char b;
char d;
};
一般的編譯器會(huì)采取一種叫做填充(padding)的方式來對(duì)齊數(shù)據(jù)。
以一個(gè)機(jī)器字(比如在32-bit的機(jī)器上為word = 32bit.)為基礎(chǔ)進(jìn)行填充。
像上面的struct會(huì)這樣存儲(chǔ):
(xp,vc6.0)
a 32bit = 4byte
c 32bit = 4byte
b,d,*,* 32bit = 4byte
其中,兩個(gè)*號(hào)表示填充(但是并沒有使用那兩個(gè)位置。)
system函數(shù):參數(shù)放入的是一個(gè)命令。
#include 《sys/types.h》
#include 《sys/wait.h》
#include 《errno.h》
#include 《unistd.h》
int system(const char * cmdstring)
{ pid_t pid;
int status;
if(cmdstring == NULL){
return (1);
}
if((pid = fork())《0){
status = -1;
}
else if(pid = 0){
execl(“/bin/sh”, “sh”, “-c”, cmdstring, (char *)0);
-exit(127); //子進(jìn)程正常執(zhí)行則不會(huì)執(zhí)行此語句
}
else{
while(waitpid(pid, &status, 0) 《 0){
if(errno != EINTER){
status = -1;
break;
}
}
}
return status;
}
先分析一下原理,然后再看上面的代碼大家估計(jì)就能看懂了:
當(dāng)system接受的命令為NULL時(shí)直接返回,否則fork出一個(gè)子進(jìn)程,因?yàn)閒ork在兩個(gè)進(jìn)程:父進(jìn)程和子進(jìn)程中都返回,這里要檢查返回的pid,fork在子進(jìn)程中返回0,在父進(jìn)程中返回子進(jìn)程的pid,父進(jìn)程使用waitpid等待子進(jìn)程結(jié)束,子進(jìn)程則是調(diào)用execl來啟動(dòng)一個(gè)程序代替自己,execl(“/bin/sh”, “sh”, “-c”, cmdstring, (char*)0)是調(diào)用shell,這個(gè)shell的路徑是/bin/sh,后面的字符串都是參數(shù),然后子進(jìn)程就變成了一個(gè)shell進(jìn)程,這個(gè)shell的參數(shù)
是cmdstring,就是system接受的參數(shù)。在windows中的shell是command,想必大家很熟悉shell接受命令之后做的事了。
rewind函數(shù)用于把fp所指文件的內(nèi)部位置指針移到文件頭
評(píng)論
查看更多