C:指向相同值的指针数组

C: array of pointers pointing to the same value

我在写一个IP转发程序,需要将下面的路由table拼接成一个char*数组

  128.15.0.0    255.255.0.0    177.14.23.1
  137.34.0.0    255.255.0.0    206.15.7.2
  137.34.128.0  255.255.192.0  138.27.4.3
  137.34.0.0    255.255.224.0  139.34.12.4
  201.17.34.0   255.255.255.0  192.56.4.5
  27.19.54.0    255.255.255.0  137.7.5.6
  0.0.0.0       0.0.0.0        142.45.9.7

我已经像这样 char *routing[128][128]; 初始化了指向 char* 的指针数组,然后遍历每一行,构建一个 char temp[128] 数组,然后将其分配给 routing 如下所示。

换句话说,routing数组中的每个指针都会指向一个IP地址。

char *routing[128][128];
char line[128], temp[128];
int i = 0, j = 0, token_count = 0, line_count = 0;
while(fgets(line, sizeof(line), routing_table) != NULL){
  // printf("%s\n", line);
  token_count = 0;
  for (i = 0; i < strlen(line); i++){
    if (line[i] != ' ' && token_count == 2){
      for (j = 0; j < 128; j++){
        if (line[i+j] == ' ')
          break;
        temp[j] = line[i+j];
      }
      i += j;
      routing[line_count][token_count] = temp; //ASSIGNMENT OCCURS HERE
      token_count++;
    }
    else if (line[i] != ' ' && token_count == 1){
      for (j = 0; j < 128; j++){
        if (line[i+j] == ' ')
          break;
        temp[j] = line[i+j];
      }
      i += j;
      routing[line_count][token_count] = temp;
      token_count++;
    }
    else if (line[i] != ' ' && token_count == 0){
      for (j = 0; j < 128; j++){
        if (line[i+j] == ' ')
          break;
        temp[j] = line[i+j];
      }
      i += j;
      routing[line_count][token_count] = temp;
      token_count++;
    }
  }
  line_count++;
}

问题是每次发生赋值时,它都会更新整个数组。所以当我在最后打印出数组时,我重复了最后一个元素。

142.45.9.7

142.45.9.7

142.45.9.7

...

142.45.9.7

142.45.9.7

我想我需要取消引用 temp 但那引发了警告并且甚至没有修复它。

我在语法上有什么错误?为什么所有的指针都指向同一个字符串?

接近尾声,就在您递增 token_count 之前,您得到了这一行:

routing[line_count][token_count] = temp;

那是你的问题。 temp 是一个包含 128 个字符的数组——如果某处有空终止符,我们在 C 语言中称之为字符串。您依次将每个 IP 地址字符串复制到其中,然后对于每个 IP 地址字符串,您将 temp 的地址分配给大型二维指针数组之一中的一个槽。所有这些指针,但它们都指向同一个实际缓冲区。

因此在循环结束时,它们都指向您复制到 temp 中的最后一个字符串。那不是你想要的,如果 temp 是函数中的局部变量,那么你就有大麻烦了。

您想要的是实际字符数组的二维数组(每个 16 个字符足以用于点分四边形和空终止符)——但我对 C 有点生疏,不会冒险领先你误入歧途了如何声明——否则你需要为你现有的二维数组中的每个字符串分配新的内存。在许多 C 实现中,您会这样做:

routing[line_count][token_count] = strdup(temp);

strdup() 是一个方便的函数,它为您提供的字符串分配足够的内存,将字符串复制到该内存中,并 returns 指向它的指针。但它不是标准的一部分,因此不能在所有情况下都指望它。如果您正在为一个编译器编写代码并且它就在那里,那么您已经准备就绪(通常是这种情况)。但是,如果您对可移植性有任何顾虑,here's a portable way to do the same thing

Portable or not,你现在正在分配内存,当你完成路由table,你需要通过调用[=19释放分配的内存=] 在你从 strdup() 返回的每一个指针上(或从其他一些更 portable 函数)。

为此,您应该在分配任何内容之前调用它:

memset(routing, 0, sizeof(char) * 128 * 128);

...其中 128 和 128 是数组的两个维度(如果我真的必须在C,并且没有动态分配整个混乱)。如果你首先将整个东西设置为零,那么那里的每个指针都以 NULL 开头。然后,当您循环遍历它以释放内存时,您可以循环遍历每个 "row" 释放每个指针,直到您遇到 NULL,然后停止。

想想另一种方式,ifconfig,route,ip等命令行输出的ip地址解析总是容易出错,为什么不使用程序化的方式获取路由呢table信息?比如在Linux上,RTNETLINK是操作route table:

的标准方式

http://man7.org/linux/man-pages/man7/rtnetlink.7.html

它以定义明确的结构为您提供所有信息。

在 windows 上,您可以使用 Win32 API 执行相同的操作:

https://msdn.microsoft.com/en-us/library/windows/desktop/aa365953(v=vs.85).aspx

routing[line_count][token_count] = temp; //ASSIGNMENT OCCURS HERE

temp 数组的内容在每次迭代时可能不同。

temp数组的地址在整个程序执行过程中是不变的。

所以您显然为 routing 数组中的每个条目分配了相同的值。