2016-08-16 140 views
-1

我正在研究對SIP消息進行一些操作的c代碼,以便更具體地從消息的SDP主體中提取值。我不是c專業人員,但是使用我在大學課程中學到的知識,我寫了我的代碼。由雙指針指向的指針值丟失(c代碼)

問題是在函數get_m_line_f(str body)內部創建了一個雙指針並從它返回。這個雙指針指向str *類型的兩個指針。它們中的每一個都有一個char指針,它指向我從sting(該塊碰巧是m = ...... \ r \ n)所需的塊的開始以及該塊的長度。

當我檢查whith指針所指向的值時,它們是正確的,但是當我檢查返回的雙指針的值時,它們是錯誤的,事實上,您可以看到雙重內部指向的地址指針沒有改變。請檢查下面的代碼和輸出,你會更好地理解這個問題。在此先感謝

這是我的主要funtion的一部分:

int main(void) { 

str body; 
str ip; 
str ports; 
str m_line; 

str *m_line_ptr_one; 
str *m_line_ptr_two; 

str *port_ptr_one; 
str *port_ptr_two; 

str **m_lines; 
str **double_ptr_two; 

char msg[] = "INVITE sip:[email protected] SIP/2.0 \r\n" 
     "Via: SIP/2.0/UDP 10.10.1.99:5060;branch=z9hG4bK343bf628;rport\r\n" 
     "From: \"Test 15\" <sip:[email protected]>;tag=as58f4201b\r\n" 
     "To: <sip:[email protected]>\r\n" 
     "Contact: <sip:[email protected]>\r\n" 
     "Call-ID: [email protected]\r\n" 
     "CSeq: 102 INVITE\r\n" 
     "User-Agent: Asterisk PBX\r\n" 
     "Max-Forwards: 70\r\n" 
     "Date: Wed, 06 Dec 2009 14:12:45 GMT\r\n" 
     "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER,SUBSCRIBE, NOTIFY\r\n" 
     "Supported: replaces\r\n" 
     "Content-Type: application/sdp\r\n" 
     "Content-Length: 258\r\n" 
     "\r\n" 
     "v=0\r\n" 
     "o=root 1821 1821 IN IP4 10.10.1.99\r\n" 
     "s=session\r\n" 
     "c=IN IP4 10.10.1.99\r\n" 
     "t=0 0\r\n" 
     "m=audio 11424 RTP/AVP 0 8 101\r\n" 
     "m=video 12324 RTP/AVP 0 8 101\r\n" 
     "c=IN IP4 10.10.1.99\r\n" 
     "a=sendrcv\r\n"; 


body.s = msg; 
body.len = strlen(msg); 

m_lines = get_m_line_f(body); 

printf("the addresses after they are returned\naudio: %p\nvideo: %p\n",*m_lines,*(m_lines + sizeof(struct str*))); 

printf("Output from the pointer after it is returned\n %.*s\n", (*m_lines)->len,(*m_lines)->s); 
printf("Output from the pointer after it is returned\n %.*s\n", (*(m_lines + sizeof(struct str*)))->len, (*(m_lines + sizeof(struct str*)))->s); 


double_ptr_two = get_m_port(m_lines); 

的get_m_line_f(STR體)函數是

struct str **get_m_line_f(str body){ 


str m_audio; 
str *m_audio_ptr; 
m_audio_ptr = &m_audio; 

str m_video; 
str *m_video_ptr; 
m_video_ptr = &m_video; 

str **m_lines; 
m_lines = (str**)malloc(2*sizeof(str*)); 


if(m_lines == NULL){ 
    printf("cannot allocate PKG memory\n"); 
    return NULL; 
} 


int len; 

if (body.s == 0){ 
    printf("Failed to get message body\n"); 
    return NULL; 
} 


if (body.len == 0){ 
    printf("message body has zero length\n"); 
    return NULL; 
} 


for (int i=0;i<=body.len;++i){ 
    if(*(body.s+i) == 'm' && *(body.s+i+1) == '='){ 
     if(strncmp(body.s+i+2,"audio",strlen("audio")) == 0){ 
       m_audio.s = body.s+i; 
     } else if(strncmp(body.s+i+2,"video",strlen("video")) == 0){ 
      m_video.s = body.s+i; 
     } 
    } 
} 


if(m_audio.s != NULL){ 
    for(len=0;*(m_audio.s+len) != '\n';++len); 
    m_audio.len = len; 
    *(m_lines) = m_audio_ptr; 
} else{ 
    printf("No \"m=audio\" line is found\n"); 
    return NULL; 
} 

if(m_video.s != NULL){ 
     for(len=0;*(m_video.s+len) != '\n';++len); 
     m_video.len = len; 
     *(m_lines + sizeof(struct str*)) = m_video_ptr; 
    } else{ 
     printf("No \"m=video\" line is found\n"); 
     return NULL; 
    } 

printf("output from the double pointer in the function where its created\n %.*s\n", (*m_lines)->len,(*m_lines)->s); 
printf("output from the double pointer in the function where its created\n %.*s\n", (*(m_lines + sizeof(struct str*)))->len, (*(m_lines + sizeof(struct str*)))->s); 


printf("Checking the addresses to be returned\naudio: %p\nvideo: %p\n",*m_lines,*(m_lines + sizeof(struct str*))); 

return m_lines; 
} 

的STR結構很簡單:

typedef struct str{ 
    char* s; 
    int len; 
} str; 

我的代碼輸出如下:

output from the double pointer in the function where its created 
m=audio 11424 RTP/AVP 0 8 101 

output from the double pointer in the function where its created 
m=video 12324 RTP/AVP 0 8 101 

Checking the addresses to be returned 
audio: 0x7fff52db0848 
video: 0x7fff52db0830 
the addresses after they are returned 
audio: 0x7fff52db0848 
video: 0x7fff52db0830 
Output from the pointer after it is returned 
m=audio 11424 RTP/AVP 0 8 101 

m=video 12324 RTP/AVP 0 8 101 

c=IN IP4 10.10.1.99 

a=sendrcv 
+0

在生命週期結束後訪問具有自動存儲持續時間的對象的未定義行爲。 – EOF

回答

0

我修改了下面的程序。有兩個錯誤。

  • 的一個錯誤是,你如何處理m_lines,但我覺得你的困惑從思考「雙指針」,當你真的出現了 - 實際上 - 是一個指向數組的指針。

  • 有效「指向數組的指針」是m_lines。它的元素是指針。不幸的是,它們是指向局部變量m_audiom_video的指針。該存儲對於調用函數不可用。當get_m_line_f返回時,m_lines元素指向的內存不再被定義。

我通過整理風格和使用數組表示法使問題更加明顯。我的更改用//樣式註釋表示。

最壞的問題是此行:

*(m_lines + sizeof(struct str*)) = m_video_ptr; 

m_lines被定義爲str**,指針2點的指針。爲了說明陣列符號如何澄清這個問題,上述相當於

m_lines[sizeof(struct str*)] = m_video_ptr; 

這意味着你分配給m_lines[12]左右,可能你的意思是不是,絕對不是你分配什麼!

在嘗試調試時,您會打印出這些值。當然,你完全按照你指定的方式去除m_lines,對於這個簡短的瞬間,你跺腳的記憶依然存在。我改變了作業並且保留了你的印刷邏輯;它現在會顯示你期望的陌生性。

您可以改變函數來返回str而不是數組。然後你可以使用該數組,消除局部變量。 IOW,而不是

str **m_lines = malloc(2 * sizeof(str*)); // do not cast malloc 

定義m_lines

str *m_lines = calloc(2, sizeof(str)); 

這樣,

  • 你可以參考m_lines[0]m_lines[1]
  • 你分配所有存儲指了指由你回來的變量。

作爲一項規則,任何一個局部變量的地址分配是一有風吹草動。有時我們將地址傳遞給一個函數。迴歸一個,不管多麼間接,幾乎總是一個錯誤。

這是你的程序有點補丁,但不正確。您必須決定是更改函數定義還是分配堆上的m_audiom_video

#include <stdbool.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

typedef struct str { 
    char *s; // put the * by the variable. 
    int len; 
} str; 

struct str ** 
get_m_line_f(str body) 
{ 
    // initialize when defining 
    str m_audio, *m_audio_ptr = &m_audio; 
    str m_video, *m_video_ptr = &m_video; 

    str **m_lines = malloc(2 * sizeof(str*)); // do not cast malloc 

    if(m_lines == NULL){ 
    printf("cannot allocate PKG memory\n"); 
    return NULL; 
    } 

    if (body.s == NULL) { // s is a pointer 
    printf("Failed to get message body\n"); 
    return NULL; 
    } 


    if (body.len == 0){ 
    printf("message body has zero length\n"); 
    return NULL; 
    } 

    int len; 

    for (int i=0; i <= body.len; ++i) { 
    // could use 0 == memcmp(body.s+i, "m=", 2) 
    if (body.s[i] == 'm' && body.s[i+1] == '=') { 
     // use compile-time constants 
     static const char audio[] = "audio", video[] = "video"; 
     if (strncmp(body.s+i+2, audio, sizeof(audio) - 1) == 0) { 
     m_audio.s = body.s+i; 
     } else if(strncmp(body.s+i+2, video, sizeof(video) - 1) == 0) { 
     m_video.s = body.s+i; 
     } 
    } 
    } 

    if (m_audio.s != NULL) { 
    for (len=0; m_audio.s[len] != '\n'; ++len); 
    m_audio.len = len; 
    m_lines[0] = m_audio_ptr; 
    } else{ 
    printf("No \"m=audio\" line is found\n"); 
    return NULL; 
    } 

    if(m_video.s != NULL) { 
    for(len=0;*(m_video.s+len) != '\n';++len); 
    m_video.len = len; 
    if (false) { // vvv addressing error here vvv 
     *(m_lines + sizeof(struct str*)) = m_video_ptr; 
    } else { 
     m_lines[1] = m_video_ptr; 
    } 
    } else { 
    printf("No \"m=video\" line is found\n"); 
    return NULL; 
    } 

    printf("output from the double pointer in the function where its created\n %.*s\n", (*m_lines)->len,(*m_lines)->s); 
    printf("output from the double pointer in the function where its created\n %.*s\n", (*(m_lines + sizeof(struct str*)))->len, (*(m_lines + sizeof(struct str*)))->s); 


    printf("Checking the addresses to be returned\naudio: %p\nvideo: %p\n", (void*)*m_lines, (void*)*(m_lines + sizeof(struct str*))); 

    return m_lines; 
} 
+0

您的更改提供了我的代碼的相同輸出,這意味着它們不能解決問題。儘量減少你的提示是非常有價值的,我從中受益匪淺。非常感謝 –