【问题标题】:Weird result when access the stored elements in an array访问数组中存储的元素时的奇怪结果
【发布时间】:2019-09-24 00:00:17
【问题描述】:

我初始化了数组rhs来存储函数rbf产生的数据,如下所示:

float rhs[m][n1+n2];
        for (i=0; i<m; i++){
         igraph_edge(&graph, i, &from, &to);
         igraph_neighbors(&graph, &v1, from, IGRAPH_ALL);
         igraph_neighbors(&graph, &v2, to, IGRAPH_ALL);
         n2 = igraph_vector_size(&v2);
         n1 = igraph_vector_size(&v1);
         for (j=0; j < n2 ; j++) {
              rhs[i][j] = rbf(to, (int) VECTOR(v2)[j]);
              printf("%d %d %f\n", to, (int) VECTOR(v2)[j], rhs[i][j]);
          }
         for (j=0; j < n1; j++) {
              rhs[i][j+n2] = rbf(from, (int) VECTOR(v1)[j]);
              printf("%d %d %d %d %f\n", from, (int) VECTOR(v1)[j], j, j+n2, rhs[i][j+n2]);
          }
printf("\n");
     }

输出:

2 1 0.367879
2 3 0.367879
2 4 0.018316
1 2 0 3 0.367879

3 2 0.367879
3 4 0.367879
2 1 0 2 0.367879
2 3 1 3 0.367879
2 4 2 4 0.018316 

4 2 0.018316
4 3 0.367879
4 5 0.367879
2 1 0 3 0.367879
2 3 1 4 0.367879 <-- ** here rhs[i = 2][( j+(n2=3) ) =  4] = 0.367879 **
2 4 2 5 0.018316 <-- ** here rhs[i = 2][( j+(n2=3) ) =  5] = 0.018316 **

4 2 0.018316
4 3 0.367879
4 5 0.367879
3 2 0 3 0.367879
3 4 1 4 0.367879

5 4 0.367879
4 2 0 1 0.018316
4 3 1 2 0.367879
4 5 2 3 0.367879

当我尝试访问这个数组时,如下所示,其中只有两个元素的顺序与它们存储时的顺序不同!我不知道为什么它会互相替换它们!

for (i=0; i<m; i++){
         igraph_edge(&graph, i, &from, &to);
         igraph_neighbors(&graph, &v1, from, IGRAPH_ALL);
         igraph_neighbors(&graph, &v2, to, IGRAPH_ALL);
         n2 = igraph_vector_size(&v2);
         n1 = igraph_vector_size(&v1);
 for (j=0; j < (n1+n2) ; j++) {
    printf("%li %li %f", i, j, rhs[i][j]);
printf("\n");
  }  
printf("\n");    
}
printf("\n%f", rhs[2][5]);

以及输出:

    0 0 0.367879
    0 1 0.367879
    0 2 0.018316
    0 3 0.367879

    1 0 0.367879
    1 1 0.367879
    1 2 0.367879
    1 3 0.367879
    1 4 0.018316

    2 0 0.018316
    2 1 0.367879
    2 2 0.367879
    2 3 0.367879
    2 4 0.018316 <-- ** here is a strange element rhs[2][4] should equal 0.367879 **
    2 5 0.367879 <-- ** here is a strange element rhs[2][5] should equal 018316 **

    3 0 0.018316
    3 1 0.367879
    3 2 0.367879
    3 3 0.367879
    3 4 0.367879

    4 0 0.367879
    4 1 0.018316
    4 2 0.367879
    4 3 0.367879


    0.367879 <-- it is this one! should equal 0.018316 but it is replacing rhs[2][5] with rhs[2][4]

我想知道为什么在数组中访问元素时的顺序与存储这些元素时的顺序不同?它究竟是什么结果?

加法:

文件toy 包含表单中的玩具数据

1 2
2 3
2 4
3 4
4 5

如果你想编译它,这里是所有代码:

#include <igraph/igraph.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#define sigma 1
    /* Declare and define the rbf function */

float rbf(int a, int b);
float rbf(int a, int b) {
               double inverse;
               double exp(double x;);
               double x;
               double result;

               inverse = ( 1/(sigma*sigma) );
               x = (- inverse * ( (a - b)*(a - b) ) );
               result = exp(x);
               return (result); 
 }

/* Define a function to print a vector in a file using the functions defined in igraph package */

void print_vector(igraph_vector_t *v, FILE *file) {
     long int i;
     for (i=0; i < igraph_vector_size(v); i++) {
        fprintf(file, "%li \n", (long int) VECTOR(*v)[i]);
      }
     fprintf(file,"\n");
  }

int main(void)
{
     igraph_t graph; 
     igraph_bool_t false;
     int ret, n1, n2;
     igraph_vector_t v1, v2;
     long int i, j, k, n, m ;
     igraph_integer_t from, to;
     igraph_adjlist_t adjlist;
     FILE *file;

     /* read the graph from a file using igraph package */
     file = fopen("toy", "r");
          if(!file){
                     return 1;
           }
     igraph_read_graph_edgelist(&graph, file, 
                   0, false);
           fclose(file);
            //return 2;

  /* initialize two vectors to store v1, v2 to store vertices */
     igraph_vector_init(&v1, (igraph_vcount(&graph)) );
     igraph_vector_init(&v2, (igraph_vcount(&graph)) );

    n = igraph_vcount(&graph); /* number of vertices in the graph */
    m = igraph_ecount(&graph); /* number of edges in the graph */


float rhs[m][n1+n2];
    for (i=0; i<m; i++){
                 igraph_edge(&graph, i, &from, &to);
                 igraph_neighbors(&graph, &v1, from, IGRAPH_ALL);
                 igraph_neighbors(&graph, &v2, to, IGRAPH_ALL);
                 n2 = igraph_vector_size(&v2);
                 n1 = igraph_vector_size(&v1);


                 for (j=0; j < n2 ; j++) {
                     rhs[i][j] = rbf(to, (int) VECTOR(v2)[j]);
                     printf("%d %d %f\n", to, (int) VECTOR(v2)[j], rhs[i][j]);
                 }
                 for (j=0; j < n1; j++) {
                     rhs[i][j+n2] = rbf(from, (int) VECTOR(v1)[j]);
                     printf("%d %d %li %li %f\n", from, (int) VECTOR(v1)[j], j, j+n2, rhs[i][j+n2]);
                 }
printf("\n");
         }

  for (i=0; i<m; i++){
                 igraph_edge(&graph, i, &from, &to);
                 igraph_neighbors(&graph, &v1, from, IGRAPH_ALL);
                 igraph_neighbors(&graph, &v2, to, IGRAPH_ALL);
                 n2 = igraph_vector_size(&v2);
                 n1 = igraph_vector_size(&v1);
                 for (j=0; j < (n1+n2) ; j++) {
                        printf("%f", rhs[i][j]);
                  }  
                 printf("\n");

     }
}

【问题讨论】:

  • 请正确缩进您的代码。您应该遵循编码风格指南(或您自己的,但要这样做)。这是一个很好的:kernel.org/doc/html/v4.10/process/coding-style.html
  • n1n2 在您执行 float rhs[m][n1+n2]; 时未初始化。所有这些都是未定义的行为。您没有包含重现问题所需的 toy 文件。请修正你的缩进。请,如果您使用 gcc 编译,请使用 -Wall -Wextra -Werror 编译并修复所有错误。
  • 使用-Wall -Wextra -Werror(或您的编译器具有的任何警告选项)编译以查看此类错误
  • I used it but nothing is related to the problem! - 我显然得到了warning: ‘n1’ may be used uninitialized in this functionn2 相同
  • 定义一个变量和给它赋值是不一样的。你需要在使用它之前给它一个值,这正是编译器告诉你的

标签: c arrays for-loop igraph


【解决方案1】:

n1n2rhs[m][n1+n2] 行之前未初始化。您的程序的所有行为可能/是未定义的行为。

int ret, n1, n2;
... code that does not touches n1 nor n2 ...
float rhs[m][n1+n2];

变量n1n2 在使用前没有初始化。它们用于声明可变长度数组 VLA。编译器在float rhs[m][n1 + n2] 行为VLA 分配内存。因为变量没有初始化,所以变量的值具有所谓的“不确定”值(读作:任何值)。编译器为rhs 数组分配未知的(对于程序员而言)浮点数。 n1n2 可能是负数,在这种情况下会发生未定义的行为。您应该改用动态分配。

也不建议将 VLA 用于大型阵列(或根本不使用它们)。你无法检测到失败。你不知道它是否会失败以及何时失败。它们不是那么可移植,并且在 C 中是可选的。不要使用 VLA,尽可能使用动态分配。

float **rhs = malloc(sizeof(rhs[0]) * m);
if (rhs == NULL) { /* handle error; */ }
for (i = ...) {
    .. later...
    rhs[i] = malloc(sizeof(rhs[i][0]) * (n1 + n2));
    if (rhs[i] == NULL) { /* handle error */ }
}
.. later ..
for (i = ... ){ 
    free(rhs[i]);
}
free(rhs);

注意事项:

  • 使用size_t 类型来表示对象的大小和数组中元素的数量。 for (size_t i = 0; i &lt; ... ; i++) 是一个流行的成语。
  • Linux kernel coding style 是一个很好的 C 文件风格指南。
  • 来自 linux 内核编码风格:“局部变量的数量 [...] 不应超过 5-10,否则您做错了什么”。
  • 始终尝试在启用所有(健全)警告的情况下进行编译。尝试修复所有警告。
  • igraph_bool_t false; "false" 是在 stdbool.h 中定义的宏。我建议重命名变量名,以防您以后想包含stdbool.h

【讨论】:

  • 或者足够大的静态数组
猜你喜欢
  • 2015-07-24
  • 2014-02-23
  • 1970-01-01
  • 2016-07-23
  • 2017-03-22
  • 1970-01-01
  • 2021-04-15
  • 1970-01-01
相关资源
最近更新 更多