[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 \n"); 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 \n"); 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!\n"); 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 \n"); 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 \n"); 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 \n"); 82 exit(EXIT_FAILURE); 83 } 84 85 close(udp_sock); 86 87 return 0; 88 }
有问题的就是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 \n"); 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 \n"); 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 \n"); 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 \n"); 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 \n"); 72 exit(EXIT_FAILURE); 73 } 74 75 // 6, 发送消息 76 char * msg="hello i'm c_client\n"; 77 78 ssize_t w_result=write(udp_sock,msg,strlen(msg)); 79 80 if(w_result<0){ 81 perror("send fail \n"); 82 exit(EXIT_FAILURE); 83 } 84 85 free(server_addr); 86 free(local_addr); 87 close(udp_sock); 88 89 return 0; 90 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!