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