Путаница между передачей по значению и ссылкой? - PullRequest
2 голосов
/ 29 июня 2009

Может кто-нибудь объяснить, почему это не работает?

int main()
{
    float* x;
    float a, b;
    int num_vals = 10;

    fill_in_x(&x, num_vals); // malloc is called and x is populated with values

    a = x[0];
    b = x[1] - x[0];

    printf("%f\n", a);
    printf("%f\n", b);

    function_using_a_and_b(a, b); // The values of a and b used in this function 
                                  // don't match those calculated in main 
}

void fill_in_x(float** x, int num_vals)
{
    *x = (float*)malloc(num_vals * sizeof(float));

    // Fill in values for x
}

void function_using_a_and_b(float a, float b)
{
    printf("%f\n", a);
    printf("%f\n", b);
}

Чтобы повторить то, что сказано в комментариях, когда я динамически распределяю память для x в malloc в отдельной функции, затем пытаюсь передать пару значений в другую функцию, значения не передаются правильно. Это похоже на проблему с указанием, но я думал, что передаю значения a и b, а не адреса. Для справки, я даже попытался использовать memcpy, чтобы поместить значения в a и b, но это тоже не помогло.

Я заставил его работать, передав адреса a и b, а затем разыменовав их в function_using_a_and_b, но почему не работает описанный выше метод?

Заранее спасибо.

Ответы [ 11 ]

3 голосов
/ 29 июня 2009

Для того, чтобы malloc работал в вашей функции fill_in_x (), вам нужно передать в функцию указатель, а не ссылку на указатель. Что касается вашего вопроса между передачей по ссылке и передачей по значению, передача по значению включает в себя функцию, делающую локальную копию переменной, в то время как передача по ссылке - это более конкретный тип передачи по указателю, который лучше объяснить через здесь . Не обращайте внимания, что это для C ++, так как он работает так же для C в отношении вашего вопроса.

2 голосов
/ 29 июня 2009

Кажется, это работает так, как я ожидал:

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

void fill_in_x(float** x, int num_vals)
{
    float* res = (float*)malloc(num_vals * sizeof(float));
    *x = res;

    // Fill in values for x
    res[0] = 1.0;
    res[1] = 4.0;
}

void function_using_a_and_b(float a, float b)
{
    printf("%f\n", a);
    printf("%f\n", b);
}

int main()
{
    float* x;
    float a, b;
    int num_vals = 10;

    fill_in_x(&x, num_vals); // malloc is called and x is populated with values

    a = x[0];
    b = x[1] - x[0];

    function_using_a_and_b(a, b); // The values of a and b used in this function 
                                  // don't match those calculated in main 
}
2 голосов
/ 29 июня 2009

Скорее всего, вы делаете что-то в fill_in_x, что не правильно. Поскольку определения нет в посте, я не могу сказать, что, но это должно быть что-то вроде:

void fill_in_x(float** array) {
      *array = (float*) malloc(10*sizeof(float));
}

(хотя возвращать выделенную память плохо, потому что это часто приводит к утечкам памяти, как в вашем коде.)


(отвечает на fill_in_x) : компиляция и запуск этого кода в Visual Studio дает ожидаемый результат.

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

void fill_in_x(float** x, int num_vals)
{
    *x = (float*)malloc(num_vals * sizeof(float));

    for(int i = 0; i < num_vals; ++i)
        (*x)[i] = (i*2)+3;
}

void function_using_a_and_b(float a, float b)
{
    printf("%f\n", a);
    printf("%f\n", b);
}

int main()
{
    float* x;
    float a, b;
    int num_vals = 10;

    fill_in_x(&x, num_vals); // malloc is called and x is populated with values

    a = x[0];
    b = x[1] - x[0];

    printf("%f\n", a);
    printf("%f\n", b);

    function_using_a_and_b(a, b); // The values of a and b used in this function 
                                  // don't match those calculated in main 
}

Пишет:

3.000000
2.000000
3.000000
2.000000

Так что я все еще не уверен, что вы имеете в виду. Я подозреваю, что проблемный код все еще отсутствует в посте.

1 голос
/ 29 июня 2009

Вы можете попробовать отладить вашу функцию fill_X и посмотреть адрес f в основном и внутри функции.

Альтернативой может быть изменение функции fill_x на

float* fill_x(){

  float* f = malloc(...);

  //do stuff with f.

  return f;

}

Тогда вам нужно освободить эту память

 float *f = fill_x();

  //do stuff with f.
  free(f);
0 голосов
/ 30 июня 2009

Как изначально написано, прототипа для области действия function_using_a_and_b() при его вызове не существует, поэтому компилятор должен преобразовать значения float в double перед их передачей. Затем функция записывается в нотатионе прототипа, поэтому компилятор может не заметить, что функция уже была вызвана с двойными числами, даже несмотря на то, что запись прототипа позволяет передавать ее как float. Это приведет к странным значениям при печати. ​​

Я не уверен, что компилятор не определит проблему - но это может объяснить то, что вы видите. Конечно, если функции находятся в отдельных исходных файлах, то у компилятора нет шансов обнаружить несоответствия.

0 голосов
/ 29 июня 2009
void fill_in_x(float** x, int num_vals)
{
    *x = (float*)malloc(num_vals * sizeof(float));

    for (int i = 0; i < num_vals; ++i) {
        (*x)[i] = (float)i;
    }
}

Это тоже работает. Заставляет меня задуматься, как выглядит ваш fill_in_x (). Там нет ничего плохого в коде, как он есть.

0 голосов
/ 29 июня 2009

Вы, вероятно, используете

*x[0] = 3.0;

в fill_in_x(), когда вам действительно нужно использовать

(*x)[0];

edit: кстати, C не имеет ссылки, это просто педагогическая особенность. Вы просто передаете переменные ADDRESSES по значению, а затем разыменовываете это значение, чтобы получить исходную переменную.

0 голосов
/ 29 июня 2009

Хех, хорошая загадка. : -)

Полагаю, объявление вашей функции выглядит так:

void fill_in_x(float* x);

когда должно выглядеть так:

void fill_in_x(float** x);

Используя ваше объявление, функция ожидает получить указатель с плавающей точкой, но вы передаете ему адрес от указателя с плавающей точкой x - который находится где-то в стеке, поскольку именно здесь расположены локальные переменные ,

Это означает, что вы распределяете пространство в собственном стеке вызовов с явно ужасающими результатами. :)

0 голосов
/ 29 июня 2009

почему бы не использовать malloc x в main, чтобы потом не забыть освободить x, что приведет к утечке памяти. Я бы посоветовал избегать использования float **, это слишком запутанно.

0 голосов
/ 29 июня 2009

То, что вы делаете, выглядит правильно, если немного странно.

Единственное, что меня беспокоит, это то, что вы не показали достаточно кода для fill_in_x, чтобы мы могли видеть, как / что вы заполняете.

 // Fill in values for x

Здесь есть вероятность, что вы делаете это неправильно - легко, потому что у вас есть две разыменования, о которых нужно подумать (float ** x).

Убедитесь, что вы делаете: -

(*x)[0] = 0;
(*x)[1] = 100;
... etc...

... а не

x[0] = 0; // compiles, but overwrites the pointer with NULL...

.. или

*(x[0]) = 0;

.. или

*x[0] = 0;

Что касается изменения a и b при вызове function_using_a_and_b - это странно. Вы правильно передаете их по значению. Какой компилятор вы здесь используете?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...