You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:02:54