2016-08-16 133 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

您的更改提供了我的代码的相同输出,这意味着它们不能解决问题。尽量减少你的提示是非常有价值的,我从中受益匪浅。非常感谢 –