C语言防火墙开发:整数IP octet转字符缓冲区遇段错误求助
解决C语言中sprintf存储IP地址时的段错误问题
我正在用C语言开发防火墙,在获取点分十进制格式IP的四个整数octet(比如255.255.197.0)后,尝试用sprintf()存入字符缓冲区时出现了段错误。相关代码如下:
char buffer[MAX_BUFF_SIZE]; // The buffer to save the IP address bzero(buffer, sizeof(buffer)); // Clean the buffer // Gets the address int o1, o2, o3, o4; do { printf("Introduce the 4 octets of the IP address (dotted quad format).\n"); printf("Numbers must go from 0 to 255.\n\n"); valid = TRUE; printf("Introduce first octet (X.-.-.-): "); scanf("%d", &o1); printf("Introduce second octet (-.X.-.-): "); scanf("%d", &o2); printf("Introduce third octet (-.-.X.-): "); scanf("%d", &o3); printf("Introduce fourth octet (-.-.-.X): "); scanf("%d", &o4); if (o1 < 0 || o1 > 255 || o2 < 0 || o2 > 255 || o3 < 0 || o3 > 255 || o4 < 0 || o4 > 255) { printf("Error [Client]: Invalid number.\n"); valid = FALSE; } } while (valid == FALSE); // When octets are valid sprintf(buffer, "%d.%d.%d.%d", o1, o2, o3, o4); // Copy the address in String format in buffer inet_aton(buffer, &my_rule.addr); printf("The IP address is %s\n", my_rule.addr);
问题排查与解决方案
你的段错误主要来自两个核心问题,我逐一给你说明并修复:
1. 缓冲区大小不足导致内存溢出
一个标准的点分十进制IP地址最长是xxx.xxx.xxx.xxx,算上3个分隔点和字符串结束符\0,总共需要16个字符的空间(3*4 +3 +1=16)。如果MAX_BUFF_SIZE的定义小于16,sprintf写入时就会超出缓冲区边界,触发段错误。
修复方式:
确保缓冲区足够大,比如直接定义:
#define MAX_BUFF_SIZE 16
或者更直观地声明固定大小的数组:
char buffer[16];
2. 错误地打印struct in_addr类型
最后一行printf("The IP address is %s\n", my_rule.addr);是严重错误:inet_aton的第二个参数是struct in_addr*,也就是说my_rule.addr是struct in_addr结构体,不是字符串指针。用%s格式符打印它会导致程序访问非法内存,进而触发段错误。
修复方式:
使用inet_ntoa()函数把struct in_addr转换为点分十进制字符串后再打印:
printf("The IP address is %s\n", inet_ntoa(my_rule.addr));
3. 用更安全的snprintf替代sprintf
sprintf本身没有缓冲区溢出保护,推荐使用snprintf,它可以指定最大写入字符数,从根源上避免溢出问题:
snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d", o1, o2, o3, o4);
修正后的完整代码
#include <stdio.h> #include <string.h> #include <arpa/inet.h> #define MAX_BUFF_SIZE 16 #define TRUE 1 #define FALSE 0 // 假设my_rule是这样的结构体 struct Rule { struct in_addr addr; }; int main() { char buffer[MAX_BUFF_SIZE]; memset(buffer, 0, sizeof(buffer)); // 用memset替代bzero,兼容性更好 struct Rule my_rule; int o1, o2, o3, o4; int valid; do { printf("Introduce the 4 octets of the IP address (dotted quad format).\n"); printf("Numbers must go from 0 to 255.\n\n"); valid = TRUE; printf("Introduce first octet (X.-.-.-): "); scanf("%d", &o1); printf("Introduce second octet (-.X.-.-): "); scanf("%d", &o2); printf("Introduce third octet (-.-.X.-): "); scanf("%d", &o3); printf("Introduce fourth octet (-.-.-.X): "); scanf("%d", &o4); if (o1 < 0 || o1 > 255 || o2 < 0 || o2 > 255 || o3 < 0 || o3 > 255 || o4 < 0 || o4 > 255) { printf("Error [Client]: Invalid number.\n"); valid = FALSE; } } while (valid == FALSE); // 使用snprintf确保不会溢出 snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d", o1, o2, o3, o4); // 检查inet_aton的返回值,确保转换成功 if (!inet_aton(buffer, &my_rule.addr)) { printf("Error [Client]: Failed to convert IP address.\n"); return 1; } // 正确打印转换后的IP地址 printf("The IP address is %s\n", inet_ntoa(my_rule.addr)); return 0; }
内容的提问来源于stack exchange,提问作者Guim
相关产品推荐
相关产品推荐

