LINUX下的getifaddrs()函数的内存释放问题
在LINUX下获取网卡信息需要用到IOCTL或者getifaddrs
而我在用getifaddrs的时候遇到了内存方面的问题
先看相关定义:
==========
函数定义:
/* Create a linked list of `struct ifaddrs' structures, one for each
network interface on the host machine. If successful, store the
list in *IFAP and return 0. On errors, return -1 and set `errno'.
The storage returned in *IFAP is allocated dynamically and can
only be properly freed by passing it to `freeifaddrs'. */
extern int getifaddrs (struct ifaddrs **__ifap) __THROW;
/* Reclaim the storage allocated by a previous `getifaddrs' call. */
extern void freeifaddrs (struct ifaddrs *__ifa) __THROW;
==============
此函数需要的结构体定义:
struct ifaddrs
{
struct ifaddrs *ifa_next; /* Pointer to the next structure. */
char *ifa_name; /* Name of this network interface. */
unsigned int ifa_flags; /* Flags as from SIOCGIFFLAGS ioctl. */
struct sockaddr *ifa_addr; /* Network address of this interface. */
struct sockaddr *ifa_netmask; /* Netmask of this interface. */
union
{
/* At most one of the following two is valid. If the IFF_BROADCAST
bit is set in `ifa_flags', then `ifa_broadaddr' is valid. If the
IFF_POINTOPOINT bit is set, then `ifa_dstaddr' is valid.
It is never the case that both these bits are set at once. */
struct sockaddr *ifu_broadaddr; /* Broadcast address of this interface. */
struct sockaddr *ifu_dstaddr; /* Point-to-point destination address. */
} ifa_ifu;
/* These very same macros are defined by <net/if.h> for `struct ifaddr'.
So if they are defined already, the existing definitions will be fine. */
# ifndef ifa_broadaddr
# define ifa_broadaddr ifa_ifu.ifu_broadaddr
# endif
# ifndef ifa_dstaddr
# define ifa_dstaddr ifa_ifu.ifu_dstaddr
# endif
void *ifa_data; /* Address-specific data (may be unused). */
};
=============
我在调用了getifaddrs()之后,正常地完成了需要的工作
但是最后如果用freeifaddrs,则出现运行时错误
*** glibc detected *** d: free(): invalid pointer: 0x0804a4d4 ***
======= Backtrace: =========
/lib/libc.so.6[0xb7eda911]
/lib/libc.so.6(__libc_free+0x84)[0xb7edbf84]
/lib/libc.so.6(freeifaddrs+0x1d)[0xb7f512dd]
d[0x8048989]
d[0x80486a5]
/lib/libc.so.6(__libc_start_main+0xdc)[0xb7e8c87c]
d[0x8048491]
======= Memory map: ========
08048000-08049000 r-xp 00000000 03:07 48637 /home/souldump/bin/d
08049000-0804a000 rw-p 00000000 03:07 48637 /home/souldump/bin/d
0804a000-0806b000 rw-p 0804a000 00:00 0 [heap]
b7d00000-b7d21000 rw-p b7d00000 00:00 0
b7d21000-b7e00000 ---p b7d21000 00:00 0
b7e76000-b7e77000 rw-p b7e76000 00:00 0
b7e77000-b7f90000 r-xp 00000000 03:05 16184 /lib/libc-2.4.so
b7f90000-b7f92000 r--p 00118000 03:05 16184 /lib/libc-2.4.so
b7f92000-b7f94000 rw-p 0011a000 03:05 16184 /lib/libc-2.4.so
b7f94000-b7f98000 rw-p b7f94000 00:00 0
b7fab000-b7fb5000 r-xp 00000000 03:05 20108 /lib/libgcc_s.so.1
b7fb5000-b7fb6000 rw-p 00009000 03:05 20108 /lib/libgcc_s.so.1
b7fb6000-b7fb7000 rw-p b7fb6000 00:00 0
b7fb7000-b7fd1000 r-xp 00000000 03:05 16177 /lib/ld-2.4.so
b7fd1000-b7fd3000 rw-p 00019000 03:05 16177 /lib/ld-2.4.so
bfb2b000-bfb41000 rw-p bfb2b000 00:00 0 [stack]
ffffe000-fffff000 ---p 00000000 00:00 0 [vdso]
实际上也有人出现相同问题:
http://p.g.yupoo.com/nph-proxy.cgi/000110A/http/www.linuxdby.com/bbs/viewthread.php=3ftid=3d10756
此人说:"这说明不是真正的链表,指针非法"
但是又没有进一步说明怎么解决
他干脆没有调用freeifaddrs,自然会内存泄漏.....
我去看了afaddrs.c
freeifaddrs的定义居然是:
void
freeifaddrs (struct ifaddrs *ifa)
{
free (ifa);
}
怎么样,很囧吧,明明在头文件里说"必须用freeifaddrs才能正确free..."
然后我看了一下getifaddrs的函数体
他在getifaddrs内部定义了一个结构
struct ifaddrs_storage
{
struct ifaddrs ifa;
union
{
/* Save space for the biggest of the four used sockaddr types and
avoid a lot of casts. */
struct sockaddr sa;
struct sockaddr_ll sl;
struct sockaddr_in s4;
struct sockaddr_in6 s6;
} addr, netmask, broadaddr;
char name[IF_NAMESIZE + 1];
};
然后把获取的各网卡信息一个个填充到此结构的struct ifaddrs ifa中,ifa的next值手动设置为下一个struct ifaddrs_storage中的ifa的地址...
这酒是所谓的"伪链表"吧?
这就是我无法正确free掉它的原因?
我究竟要怎么把它free掉?freeifaddrs一运行就运行时错误
LINUX取得本机IP的简单C程序
注意这里用了两个struct ifaddrs
//代码根据UNP和man手册编写
//适用于LINUX/BSD(FreeBSD, MacOS X)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
int main(void)
{
struct ifaddrs *ifc, *ifc1;
char ip[64];
char nm[64];
if (0 != getifaddrs(&ifc)) return(-1);
ifc1 = ifc;
printf("Iface\tIP address\tNetmask\n");
for(; NULL != ifc; ifc = (*ifc).ifa_next) {
printf("%s", (*ifc).ifa_name);
if (NULL != (*ifc).ifa_addr) {
inet_ntop(AF_INET, &(((struct sockaddr_in*)((*ifc).ifa_addr))->sin_addr), ip, 64);
printf("\t%s", ip);
} else {
printf("\t\t");
}
if (NULL != (*ifc).ifa_netmask) {
inet_ntop(AF_INET, &(((struct sockaddr_in*)((*ifc).ifa_netmask))->sin_addr), nm, 64);
printf("\t%s", nm);
} else {
printf("\t\t");
}
printf("\n");
}
freeifaddrs(ifc1);
return(0);
}
--------------------------------------------------------------------------------
============原来的============
struct ifaddrs *ifap, *ifaphead, *ifaTmp;
getifaddrs(&ifap);
ifaphead = ifap;
while((ifapTmp = ifap) != NULL)
{
//实际任务代码
ifap = ifapTmp->ifa_next;
}
freeifaddrs(ifaphead);
=========修改后========
struct ifaddrs *ifap, *ifaphead;
getifaddrs(&ifap);
ifaphead = ifap;
while(ifap != NULL)
{
//实际任务代码
ifap = ifa_next;
}
freeifaddrs(ifaphead);
==================
仅仅是用了一个ifapTmp来代替ifap做事,区别仅此而已(而且我也忘了一开始为什么要用ifapTmp....)
但是最后都是用了freeifaddrs(ifaphead)啊,并没有传错指针啊????
中间的代码并没有对这段数据做任何修改啊.....
请指教一下,这唯一的区别为什么会造成我原先的代码freeifaddrs失败?谢谢!
ifaphead = ifap; //这里用ifaphead保存ifap指针地址
while((ifapTmp = ifap) != NULL)
{
ifap = ifapTmp->ifa_next; //这里修改了ifap的地址
}
freeifaddrs(ifaphead); //由于ifap的地址修改,所以ifaphead已经是无效指针。
分享到:
相关推荐
本资源“Linux常用C函数(中文版)”提供了一份详细的C函数参考,涵盖了在Linux环境下编程时经常会遇到的一些关键函数。这些函数是C语言标准库的一部分,同时也是Linux系统调用的基础。下面,我们将深入探讨一些重要...
`freeifaddrs`则用于释放由`getifaddrs`获取的内存资源。 由于Android NDK中没有提供这两个函数,我们可以通过以下步骤来解决这个问题: 1. **自定义实现**:编写C/C++代码来实现`getifaddrs`和`freeifaddrs`。...
### Linux下手动释放内存 在Linux系统中,内存管理是一个重要的方面,特别是在服务器环境中,合理的内存管理能够提高系统的性能和稳定性。本文将详细介绍如何通过命令手动释放Linux系统的内存,并解释这些命令背后...
本资料集主要探讨了Linux环境下C语言的内存控制函数,这些函数在编写高效、安全的C程序时至关重要。 1. `malloc()` 函数:这是最常用的动态内存分配函数,用于向系统申请指定大小的内存空间。其原型为`void* malloc...
例如,当你使用"内存分配"函数为一个数据结构分配内存后,一旦该数据结构不再需要,你应该调用"内存释放"函数来释放对应的内存。不正确地管理内存可能会导致程序崩溃或者运行效率下降。 "子程序1"和"子程序2"可能是...
linux下实现getch函数
在易语言内存释放源码中,通常会包含使用这些API函数来实现的示例代码,例如编写一个工具,扫描并显示系统中所有进程的内存使用情况,或者检测特定程序的内存泄漏。这种工具对于调试和优化程序的内存性能非常有用。...
本资源“Linux常用C函数(中文版)”提供了一份详细的C函数参考指南,以方便开发者查找和理解Linux环境下C语言编程时常用的功能函数。这份资料采用HTML格式,便于在网页浏览器中查看和搜索,利用浏览器的"Ctrl+F...
接下来,GCC(GNU Compiler Collection)是Linux下的主要编译器,支持多种编程语言,如C、C++、Objective-C、Fortran等。GCC不仅负责将源代码转换为可执行文件,还提供了代码优化功能。例如,使用`gcc -o output ...
linux下函数介绍蛮详细的,,函数作用,对应的头文件都是什么,挺好用的
本资料集中的“Linux常用C函数(中文版)”提供了关于在Linux环境下使用C语言编程时常见函数的详细解释,对于学习和理解Linux C编程具有极大的帮助。以下是一些关键知识点的概述: 1. **标准库函数**: - `stdio.h`...
本资源提供了两个文档,一个是"linux的c函数(Word版).doc",另一个是"Linux_C_fun.pdf",它们都包含了关于Linux环境下常用C语言函数的详细资料。下面我们将深入探讨这些知识点。 1. **标准库函数**: - `stdio.h`...
以上仅是部分常用C函数的介绍,实际的“Linux常用C函数(中文版)”文档可能包含更详细的函数解释、示例代码和使用技巧,帮助开发者深入理解和使用这些函数,从而更高效地编写Linux下的C程序。学习和熟练掌握这些...
在Linux系统中,C语言是基础且强大的编程工具,它提供了丰富的函数库来处理内存管理和字符串操作。本篇主要探讨的“Linux C函数参考——内存及字符串操作篇”涵盖了两个核心领域:内存管理和字符串处理。以下是对这...
内存管理在C语言编程中不可或缺,`malloc`和`free`用于动态分配和释放内存,`calloc`则可以一次性分配并初始化内存,`realloc`用于调整已分配内存的大小。 信号处理函数,如`signal`,允许程序对特定事件(如键盘...
本文将深入探讨Linux下的文件拷贝函数,以及如何在实际编程中实现这一功能。 首先,我们需要了解Linux中的基本文件操作接口,它们主要通过标准C库提供的`stdio.h`或`unistd.h`头文件中的函数实现。例如,`fopen()`...
《Linux C函数库中文手册》是一本针对Linux操作系统下C语言编程的重要参考资料,它详尽地阐述了在Linux环境中常用C函数的用法,并且配备了丰富的实例,便于读者理解和掌握。这本书采用CHM(Microsoft Compiled ...
"Linux常用C函数速查(中文版)"是一份非常实用的手册,它包含了大量在Linux环境下进行C语言编程时会用到的关键函数,帮助程序员快速查找并理解这些函数的用途和用法。 1. **标准库函数**:C语言的标准库提供了许多...
本文将详细介绍Linux模块间函数调用的通讯机制,并探讨如何解决在实际开发中遇到的相关问题。 #### 二、符号导出与函数调用 ##### 1. 符号导出 在Linux内核中,为了使一个模块中的函数能够被其他模块调用,我们需要...