Как заставить работать указатели? - PullRequest
0 голосов
/ 06 мая 2018

У меня есть 2 функции. Первая функция называется «chooser», которая сканирует 10 чисел в массив и выводит 3 числа из этого массива. Вторая функция, называемая «калькулятор», определяет 3 числа, которые должны быть распечатаны. Тем не менее, я думаю, что я сделал что-то не так с указателями?

void chooser() {
    int cool_array[10] = {'\0'};

    int i = 0;
    while(i < 10) {
        scanf("%d", &cool_array[i]);
        i++;
    }

    int first_num = 0;
    int second_num = 0;
    int third_num = 0;
    calculator(cool_array, first_num, second_num, third_num);

    printf("%d %d %d\n", first_num, second_num, third_num);
}

void calculator(int cool_array[],
            int *first_num, int *second_num, int *third_num) {

    int one = cool_array[0];
    int two = cool_array[1];
    int _three = cool_array[2];

    // I want the code below to change the number of first_num,
    // second_num and third_num in the chooser function, so it
    // can print the new numbers determined by the calculator function
    first_num = &one;
    second_num = &two;
    third_num = &three;
}

Ответы [ 2 ]

0 голосов
/ 06 мая 2018

Как указано в моем комментарии выше, calculator переводит указатели на int, как показано ниже:

void chooser() {
    <snip>

    int first_num = 0;
    int second_num = 0;
    int third_num = 0;

    // calculator(cool_array, first_num, second_num, third_num);
    /* the above is incorrect because calculator expacts a pointer to
     * int as its 2nd, 3rd, and 4th values. It must be called as:
     */
    calculator(cool_array, &first_num, &second_num, &third_num);

    printf("%d %d %d\n", first_num, second_num, third_num);
}

Выше была простая синтаксическая проблема, которая могла быть обнаружена любым компилятором и была выдана ошибка, но теперь мы находимся в центре вашей проблемы. one, two, three объявлены локальными для calculator, и там значения (и адреса) недоступны после calculator , возвращающих , и любая попытка получить доступ после того, как они вышли из области видимости, Неопределенное поведение . (ваш код может работать так, как задумано, или SegFault, или что-то среднее). Посмотрите на комментарии ниже:

void calculator(int cool_array[],
            int *first_num, int *second_num, int *third_num) {

    int one = cool_array[0];    /* so far so good, you assign values from */
    int two = cool_array[1];    /* cool_array to one, two and three       */
    int three = cool_array[2];  /* ('_names' are generally reserved)      */

    // I want the code below to change the number of first_num,
    // second_num and third_num in the chooser function, so it
    // can print the new numbers determined by the calculator function

    /* BIG PROBLEM, one, two, and three are decalred local to calculator,
       when calculator returns, the function stack memory (where local 
       variables are stored) is released for reuse by your program and any
       attempt to access addresses within the function stack after the
       function returns is Undefined Behavior -- (really bad)
    first_num = &one;
    second_num = &two;
    third_num = &three;
    */

    /* assign the value to the address 'pointed to' (held) by each */
    *first_num = one;
    *second_num = two;
    *third_num = three;
}

Далее, посмотрите, что вы пытались сделать. first_num = &one; назначает адрес one на first_num. Мы обсудили проблему с адресом one, но есть еще одна фундаментальная проблема. first_num в calculator является копией указателя first_num в chooser. Копия в calculator имеет свой собственный (и очень другой) адрес. Если бы one имел срок хранения, который сохранился после возврата calculator, вы все равно не увидели бы никаких изменений в first_num в chooser. Зачем? потому что в calculator вы просто изменили копию указателя с chooser.

Однако, хотя first_num в calculator является копией, адрес , который он хранит в качестве значения , совпадает с указателем в chooser. Таким образом, если вы установите значение по адресу , указанному на на first_num (путем разыменования его и присвоения значения), то это изменение будет отражено обратно в chooser. Так работают указатели (и как работают передаваемые по значению C параметры функции).

Теперь давайте сделаем то, что вы пытаетесь.

#include <stdio.h>

/* let's put the functions in the right order (or use prototypes) */

void calculator(int cool_array[],
            int *first_num, int *second_num, int *third_num) {

    int one = cool_array[0];
    int two = cool_array[1];
    int three = cool_array[2];

    /* set the value at the address held by each poiter to wanted values */
    *first_num = one;
    *second_num = two;
    *third_num = three;
}

void chooser() {
    int cool_array[10] = {0};

    int i = 0;
    while(i < 10) {
        scanf("%d", &cool_array[i]);
        i++;
    }

    int first_num = 0;
    int second_num = 0;
    int third_num = 0;
    /* a proper call to calculator */
    calculator(cool_array, &first_num, &second_num, &third_num);

    printf("%d %d %d\n", first_num, second_num, third_num);
}

int main (void) {

    chooser();
    return 0;
}

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

Пример Использование Выходные данные

$ ./bin/choose
10 20 30 40 50 60 70 80 90 100
10 20 30

из, если вы предпочитаете трубопроводный пример, который генерирует те же числа и автоматически передает их в вашу программу:

$ printf "%s\n" {10..100..10} | ./bin/choose
10 20 30

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

0 голосов
/ 06 мая 2018

То, что вы пытаетесь сделать, это взять ссылку на 3 переменные, чтобы изменить их в функции калькулятора Вы можете просто определить функцию как:

void calculator(int cool_array[], int &first_num, int &second_num, int &third_num)

Тогда, конечно, вам не нужно использовать оператор разыменования вниз в функции калькулятора, просто скажите first_num = one , и вы будете изменять исходную переменную.

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