切勿使用:指向局部变量的指针作为函数的返回指针!

今天码代码的时候,出现了一个诡异的问题:

首先:函数 pkt_analyzer 返回了一个 PktUnit类型的指针。我先把端点跑到puu赋值后的下一句,查看puu里面的内容,发现是正确的: payload_len = 7,pkt_len = 35

接着我再向下跑一步,发现puu内容就不对了: payload_len = 1514280713 ;pkt_len = 17 整个就不对了……

找了一个多小时,没发现问题出在哪儿!后来突然想到,可能是函数返回的时候出的问题,不能光看函数的立即返回结果!

果然,这是一个属于:使用指向局部变量的指针作为函数返回值的例子!

 pointer * Func{

  return pointer = & iTemp;

}

这样做会造成非常严重的后果!!!!

千万不要企图返回局变量堆栈上的指针,返回局部栈上的指针,你的指针就指向了该局部变量iTemp的地址,由于局部栈会在函数返回的时刻清栈,然而你的指针所指向的地址还是不变的。也就是说 pointer还是指向iTemp原来的那块内存,但是接着执行下来,那块内存的内容完全是不确定的!所以,导致你下次使用 函数返回指针 ret_pointer = Func(); ret_pointer的内容完全不确定,会产生灾难性后果!!

先给出问题代码:

 

#include "pkt_analyzer.h"
#include "stdio.h"
#include "string.h"
#include "malloc.h"

extern PktUnit *pkt_analyzer(char *rx_buffer, int rx_len);
                                       
int main()
{
    int i = 0;
    int payload_len = 0;
    u_int8 *my_payload = (u_int8 *)malloc(sizeof(u_int8));

    PktUnit *ppu = 0;

    char in_buffer[PKT_HDEADER_LEN + 7] = {0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0e,0x05,0x0d,0x2e,0x23,0x01,0xc2,0x0e,0x0be,0xff,0x03,0x04,0x05,0x06,0x07};

    ppu = pkt_analyzer(in_buffer,sizeof(in_buffer));

    printf("payload_len = %d\n",ppu->payload_len);
    printf("pkt_len = %d \n",ppu->pkt_len);
    printf("timestampe = %ul",ppu->pkt_hdr.timestamp);

    memcpy(my_payload, ppu->payload,sizeof(u_int8)*ppu->payload_len);

    for(i=0; i< ppu->payload_len ;i++){
        printf("%x\n", *my_payload++);
    }

    free(my_payload);
    return 0;
}
/*
 * recv_pkt_analyzer.c
 *
 *  Created on: 2014-5-7
 *      Author: fang ying
 */

/* @Function Description: Perform packet analysis
 *
 * @param
 * @param
 * @return
 */

#include "pkt_analyzer.h"
#include "stdlib.h"
#include "string.h"

#ifndef NULL
#define NULL 0
#endif

#define MakeDoubleWord(a,b,c,d,e,f,g,h)        (((u_int64)(a & 0xff) << 56 )|((u_int64)(b & 0xff) << 48)|\
                                               ((u_int64)(c & 0xff) << 40 )|((u_int64)(d & 0xff) << 32)|\
                                               ((u_int64)(e & 0xff) << 24 )|((u_int64)(f & 0xff) << 16)|\
                                               ((u_int64)(g & 0xff) << 8  )|((u_int64)(h & 0xff) << 0 ))

#define MakeWord(a,b,c,d)                    (((u_int32)(a & 0xff) << 24 )|((u_int32)(b & 0xff) << 16)|\
                                               ((u_int32)(c & 0xff) << 8 ) |((u_int32)(d & 0xff) << 0))



PktUnit *pkt_analyzer(char *rx_buffer, int rx_len){

    u_int32         get_class_id = 0;
    u_int32         get_cmd_field = 0;
    u_int64            get_timestamp = 0;
    u_int32            get_parameter = 0;
    u_int32         get_pkt_payload = 0;

    PktUnit    packet_rx;
    PktUnit *pkt_unit = NULL;

    /* first check the validity of rx buffer */
    if(rx_buffer == NULL || rx_len <= 0){
        return NULL;
    }

    get_class_id = MakeWord(rx_buffer[0],rx_buffer[1],rx_buffer[2],rx_buffer[3]);
    /* get the class identification of the rx packet */
    switch(get_class_id){
        case CMD_DATA:
            packet_rx.pkt_hdr.class_id = CMD_DATA;
            break;
        case SHORT_MSG:
            packet_rx.pkt_hdr.class_id = SHORT_MSG;
            break;
        case LONG_MSG:
            packet_rx.pkt_hdr.class_id = LONG_MSG;
            break;
        case EXTDATA_MSG:
            packet_rx.pkt_hdr.class_id = EXTDATA_MSG;
            break;
        case CMD_EXCHANGE:
            packet_rx.pkt_hdr.class_id = CMD_EXCHANGE;
            break;
        default:
            return NULL;
    }

    /* check direction */
    get_cmd_field = MakeWord(rx_buffer[8],rx_buffer[9],rx_buffer[10],rx_buffer[11]);
    if(get_cmd_field != MASTER_2_TASK){
        return NULL;
    }else{
        // fill the cmd field
        packet_rx.pkt_hdr.cmd_field = get_cmd_field;
    }

    /* get parameter field */
    get_parameter = MakeWord(rx_buffer[12],rx_buffer[13],rx_buffer[14],rx_buffer[15]);
    packet_rx.pkt_hdr.para_field = get_parameter;

    /* get timestamp information */
    get_timestamp = MakeDoubleWord(rx_buffer[20],rx_buffer[21],rx_buffer[22],rx_buffer[23],
                                rx_buffer[24],rx_buffer[25],rx_buffer[26],rx_buffer[27]);
    packet_rx.pkt_hdr.timestamp = get_timestamp;

    /* get packet length */
    packet_rx.pkt_len = rx_len;

    /* analysis packet according to class id */
    if(get_class_id == CMD_DATA){
        packet_rx.payload_len = CMD_DATA_PAYLOAD_LEN;
    }

    if(get_class_id == SHORT_MSG){
        switch(get_parameter){
            case AUDIO_250MS:
                packet_rx.payload_len = AUDIO_250MS_PAYLOAD_LEN;
                break;
            case SHORT_MSG_250MS:
                packet_rx.payload_len = SHORT_MSG_250MS_PAYLOAD_LEN;
                break;
            case SHORT_MSG_500MS:
                packet_rx.payload_len = SHORT_MSG_500MS_PAYLOAD_LEN;
                break;
            case KEYBOARD_250MS:
                packet_rx.payload_len = KEYBOARD_250MS_PAYLOAD_LEN;
                break;
            case KEYBOARD_500MS:
                packet_rx.payload_len = KEYBOARD_500MS_PAYLOAD_LEN;
                break;
            default:
                return NULL;
        }
    }

    if(get_class_id == LONG_MSG){
        switch(get_parameter){
            case LONG_MSG_500MS:
                packet_rx.payload_len = LONG_MSG_500MS_PAYLOAD_LEN;
                break;
            case LONG_MSG_750MS:
                packet_rx.payload_len = LONG_MSG_750MS_PAYLOAD_LEN;
                break;
            default:
                return NULL;
        }
    }

    if(get_class_id == EXTDATA_MSG){
        switch(get_parameter){
            case EXT_DATA_1P2K:
                packet_rx.payload_len = EXT_DATA_1P2K_PAYLOAD_LEN;
                break;
            case EXT_DATA_2P4K:
                packet_rx.payload_len = EXT_DATA_2P4K_PAYLOAD_LEN;
                break;
            case EXT_DATA_4P8K:
                packet_rx.payload_len = EXT_DATA_4P8K_PAYLOAD_LEN;
                break;
            case EXT_DATA_9P6K:
                packet_rx.payload_len = EXT_DATA_9P6K_PAYLOAD_LEN;
                break;
            case EXT_DATA_19P2K:
                packet_rx.payload_len = EXT_DATA_19P2K_PAYLOAD_LEN;
                break;
            case EXT_DATA_25P6K:
                packet_rx.payload_len = EXT_DATA_25P6K_PAYLOAD_LEN;
                break;
            case EXT_DATA_38P4K:
                packet_rx.payload_len = EXT_DATA_38P4K_PAYLOAD_LEN;
                break;
            default:
                return NULL;
        }
    }

    if(get_class_id == CMD_EXCHANGE){
        switch(get_parameter){
            case SIGNALING_400MS_RECV_MODE:
                break;
            case AUDIO_250MS_RECV_MODE:
                break;
            case SHORT_MSG_250MS_RECV_MODE:
                break;
            case SHORT_MSG_500MS_RECV_MODE:
                break;
            case KEYBOARD_250MS_RECV_MODE:
                break;
            case KEYBOARD_500MS_RECV_MODE:
                break;
            case LONG_MSG_500MS_RECV_MODE:
                break;
            case LONG_MSG_750MS_RECV_MODE:
                break;
            case EXT_DATA_1P2K_RECV_MODE:
                break;
            case EXT_DATA_2P4K_RECV_MODE:
                break;
            case EXT_DATA_4P8K_RECV_MODE:
                break;
            case EXT_DATA_9P6K_RECV_MODE:
                break;
            case EXT_DATA_19P2K_RECV_MODE:
                break;
            case EXT_DATA_25P6K_RECV_MODE:
                break;
            case EXT_DATA_38P4K_RECV_MODE:
                break;
            default:
                return NULL;
        }
    }

    /* get payload */
    packet_rx.payload = (int_8 *)malloc(sizeof(u_int8));
    //packet_rx.payload = &rx_buffer[PKT_HDEADER_LEN];
    memcpy(packet_rx.payload,&rx_buffer[PKT_HDEADER_LEN],sizeof(u_int8)*packet_rx.payload_len);
    
    pkt_unit = &packet_rx;
    return (pkt_unit);
}
/*
 * pkt_analyzer.h
 *
 *  Created on: 2014-5-7
 *      Author: fang ying
 */

#ifndef _PKT_ANALYZER_H_
#define _PKT_ANALYZER_H_

/* type defination */
typedef    char                int_8;
typedef unsigned char         u_int8;
typedef unsigned short        u_int16;
typedef unsigned int        u_int32;
typedef unsigned long long  u_int64;


typedef struct PktHeader_t{
    u_int32    class_id;        /* class identification unique number*/
    u_int32    board_id;        /* board identification */
    u_int32 cmd_field;        /* command field */
    u_int32 para_field;        /* parameter field */
    u_int64    freq_info;        /* frequency information */
    u_int32 channel_SNR;    /* SNR of the channel */
    u_int64 timestamp;        /* timestamp */

}PktHeader;


typedef struct PktUnit_t{
    PktHeader pkt_hdr;        /* packet header */
    int_8       *payload;        /* data payload */
    u_int32   payload_len;    /* packet payload length */
    u_int32   pkt_len;        /* packet total length */
}PktUnit;

/* constriant definations */
#define PKT_HDEADER_LEN        28

/* class identification */
#define CMD_DATA             0x1        /* command data unit */
#define SHORT_MSG            0x2        /* short message data unit */
#define LONG_MSG            0x3        /* long  message data unit */
#define    EXTDATA_MSG            0x4        /* extra data frame unit   */
#define CMD_EXCHANGE        0x5        /* command exchange unit   */

/* board identification */
#define MASTER_BOARD        0x0
#define TASK_BOARD            0x1

/* command field of command data unit */
#define MASTER_2_TASK        0x1
#define    TASK_2_MASTER        0x2

/******************** command data unit header explain **********************/
/* parameter field of command data unit */
#define FREQUENCY_PAYLOAD_INFO        0x1
#define    FREQUENCY_INFO_ONLY            0x2
#define    PAYLOAD_INFO_ONLY            0x3
#define    RESERVED                    0x4

#define SYN_CHECKED                    0x1
#define    RECEIVE_COMPLETE            0x2
#define    EARLY_TX_SUCESS                0x3
#define    EARLY_TX_FAILED                0x4

/******************** short and long message data unit header explain ****************/
/* parameter field of short message interact unit */
#define AUDIO_250MS            0x1
#define    SHORT_MSG_250MS        0x2
#define    SHORT_MSG_500MS        0x3
#define    KEYBOARD_250MS        0x4
#define    KEYBOARD_500MS        0x5
#define    LONG_MSG_500MS        0x6
#define    LONG_MSG_750MS        0x7
#define    EXT_DATA_1P2K        0x8
#define    EXT_DATA_2P4K        0x9
#define    EXT_DATA_4P8K        0x10
#define    EXT_DATA_9P6K        0x11
#define    EXT_DATA_19P2K        0x12
#define    EXT_DATA_25P6K        0x13
#define    EXT_DATA_38P4K        0x14

/* length constraints of message */
#define CMD_DATA_PAYLOAD_LEN                    7
#define AUDIO_250MS_PAYLOAD_LEN                    62
#define    SHORT_MSG_250MS_PAYLOAD_LEN                94
#define    SHORT_MSG_500MS_PAYLOAD_LEN                94
#define    KEYBOARD_250MS_PAYLOAD_LEN                94
#define KEYBOARD_500MS_PAYLOAD_LEN                94
#define LONG_MSG_500MS_PAYLOAD_LEN                478
#define LONG_MSG_750MS_PAYLOAD_LEN                766
#define    EXT_DATA_1P2K_PAYLOAD_LEN                574
#define EXT_DATA_2P4K_PAYLOAD_LEN                574
#define EXT_DATA_4P8K_PAYLOAD_LEN                574
#define EXT_DATA_9P6K_PAYLOAD_LEN                1152
#define EXT_DATA_19P2K_PAYLOAD_LEN                2304
#define EXT_DATA_25P6K_PAYLOAD_LEN                3456
#define EXT_DATA_38P4K_PAYLOAD_LEN                4608

/**************** command exchange unit header explain *****************/
/* parameter field of command exchange unit */
#define    SIGNALING_400MS_RECV_MODE                0x0
#define    AUDIO_250MS_RECV_MODE                    0x1
#define    SHORT_MSG_250MS_RECV_MODE                0x2
#define    SHORT_MSG_500MS_RECV_MODE                0x3
#define    KEYBOARD_250MS_RECV_MODE                0x4
#define    KEYBOARD_500MS_RECV_MODE                0x5
#define    LONG_MSG_500MS_RECV_MODE                0x6
#define    LONG_MSG_750MS_RECV_MODE                0x7
#define    EXT_DATA_1P2K_RECV_MODE                    0x8
#define   EXT_DATA_2P4K_RECV_MODE                    0x9
#define EXT_DATA_4P8K_RECV_MODE                    0x10
#define EXT_DATA_9P6K_RECV_MODE                    0x11
#define EXT_DATA_19P2K_RECV_MODE                0x12
#define EXT_DATA_25P6K_RECV_MODE                0x13
#define EXT_DATA_38P4K_RECV_MODE                0x14

#endif /* PKT_ANALYZER_H_ */

问题出在这个地方:

这里使用了指向局部变量的指针,并作为函数的返回指针。

改正后的代码如下

/*
 * recv_pkt_analyzer.c
 *
 *  Created on: 2014-5-7
 *      Author: fang ying
 */

/* @Function Description: Perform packet analysis
 *
 * @param
 * @param
 * @return
 */

#include "pkt_analyzer.h"
#include "stdlib.h"
#include "string.h"

#ifndef NULL
#define NULL 0
#endif

#define MakeDoubleWord(a,b,c,d,e,f,g,h)        (((u_int64)(a & 0xff) << 56 )|((u_int64)(b & 0xff) << 48)|\
                                               ((u_int64)(c & 0xff) << 40 )|((u_int64)(d & 0xff) << 32)|\
                                               ((u_int64)(e & 0xff) << 24 )|((u_int64)(f & 0xff) << 16)|\
                                               ((u_int64)(g & 0xff) << 8  )|((u_int64)(h & 0xff) << 0 ))

#define MakeWord(a,b,c,d)                    (((u_int32)(a & 0xff) << 24 )|((u_int32)(b & 0xff) << 16)|\
                                               ((u_int32)(c & 0xff) << 8 ) |((u_int32)(d & 0xff) << 0))



PktUnit *pkt_analyzer(char *rx_buffer, int rx_len){

    u_int32         get_class_id = 0;
    u_int32         get_cmd_field = 0;
    u_int64            get_timestamp = 0;
    u_int32            get_parameter = 0;
    u_int32         get_pkt_payload = 0;

    PktUnit    *packet_rx = (PktUnit *)malloc(sizeof(PktUnit));

    /* first check the validity of rx buffer */
    if(rx_buffer == NULL || rx_len <= 0){
        return NULL;
    }

    get_class_id = MakeWord(rx_buffer[0],rx_buffer[1],rx_buffer[2],rx_buffer[3]);
    /* get the class identification of the rx packet */
    switch(get_class_id){
        case CMD_DATA:
            packet_rx->pkt_hdr.class_id = CMD_DATA;
            break;
        case SHORT_MSG:
            packet_rx->pkt_hdr.class_id = SHORT_MSG;
            break;
        case LONG_MSG:
            packet_rx->pkt_hdr.class_id = LONG_MSG;
            break;
        case EXTDATA_MSG:
            packet_rx->pkt_hdr.class_id = EXTDATA_MSG;
            break;
        case CMD_EXCHANGE:
            packet_rx->pkt_hdr.class_id = CMD_EXCHANGE;
            break;
        default:
            return NULL;
    }

    /* check direction */
    get_cmd_field = MakeWord(rx_buffer[8],rx_buffer[9],rx_buffer[10],rx_buffer[11]);
    if(get_cmd_field != MASTER_2_TASK){
        return NULL;
    }else{
        // fill the cmd field
        packet_rx->pkt_hdr.cmd_field = get_cmd_field;
    }

    /* get parameter field */
    get_parameter = MakeWord(rx_buffer[12],rx_buffer[13],rx_buffer[14],rx_buffer[15]);
    packet_rx->pkt_hdr.para_field = get_parameter;

    /* get timestamp information */
    get_timestamp = MakeDoubleWord(rx_buffer[20],rx_buffer[21],rx_buffer[22],rx_buffer[23],
                                rx_buffer[24],rx_buffer[25],rx_buffer[26],rx_buffer[27]);
    packet_rx->pkt_hdr.timestamp = get_timestamp;

    /* get packet length */
    packet_rx->pkt_len = rx_len;

    /* analysis packet according to class id */
    if(get_class_id == CMD_DATA){
        packet_rx->payload_len = CMD_DATA_PAYLOAD_LEN;
    }

    if(get_class_id == SHORT_MSG){
        switch(get_parameter){
            case AUDIO_250MS:
                packet_rx->payload_len = AUDIO_250MS_PAYLOAD_LEN;
                break;
            case SHORT_MSG_250MS:
                packet_rx->payload_len = SHORT_MSG_250MS_PAYLOAD_LEN;
                break;
            case SHORT_MSG_500MS:
                packet_rx->payload_len = SHORT_MSG_500MS_PAYLOAD_LEN;
                break;
            case KEYBOARD_250MS:
                packet_rx->payload_len = KEYBOARD_250MS_PAYLOAD_LEN;
                break;
            case KEYBOARD_500MS:
                packet_rx->payload_len = KEYBOARD_500MS_PAYLOAD_LEN;
                break;
            default:
                return NULL;
        }
    }

    if(get_class_id == LONG_MSG){
        switch(get_parameter){
            case LONG_MSG_500MS:
                packet_rx->payload_len = LONG_MSG_500MS_PAYLOAD_LEN;
                break;
            case LONG_MSG_750MS:
                packet_rx->payload_len = LONG_MSG_750MS_PAYLOAD_LEN;
                break;
            default:
                return NULL;
        }
    }

    if(get_class_id == EXTDATA_MSG){
        switch(get_parameter){
            case EXT_DATA_1P2K:
                packet_rx->payload_len = EXT_DATA_1P2K_PAYLOAD_LEN;
                break;
            case EXT_DATA_2P4K:
                packet_rx->payload_len = EXT_DATA_2P4K_PAYLOAD_LEN;
                break;
            case EXT_DATA_4P8K:
                packet_rx->payload_len = EXT_DATA_4P8K_PAYLOAD_LEN;
                break;
            case EXT_DATA_9P6K:
                packet_rx->payload_len = EXT_DATA_9P6K_PAYLOAD_LEN;
                break;
            case EXT_DATA_19P2K:
                packet_rx->payload_len = EXT_DATA_19P2K_PAYLOAD_LEN;
                break;
            case EXT_DATA_25P6K:
                packet_rx->payload_len = EXT_DATA_25P6K_PAYLOAD_LEN;
                break;
            case EXT_DATA_38P4K:
                packet_rx->payload_len = EXT_DATA_38P4K_PAYLOAD_LEN;
                break;
            default:
                return NULL;
        }
    }

    if(get_class_id == CMD_EXCHANGE){
        switch(get_parameter){
            case SIGNALING_400MS_RECV_MODE:
                break;
            case AUDIO_250MS_RECV_MODE:
                break;
            case SHORT_MSG_250MS_RECV_MODE:
                break;
            case SHORT_MSG_500MS_RECV_MODE:
                break;
            case KEYBOARD_250MS_RECV_MODE:
                break;
            case KEYBOARD_500MS_RECV_MODE:
                break;
            case LONG_MSG_500MS_RECV_MODE:
                break;
            case LONG_MSG_750MS_RECV_MODE:
                break;
            case EXT_DATA_1P2K_RECV_MODE:
                break;
            case EXT_DATA_2P4K_RECV_MODE:
                break;
            case EXT_DATA_4P8K_RECV_MODE:
                break;
            case EXT_DATA_9P6K_RECV_MODE:
                break;
            case EXT_DATA_19P2K_RECV_MODE:
                break;
            case EXT_DATA_25P6K_RECV_MODE:
                break;
            case EXT_DATA_38P4K_RECV_MODE:
                break;
            default:
                return NULL;
        }
    }

        /* get payload */
    packet_rx->payload = (int_8 *)malloc(sizeof(u_int8));
    //packet_rx.payload = &rx_buffer[PKT_HDEADER_LEN];
    memcpy(packet_rx->payload,&rx_buffer[PKT_HDEADER_LEN],sizeof(u_int8)*packet_rx->payload_len);
    return packet_rx;
}

上面修改的地方,我定义了一个指针,并且动态申请了空间后面就对了。其思想是基于:

因为函数中的局部变量在函数调用结束后就会被释放;这句话是对的,局部变量超出其作用域后就会被释放掉
所以如果你在函数内部定义一个指针,并申请了空间;这句不怎么对,因为只查动态申请的内存都是在堆中申请,不会被释放掉

但是,如果是使用字符串指针形式,char *str = "hello world"这个叫字符串字面常量。储存在静态区,是只读!!!!的所以可以返回

 

#include<stdio.h>
 
char    *returnstr()
{
        char    *str="Hello!World!";
        printf("In returnstr, addr of str:\t%p\n", str);
        return  str; //"Hello!world!\n";
}
int     main()
{
        char *str=returnstr();
        printf("In main,      addr of str:\t%p\n", str);
        printf("%s\n", str);
        return  0;
}

 

 

 函数中的变量存储空间是在栈上分配的,函数结束时自动释放,所以不能返回这样的变量,即使你返回了,就像7楼所说的,也得到了正确的值,请不要高兴,这是因为那块内存还没有被占用,值还没有改变,所以你得到了正确的值,有一种情况是可以返回局部指针的,就是在堆上动态分配存储空间,这些空间在函数结束时不会自动释放,但是需要自己释放,所以得记住,要是忘记了就漏掉了。

 

 

posted @ 2014-05-08 19:25  fangying  阅读(1212)  评论(0编辑  收藏  举报