1. 程式人生 > >strcpy實現機制,陣列越界-->memcpy,memmove

strcpy實現機制,陣列越界-->memcpy,memmove

先來看一個常見的C++面試題目:

void test()
{
 charstring[10],str1[10];
 int i;
 for(i=0; i<10; i++)
 {
  str1[i] ='a';
 }
 strcpy( string, str1 );
}

這個題目錯誤在於哪裡?

答:陣列越界,在對str[i] = 'a';迴圈賦值過程中最後沒有'/0'識別符號,導致在strcpy進行拷貝的時候越界,會導致程式崩潰,

看strcpy的內部實現:

char *  strcpy(char * dst, const char * src)
{
        char * cp = dst;

        while( *cp++ = *src++ )
                ;               /* Copy src over dst */

        return( dst );
}
看到沒,是直接賦值!沒有引數檢測assert(dst != NULL);和assert(src != NULL));,也沒有'\0'字串結尾判斷。

現在我們將程式改一下,如下:

char* strcpy_1(char* dest, const char* src)
{
	char * ret = dest;
	memmove(ret, src, strlen(src)+1);
	return ret;
}
void test()
{
<span style="white-space:pre">	</span>char string[10],str1[10];
	 int i;
	 for(i=0; i<10; i++)
	 {
		 str1[i] ='a';
		
	 }
	 printf("str1 = %s,str1 address = %d\n", str1, str1);
	 strcpy_1( string, str1 );
	 //strcpy(string,str1);
	 printf("str = %s,str1 address = %d\n", str1, str1);
	 printf("string = %s,string address = %d\n", string, string);
	 getchar();
	 getchar();
	 return 0;
}
編譯執行結果如下圖所示


從列印資訊就可以看出,陣列str1後面已經是亂碼了。對比str1與string的地址可以看出,相差20個位元組,在拷貝後str1地址後的第21個位元組起被string覆蓋了。

同樣,用memcpy也會出現這種情況。這裡考慮不考慮記憶體重疊都無濟與事了,所以在進行逐個賦值時最好加上‘\0’,我改過後的程式為:

void test()
{
 charstring[10],str1[10];
 int i;
 for(i=0; i<10; i++)
 {
      if (i == (sizeof(str1)-1))
      {
	str1[i] = '\0';
	break;
      }
    str1[i] ='a';
 }
 strcpy( string, str1 );
}

附:memcpy與memove的實現細節

1:系統的memcpy沒有考慮記憶體重疊的問題,其程式碼為:

void *  memcpy (void * dst,const void * src,size_tcount)
{
        void * ret = dst;
        /*
         * copy from lower addresses to higher addresses
         */
        while (count--) {
                *(char *)dst = *(char *)src;
                dst = (char *)dst + 1;
                src = (char *)src + 1;
        }
        return(ret);
}
2:考慮記憶體重疊的函式為memove,其程式碼為:
void *  memmove (void * dst, const void * src,size_t count )
{
        void * ret = dst;
        if (dst <= src || (char *)dst >= ((char *)src + count)) {
                /*
                 * Non-Overlapping Buffers
                 * copy from lower addresses to higher addresses
                 */
                while (count--) {
                        *(char *)dst = *(char *)src;
                        dst = (char *)dst + 1;
                        src = (char *)src + 1;
                }
        }
        else {
                /*
                 * Overlapping Buffers
                 * copy from higher addresses to lower addresses
                 */
                dst = (char *)dst + count - 1;
                src = (char *)src + count - 1;


                while (count--) {
                        *(char *)dst = *(char *)src;
                        dst = (char *)dst - 1;
                        src = (char *)src - 1;
                }
        }
        return(ret);
}

以下摘自:http://www.cnblogs.com/xulb597/archive/2012/05/23/2515215.html

strcpy、memcpy、memmove的區別

strcpy和memcpy都是標準C庫函式,它們有下面特點:
strcpy提供了字串的複製。即strcpy只用於字串複製,並且它不僅複製字串內容外,還會複製字串的結束符。
strcpy的函式原型是:char* strcpy(char* dest, const char* src);

memcpy只提供一般的記憶體複製,即memcpy對於需要複製的內容沒有限制,因此用途更廣。
memcpy的函式原型是:void *memcpy(void *dest,  const char* src,  size_t count);

strcpy 和 memcpy主要有以下三方面的區別:
1、複製的內容不同。strcpy只能複製字串,而memcpy可以複製任意內容,例如字串、整型、結構體、類等。
2、複製的方法不同。strcpy不需要指定長度,它遇到被複制字串的結束符"\0”才結束,所以容易溢位。memcpy則是根據第3個引數決定複製的長度。
3、用途不同。通常在複製字串時用strcpy,而需要複製其它型別的資料是用memcpy。

memcpy 和 memmove 都是C語言中的庫函式,在庫函式 string.h中,其原型相似,它們都是從src所指向的記憶體中複製count個位元組到dest所指記憶體中。並返回dest的值。
當源記憶體區域 和 目標記憶體區域無交叉重疊時,兩者的結果是一樣的,但如果有交叉呢?
memcpy是從src的其實部分開始複製,所以雖然第一種情況下沒有問題,但如果遇到第二種情況,則會發生錯誤,交叉部分的src內容就會被覆蓋掉了。
而memmove則由於採用不同的複製機制,所以可以正確處理第二種情況。

相關推薦

strcpy實現機制,陣列越界-->memcpy,memmove

先來看一個常見的C++面試題目: void test() {  charstring[10],str1[10];  int i;  for(i=0; i<10; i++)  {   str1[i] ='a';  }  strcpy( string, str1 ); }

[c語言]對各種字串庫函式的實現strcpy,strcat,strstr,strchr,strcmp,memcpy,memmove

1.模擬實現strcpy //1.模擬實現strcpy(字串拷貝) #include<stdio.h> #include<assert.h> char * my_strcpy(char *dest,const char *str) {

strcpy strcat strstr strchr strcmp memcpy memmove的自我編譯

  1.實現strcpy  #include<stdio.h> #include<assert.h> char* m_strcpy(char* dest, const char* src) { char *ret = dest; assert(

memset memcmp memcpy memmove 自己實現

assert for source null 方式 size_t res 取值 從後往前 memset memcmp memcpy memmove 自己實現 memset #include <stdio.h> #include <memory.h>

memcpy memmove區別和實現(如何處理記憶體重疊問題)

memcpy與memmove的目的都是將N個位元組的源記憶體地址的內容拷貝到目標記憶體地址中。 但當源記憶體和目標記憶體存在重疊時,memcpy會出現錯誤,而memmove能正確地實施拷貝,但這也增加了一點點開銷。 memmove的處理措施: (1)當源記憶體的首地址等於目標記憶體的首地址時,不進行任何拷貝

mem系列函式(memset memcpy memmove) 和str系列函式(strlen strcpy strcmp strcat strstr strtok)

 void *memset(void *s, int ch, size_t n);  函式解釋:將s中前n個位元組 (typedef unsigned int size_t )用 ch 替換並返回 s 。  memset:作用是在一段記憶體塊中填充某個給定的值,它是對較大的

關於strcpy陣列越界的問題

使用平臺是Ubuntu10.0 ,GCC編譯器 我們先看下面這段程式, #include <stdio.h> #include <string.h> int mian(){ char str1[] = "abcd" ; char s

關於Java與c++隱藏、重寫不同實現機制的探討

tail namespace 文獻 ide archive pretty proc font 分開 一、文章來由 本人如今用c++很多其它。可是曾經Java也寫過不少,Java和c++非常像,可是深入挖一些,Java跟c++的差別非常大,就拿剛剛發的另

shiro中的reaml理解及實現機制

rmi 我們 身份認證 理解 例子 generated std dbutil sets shiro中的reaml非常重要,所有的身份數據驗證都在reaml中實現。可以把Realm看成DataSource,即安全數據源。 Shiro從Realm

Java虛擬機 - 多態性實現機制

虛擬機 () fat 第一次 實際類型 私有方法 base 動態 技術分享 【深入Java虛擬機】之五:多態性實現機制——靜態分派與動態分派 方法解析 Class文件的編譯過程中不包含傳統編譯中的連接步驟,一切方法調用在Class文件裏面存儲的都只是符號引用,而

[06] Session實現機制以及和Cookie的區別

但是 session存儲 請求 pri com 無法 體驗 -c data 1、為什麽有Session和Cookie根據早期的HTTP協議,每次request-reponse時,都要重新建立TCP連接。TCP連接每次都重新建立,所以服務器無法知道上次請求和本次請求是否來自於

postgresql的日誌實現機制

此外 一個 進行 比較 批量 原子 註意 機制 依次 1、事務的概念 事務是從實際生活中引入數據庫的一個概念,即事務內的操作,要麽全做,要麽全不做。就像銀行轉賬一樣,當從一個帳戶轉出一部分錢之後,就必須在另一個帳戶中存入相同數目的錢,若是轉出錢之後,事務中止了,沒有在另

深入分析_linux_spinlock_實現機制【轉】

源碼 idt 內存 獲取 編寫 存在 www 浪費 理論 轉自:http://blog.csdn.net/electrombile/article/details/51289813 在 x86 平臺上,spinlock 主要通過處理器的 lock 指令前綴實現當某個線

JDK動態代理[3]----WeakCache緩存的實現機制

true sta 因此 ole cti 賦值 try pri 否則 上一篇我們分析了Proxy類的內部是怎樣產生代理類的,我們看到了Proxy內部用到了緩存機制,如果根據提供的類加載器和接口數組能在緩存中找到代理類就直接返回該代理類,否則會調用ProxyClassFacto

動態代理的使用和實現機制

provide imp .com 獲取 機制 代理類 long .html pack 工作中很久沒有接觸動態代理,之前的學習也有些模糊,導致有些遺忘,這裏記錄下個人對動態代理的理解,如有讀者發現問題多多指正吧。就java而言對於動態代理的支持多是以接口實現,其實現主要是通過

STL及一些容器底層實現機制

失效 list容器 容量 較高的 浪費 復制 處理 跳轉 strong 1、vector容器 vector的數據安排以及操作方式,與數組類似。倆這唯一的區別就是空間的運用靈活性。數組是靜態空間,一旦配置了就不能改變,vector是動態數組。在堆上分配內存。vector是動態

C++異常機制實現機制

++ 檢查 剛才 next exc 基類 判斷 需要 了解 1、C函數的調用和返回   要理解C++異常機制實現之前,首先要了解一個函數的調用和返回機制,這裏面就要涉及到ESP和EBP寄存器。我們先看一下函數調用和返回的流程。 下面是按調用約定__stdcall 調用函數

spark源碼系列之累加器實現機制及自定義累加器

大數據 spark一,基本概念 累加器是Spark的一種變量,顧名思義該變量只能增加。有以下特點: 1,累加器只能在Driver端構建及並只能是Driver讀取結果,Task只能累加。 2,累加器不會改變Spark Lazy計算的特點。只會在Job觸發的時候進行相關累加操作。 3,現有累加器的類型。相信有很

數據庫事務隔離級別和鎖實現機制

約定 表鎖 四種 back 數據庫操作 升級 數據對象 三級封鎖 pro 1. 數據庫事務處理中出現的數據不一致的情況 在多個事務並發做數據庫操作的時候,如果沒有有效的避免機制,就會出現種種問題。大體上有四種問題,歸結如下: 1.1 丟失更新 如果兩個事務都要更新數據庫一個

輕松理解MYSQL MVCC 實現機制

讀取 系統版本號 版本 根據 sql事務 結果 into arch class 輕松理解MYSQL MVCC 實現機制 轉載https://blog.csdn.net/whoamiyang/article/details/51901888 1. MVCC簡介 1