[c语言]-注意创建指针时的内存区域是栈内存 or 堆内存

   之前用c语言写了个udp_socket的代码,但是一直报错,花了好长时间才找到原因,特此记录。

   上代码:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include "string.h"
 4 #include <sys/socket.h>
 5 #include <netinet/in.h>
 6 #include <unistd.h>
 7 #include <arpa/inet.h>
 8 
 9 
10 void createSockAddr(char *ip,int port ,struct sockaddr * tmp){
11     //创建sockaddr_in结构体变量
12     struct sockaddr_in addr;
13     //每个字节都用0填充
14     memset(&addr,0,sizeof(addr));
15 
16     //使用IPv4地址
17     addr.sin_family=AF_INET;
18     //具体的IP地址
19     addr.sin_addr.s_addr=inet_addr(ip);
20      //端口
21     addr.sin_port=htons(port);
22 
23     tmp=(struct sockaddr *)&addr;
24 }
25 
26 
27 int main(void)
28 {
29     /* code */
30 
31     // 1. 声明 udp socket,
32     int udp_sock=socket(AF_INET,SOCK_DGRAM,0);
33     if(udp_sock<0){
34         perror("get socket fail 
");
35         exit(EXIT_FAILURE);
36     }
37 
38     // 2. 创建本地sockaddr
39     struct sockaddr * local_addr;
40 
41     createSockAddr("127.0.0.1",9002,local_addr);
42 
43     if(local_addr==NULL){
44         perror("get local_addr fail 
");
45         exit(EXIT_FAILURE);
46     }
47 
48     // 3. 监听端口
49     int bind_result=bind(udp_sock,local_addr,sizeof(struct sockaddr_in ));
50 
51     if(bind_result == -1){
52         printf("bind fail!
");
53         return -1;
54     }
55 
56 
57     // 2. 创建server addr
58     struct sockaddr * server_addr;
59 
60     createSockAddr("127.0.0.1",2000,server_addr);
61 
62     if(server_addr==NULL){
63         perror("get server_addr fail 
");
64         exit(EXIT_FAILURE);
65     }
66 
67     // 5. 连接server
68     int conn_result=connect(udp_sock,server_addr,sizeof(struct sockaddr ));
69 
70     if(conn_result < 0 ){
71         perror("connect fail 
");
72         exit(EXIT_FAILURE);
73     }
74 
75     // 6, 发送消息
76     char * msg="hello i'm c_client";
77     size_t msg_len=strlen(msg);
78     ssize_t  w_result=sendto(udp_sock,msg,msg_len,0,server_addr,sizeof(struct sockaddr ));
79 
80     if(w_result==-1){
81         perror("send fail 
");
82         exit(EXIT_FAILURE);
83     }
84 
85     close(udp_sock);
86 
87     return 0;
88 }
View Code

  有问题的就是struct sockaddr 指针的创建方式:

  首先在 createSocketAddr函数的外部声明了一个 struct socketaddr  的指针变量 local_addr,然后想的是复用代码,就写了个 createSocketAddr 函数,将指针当做参数传进去以便赋值。

  有经验的一定会发现这种写法存在问题,并且编译器也会发出一个类似 “返回了栈内存的变量地址”的警告。

  错误的原因正是由于指针指向的数据结构是在函数createSocketAddr ( ) 内部直接创建的,所以该地址是在栈内存中,当退出函数时由于出栈会导致该地址其实属于一种“无效内存”。这种"无效内存"中的数据可能会被分配给其他数据结构从而改变了数据,或者直接产生警告或者报错。

 正确的写法应该是在堆内存中申请一块区域用来存放数据,通过指针将该结构传入函数内部中进行处理,并且执行完后由于是申请的堆内存,一定要手动free回收;

 正确的代码

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include "string.h"
 4 #include <sys/socket.h>
 5 #include <netinet/in.h>
 6 #include <unistd.h>
 7 #include <arpa/inet.h>
 8 
 9 
10 struct sockaddr_in * createSockAddr(char *ip,int port ){
11     // 使用malloc从堆内存中分配一块 struct sockaddr_in 的区域
12     struct sockaddr_in * tmp = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
13 
14     // 填充 tmp 的内存区域
15     //每个字节都用0填充
16     memset(tmp,0,sizeof(struct sockaddr_in));
17 
18     //使用IPv4地址
19     (*tmp).sin_family=AF_INET;
20     //具体的IP地址
21     (*tmp).sin_addr.s_addr=inet_addr(ip);
22      //端口
23     (*tmp).sin_port=htons(port);
24 
25     return tmp;
26 }
27 
28 
29 int main(void)
30 {
31     /* code */
32 
33     // 1. 声明 udp socket,
34     int udp_sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
35     if(udp_sock<0){
36         perror("get socket fail 
");
37         exit(EXIT_FAILURE);
38     }
39 
40     // 2. 创建本地sockaddr, 初始化指针==NULL,表示指针指向未分配的地址0x00,不能对该地址进行 (*操作),相当于指针未分配空间进行初始化;
41 
42     struct sockaddr_in * local_addr=createSockAddr("127.0.0.1",9002);;
43 
44     if(local_addr==NULL){
45         perror("get local_addr fail 
");
46         exit(EXIT_FAILURE);
47     }
48 
49     // 3. 监听端口
50     int bind_result=bind(udp_sock,(const struct sockaddr *)local_addr,sizeof(struct sockaddr_in ));
51 
52     if(bind_result == -1){
53         perror("bind fail 
");
54         exit(EXIT_FAILURE);
55     }
56 
57 
58     // 2. 创建server addr
59     struct sockaddr_in * server_addr =  createSockAddr("10.108.132.161",2000);;
60 
61 
62     if(server_addr==NULL){
63         perror("get server_addr fail 
");
64         exit(EXIT_FAILURE);
65     }
66 
67     // 5. 连接server
68     int conn_result=connect(udp_sock,(const struct sockaddr *)server_addr,sizeof(struct sockaddr_in ));
69 
70     if(conn_result < 0 ){
71         perror("connect fail 
");
72         exit(EXIT_FAILURE);
73     }
74 
75     // 6, 发送消息
76     char * msg="hello i'm c_client
";
77     
78     ssize_t  w_result=write(udp_sock,msg,strlen(msg));
79 
80     if(w_result<0){
81         perror("send fail 
");
82         exit(EXIT_FAILURE);
83     }
84 
85     free(server_addr);
86     free(local_addr);
87     close(udp_sock);
88 
89     return 0;
90 }
原文地址:https://www.cnblogs.com/zhaohuaxishi/p/14822124.html