切勿使用:指向局部变量的指针作为函数的返回指针!
今天码代码的时候,出现了一个诡异的问题:
首先:函数 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楼所说的,也得到了正确的值,请不要高兴,这是因为那块内存还没有被占用,值还没有改变,所以你得到了正确的值,有一种情况是可以返回局部指针的,就是在堆上动态分配存储空间,这些空间在函数结束时不会自动释放,但是需要自己释放,所以得记住,要是忘记了就漏掉了。