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
数组中的每个条目分配了相同的值。
我在写一个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
数组中的每个条目分配了相同的值。