2017-07-28 193 views
0

我有一個大字符串,我想使用它的一些片段,但我不想一定要複製它們,所以我想我可以製作一個標記有用塊的開始和長度的結構從大字符串開始,然後創建一個讀取它的函數。字符串的返回子字符串

struct descriptor { 
    int start; 
    int length; 
}; 

到目前爲止好,但是當我到寫作,我意識到,我真的不能返回塊而不復制到記憶功能......

char* getSegment(char* string, struct descriptor d) { 
    char* chunk = malloc(d.length + 1); 
    strncpy(chunk, string + d.start, d.length); 
    chunk[d.length] = '\0'; 
    return chunk; 
} 

所以問題我有分別是:

  • 有什麼辦法,我可以返回一條繩子但沒有照搬
  • 如果沒有,我該怎麼處理這個內存泄漏,因爲我複製s在堆內存中,我無法控制誰會撥打getSegment
+1

你不能只是返回'字符串+ d.start'?唯一的問題是如果有人寫入內存。其他問題將是空終止符,所以你可能需要通過傳遞新的子字符串 –

+2

來管理它,而不會損壞原始字符串,什麼都不做。你必須將沒有空終止的子字符串複製到其他空格中以終止它。你無法處理泄漏(使用該界面);你必須依靠調用者正確處理分配的內存。你可以定義'char * getSegment(const char * source,struct descriptor d,char * output)',其中調用者在'output'參數中提供的空間必須至少爲d.length + 1'字節的內存。當然,調用者也對該內存負責。 –

+0

@JonathanLeffler什麼是一個適當的接口,被調用者不需要處理內存管理? –

回答

1

回答您的兩個問題:

  1. 沒有
  2. 調用方應爲被複制字符串提供緩衝
  3. 我會親自傳遞指針descrpiptor

char* getSegment(const char* string, const char *buff, struct descriptor *d)

+0

如果我像我一樣傳遞結構我的例子是在內存中複製它?也許我對這樣的事實感到困惑,在動態語言中,對象總是通過引用傳遞的,我將結構看作是對象的等價物。 –

+0

@php_nub_qq:是的,結構被複制;不,當結構中只有兩個整數時,成本不是一個主要問題。就我個人而言,我可能會傳遞結構,而不是指向它的指針。如果結構變得更大(例如,也包含指針),那麼我會考慮將指針傳遞給結構。我也會考慮運行性能測量。「 –

1
  • 有什麼辦法,我可以返回一條繩子但沒有照搬

你說的沒錯,如果你想與任何的意想不到的許多C函數使用塊要使用以null結尾的字符數組,則必須進行復制。否則,添加終止符會修改原始字符串。

但是,如果您準備將句塊作爲固定長度來處理,那麼您可以將它們表示爲不作爲指向第一個字符和長度的指針的組合來複制。某些標準庫函數使用用戶指定的字符串長度,因此支持在沒有空終止的情況下對這些段進行操作。但是,您需要非常小心。

如果你採取這種方法,我會建議colocating指針和結構的長度。例如,

struct string_segment { 
    char *start; 
    size_t length; 
}; 

可以聲明這種類型的變量,傳遞和返回此類型的對象,並創建該類型的複合文字而沒有任何動態存儲器分配,從而避免打開任何途徑內存泄漏。

  • 如果沒有,我該怎麼處理這個內存泄漏,因爲副本是堆內存和我沒有對誰將會調用getSegment控制?

返回動態分配的對象不會自動創建一個內存泄漏 - 它只是賦予呼叫者責任以釋放分配的內存。當調用者未能滿足該責任或將其傳遞給發生內存泄漏的其他代碼時。幾個標準庫函數確實會返回動態分配的對象,在第三方庫中並不常見。規範示例(malloc()本身除外)可能是POSIX標準的strdup()函數。

如果你的函數返回一個指向動態分配對象的指針 - 無論是複製的字符串還是塊定義結構 - 那麼它應該釋放它的責任落在調用者上。當您從自己的代碼中調用該功能時,您必須確保您履行義務,但是如果已明確記錄該功能的行爲,則不能對其他呼叫者未履行義務時可能犯的錯誤承擔責任。

1

有什麼辦法,我可以返回一條繩子,而不將其複製

一個包括終止空字符,所以除非部分代碼想是尾巴,指向「一段字符串」的指針仍然是一個字符串,是不可能的。


我該怎麼處理這個內存泄漏,因爲副本是堆內存和我沒有對誰將會調用getSegment控制?

使用可變長度數組(由於C99和C11支持可選)創建臨時空間。好,直到塊的結束。在這一點上,內存被釋放,不應該被進一步使用。

char* getSegment(char* string, struct descriptor d, char *dest) { 
    // form result in `dest` 
    return dest; 
} 

使用

char *t; 
    { 
    struct descriptor des = bar(); 
    char *large_string = foo(); 
    char sub[des.length + 1u]; //VLA 
    t = getSegment(large_string, des, sub); 
    puts(t); // use sub or t; 
    } 
    // do not use `t` here, invalid pointer. 

召回大小是值得關注的。如果代碼返回大的子字符串,最好是malloc()緩衝區,並在完成時強制調用代碼釋放它。