Странный результат при доступе к хранимым элементам в массиве - PullRequest
2 голосов
/ 06 мая 2019

Я инициализировал массив 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");

     }
}

1 Ответ

2 голосов
/ 06 мая 2019

n1 и n2 неинициализированы перед строкой rhs[m][n1+n2]. Все поведение вашей программы может / является неопределенным поведением.

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

Переменные n1 и n2 не инициализируются перед использованием. Они используются для объявления массива переменной длины VLA. Компилятор выделяет память для VLA в строке float rhs[m][n1 + n2]. Поскольку переменные не инициализированы, значения переменных имеют то, что называется «неопределенным» значением (читается как: любое значение). Компилятор выделяет неизвестное (для программиста) число чисел с плавающей точкой для массива rhs. n1 и n2 могут быть отрицательными, в этом случае происходит неопределенное поведение. Вместо этого вы должны использовать динамическое распределение.

Также использование 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 < ... ; i++) - это популярная идиома.
  • Стиль кодирования ядра Linux - хорошее руководство по стилю в C-файлах.
  • Из стиля кодирования ядра Linux: «количество локальных переменных [...] не должно превышать 5-10, или вы что-то делаете неправильно».
  • Всегда старайтесь компилировать с включенными предупреждениями (здравомыслие). Попробуйте исправить все предупреждения.
  • igraph_bool_t false; "false" - это макрос, определенный в stdbool.h. Я предлагаю переименовать имя переменной, на случай, если позже вы захотите включить stdbool.h.
...