在C程序中从文件中找出IP地址

问题描述 投票:0回答:1

因此,我必须创建一个 .c 文件,按升序对 IP 地址进行排序,并对所有 IP 地址进行计数。考虑到存在 ip.txt 文件,同时包含如下内容(IP 地址和错误代码)

127.0.0.0 500
127.0.0.0 400
127.0.0.1 300
127.0.0.2 100

请提出一些建议如果您擅长编程,请提前谢谢!

以下是我进行的尝试,请随意建议和修改代码以获得完美的输出。

尝试过的代码附加在图像文件中,我希望整理 IP 地址并在输出控制台中给出从最大到最小的 IP 地址计数。

下面的文件_操作_代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(){
    char * line = NULL;
    size_t len = 0;
    ssize_t read;
    int count=0, totalCh=0;

    FILE *fp = fopen("ip.txt", "r");
    if(fp == NULL){
        printf("IP File does not exist!\n");
        return -1;
    }

    while ((read = getline(&line, &len, fp)) != -1) {
        count++;
        totalCh+=read;
        printf("line of length: %zu\n", read);
        printf("line content: %s", line);
    }

    printf("Total number of lines=%d\n", count);
    printf("Total number of characters=%d\n", totalCh);

    // logic to fetch IP addr and sort out and give count to output console pending

    fclose(fp);
    if (line)
        free(line);

    return 0;
}
c file clang logic getline
1个回答
0
投票

如果您编写了合适的比较函数,那么您可以使用

qsort
对数据进行排序。

但你可能连这个都不需要。以下是安全地从文件获取结果的示例。

主机的 IPv4 地址

IP (v4) 地址是一组 4 个八位字节。对于主机,您不能将

0
作为第一个八位位组或最后一个八位位组。而且你也不可能拥有所有的---
255
0
是网络地址,
255
是广播地址。

封装:
Packet
表示有效的IP和代码

typedef struct
{
    char     ip[16];
    int      a, b, c, d;  // octets
    unsigned code;
} Packet;

这对于快速测试来说是可以的,并且让生活变得更轻松。因为这只是玩具,我们可以同时拥有八位字节的字符串和十进制值。

此函数

so_compare()
比较 2
Packet
,如果
-1
按排序顺序位于
one
之前,则返回
other
。如果
+1
one
之后,则
other
。这就是您使用
qsort
中 stdlib 中的
C
对它们进行排序所需的全部内容。

int so_compare(Packet* one, Packet* other)
{
    if (one == NULL) return 0;
    if (other == NULL) return 0;
    // 1
    if (one->a < other->a) return -1;
    if (one->a > other->a) return 1;
    // 2
    if (one->b < other->b) return -1;
    if (one->b > other->b) return 1;
    // 3
    if (one->c < other->c) return -1;
    if (one->c > other->c) return 1;
    // 4
    if (one->d < other->d) return -1;
    if (one->d > other->d) return 1;
    // code
    if (one->code < other->code) return -1;
    if (one->code > other->code) return 1;
    // stable
    return 1;
}

您只需为输入文件中的每个有效行获取一个即可。

验证线路

这可以非常简单:我们只需要一个有效 IP 和有效代码。

sscanf()
在这里很好,因为我们可以一次解析所有 5 个值。

一个简单的解析行的函数

下面的

so_get_packet()
从输入文件中获取一行并返回一个有效的
Packet
,用几行代码。

提取八位字节的值,验证它们,填充新的

Packet
,我们就完成了。

Packet* so_get_packet(const char* addr)
{
    int         a, b, c, d;
    int         code;
    int         res  = 0;
    const char* mask = "%3d.%3d.%3d.%3d %3d";
    res = sscanf(addr, mask, &a, &b, &c, &d, &code);
    if (res != 5) return NULL;
    if ((a < 1) || (a > 254)) return NULL;
    if ((b < 0) || (b > 254)) return NULL;
    if ((c < 0) || (c > 254)) return NULL;
    if ((d < 1) || (d > 254)) return NULL;
    Packet* pck = malloc(sizeof(Packet));
    if (pck == NULL) return NULL;
    sprintf(pck->ip, "%d.%d.%d.%d", a, b, c, d);
    pck->a = a, pck->b = b, pck->c = c, pck->d = d;
    pck->code = code;
    return pck;
}

存储有效数据包

这是

C
。通过组合和遏制,生活变得更加轻松。考虑一系列数据包,我们可以使用如下的
Vector
来存储它们。

#define MAX_DATA 100
typedef struct
{
    size_t size;
    size_t limit;
    Packet data[MAX_DATA];
} Vector;

所以程序只是一个问题

  • 读取文件
  • 为每个有效的行数据创建一个
    Packet
  • 将数据包插入
    Vector
    事物
  • 数据排序

由于每个

Vector
都有一个
size
,我们总是知道到目前为止我们获得的地址数量。

无需
qsort
数据

因为我们一次只获取一行更有意义,所以按顺序插入它们......

int so_insert(Packet* pck, Vector* V)
{
    if (pck == NULL) return -1;
    if (V == NULL) return -2;
    if (V->size == V->limit) return -3; // full
    if (V->size == 0) // was empty
    {
        V->data[0] = *pck;
        V->size = 1;
        return 0;
    }
    for (size_t pos = V->size; pos > 0; --pos)
    {   // insert in position
        if (so_compare(pck, &V->data[pos - 1]) > 0)
        {   // 'pos' is the position
            V->data[pos] = *pck;
            ++V->size;
            return 0;
        }
        V->data[pos] = V->data[pos - 1];
    };  // for
    V->data[0] = *pck;
    ++V->size;
    return 0;
}

这里并不奇怪:如上所述,

so_insert()
按顺序将
Packet
插入到
Vector
中,因此当我们到达输入末尾时,所有行都已在
Vector
中排序。

消耗文件

so_consume_file()
执行预期操作:获取文件名并返回地址和代码的排序列表。或者
NULL
如果出现错误。

Vector* so_consume_file(const char* file_name)
{
    FILE* in = fopen(file_name, "r");
    if (in == NULL) return NULL;
    // create array
    Vector* data = so_create(MAX_DATA);
    if (data == NULL) return NULL;

    char  buffer[256] = {0};
    char* p           = buffer;
    int   res         = 0;
    while ((p = fgets(buffer, sizeof(buffer), in)) != NULL)
    {
        Packet* pck = so_get_packet(buffer);
        if (pck != NULL)
        {
            so_insert(pck, data);
            free(pck);
        }
    };
    fclose(in);
    so_show_v(data, "final data ");
    return data;
}

并且易于阅读:单个循环。如果一条线路有一个数据包,它就会进入列表。最后,列表被打印并销毁。

测试的完整代码

#define MAX_DATA 100

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct
{
    char     ip[16];
    int      a, b, c, d;  // octets
    unsigned code;
} Packet;

typedef struct
{
    size_t size;
    size_t limit;
    Packet data[MAX_DATA];
} Vector;

Vector* so_create(size_t);
Vector* so_destroy(Vector*);
Vector* so_consume_file(const char*);
int so_insert(Packet*, Vector*);
int     so_show_v(Vector*,const char*);

Packet* so_get_packet(const char*);
int     so_compare(Packet*, Packet*);
int     so_show_p(Packet*, const char*);

// https://stackoverflow.com/questions/77597529/
// sort-out-ip-addrs-from-file-in-c-program

int main(int argc, char** argv)
{
    const char* def_name = "in.txt";
    char        f_name[50];
    if (argc < 2)
        strcpy(f_name, def_name);
    else { strcpy(f_name, argv[1]); }
    fprintf(stderr, "input file is \"%s\"\n", f_name);
    Vector* my_data = so_consume_file(f_name);
    so_destroy(my_data);
    return 0;
}

Vector* so_create(size_t limit)
{
    if (limit > MAX_DATA) return NULL;
    Vector* one = malloc(sizeof(Vector));
    if (one == NULL) return NULL;
    one->limit = limit;
    one->size  = 0;
    return one;
}

Vector* so_destroy(Vector* del)
{
    if (del == NULL) return NULL;
    free(del);
    return NULL;
}

Vector* so_consume_file(const char* file_name)
{
    FILE* in = fopen(file_name, "r");
    if (in == NULL) return NULL;
    // create array
    Vector* data = so_create(MAX_DATA);
    if (data == NULL) return NULL;

    char  buffer[256] = {0};
    char* p           = NULL;
    while ((p = fgets(buffer, sizeof(buffer), in)) != NULL)
    {
        Packet* pck = so_get_packet(buffer);
        if (pck != NULL)
        {
            so_insert(pck, data);
            free(pck);
        }
    };
    fclose(in);
    so_show_v(data, "final data ");
    return data;
}

int so_insert(Packet* pck, Vector* V)
{
    if (pck == NULL) return -1;
    if (V == NULL) return -2;
    if (V->size == V->limit) return -3; // full
    if (V->size == 0) // was empty
    {
        V->data[0] = *pck;
        V->size = 1;
        return 0;
    }
    for (size_t pos = V->size; pos > 0; --pos)
    {   // insert in position
        if (so_compare(pck, &V->data[pos - 1]) > 0)
        {   // 'pos' is the position
            V->data[pos] = *pck;
            ++V->size;
            return 0;
        }
        V->data[pos] = V->data[pos - 1];
    };  // for
    V->data[0] = *pck;
    ++V->size;
    return 0;
}

int so_show_v(Vector* V, const char* msg) 
{
    if (V == NULL) return -1; // no vector
    if (msg != NULL) printf("%s", msg);
    printf("%llu/%llu elements\n", V->size, V->limit);
    for (size_t i = 0; i < V->size; ++i)
    {
        so_show_p(&V->data[i], NULL);
    }
    printf("---\n\n");
    return 0;
}

Packet* so_get_packet(const char* addr)
{
    int         a, b, c, d;
    int         code;
    int         res  = 0;
    const char* mask = "%3d.%3d.%3d.%3d %3d";
    res = sscanf(addr, mask, &a, &b, &c, &d, &code);
    if (res != 5) return NULL;
    if ((a < 1) || (a > 254)) return NULL;
    if ((b < 0) || (b > 254)) return NULL;
    if ((c < 0) || (c > 254)) return NULL;
    if ((d < 1) || (d > 254)) return NULL;
    Packet* pck = malloc(sizeof(Packet));
    if (pck == NULL) return NULL;
    sprintf(pck->ip, "%d.%d.%d.%d", a, b, c, d);
    pck->a = a, pck->b = b, pck->c = c, pck->d = d;
    pck->code = code;
    return pck;
}

int so_compare(Packet* one, Packet* other)
{
    if (one == NULL) return 0;
    if (other == NULL) return 0;
    // 1
    if (one->a < other->a) return -1;
    if (one->a > other->a) return 1;
    // 2
    if (one->b < other->b) return -1;
    if (one->b > other->b) return 1;
    // 3
    if (one->c < other->c) return -1;
    if (one->c > other->c) return 1;
    // 4
    if (one->d < other->d) return -1;
    if (one->d > other->d) return 1;
    // code
    if (one->code < other->code) return -1;
    if (one->code > other->code) return 1;
    // stable
    return 1;
}

int so_show_p(Packet* P, const char* msg)
{
    if (P == NULL) return -1;
    if (msg != NULL) printf("%s", msg);
    printf("     %16s %4d\n", P->ip, P->code);
    return 0;
}

程序接受文件名作为输入。默认为 in.txt

示例输出

SO> cat in.txt

stack overflow

127.0.0.0 500 not a host
127.0.0.0 400 not a host
127.0.0.1 300
127.0.0.2 100
127.0.0.2 99
127.0.0.2 101
127.0.0.2 100

SO> v1
input file is "in.txt"
final data 5/100 elements
            127.0.0.1  300
            127.0.0.2   99
            127.0.0.2  100
            127.0.0.2  100
            127.0.0.2  101
---


SO>

SO>


SO> cat other.txt
127.0.0.10 500
127.0.0.100 400
127.0.0.1 300
127.0.0.2 100
127.0.0.2 101
127.0.0.2 101
10.0.0.1 200
10.0.0.1 201
10.0.0.92 200
10.0.0.2 200

SO> v1 other.txt
input file is "other.txt"
final data 10/100 elements
             10.0.0.1  200
             10.0.0.1  201
             10.0.0.2  200
            10.0.0.92  200
            127.0.0.1  300
            127.0.0.2  100
            127.0.0.2  101
            127.0.0.2  101
           127.0.0.10  500
          127.0.0.100  400
---


SO>

未经真正测试。希望它有助于展示一种以受控方式从原始文件数据到原型的方法。

© www.soinside.com 2019 - 2024. All rights reserved.