首页 > 解决方案 > 如何使指针起作用?

问题描述

我有 2 个功能。第一个函数称为“选择器”,它将 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;
}

标签: carraysfunctionpointersprintf

解决方案


正如我在上面的评论中所表达的,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;分配to的地址 。我们已经讨论了地址的问题,但还有另一个根本问题。in是in指针的副本。副本有它自己的(并且非常不同的)地址。如果有一个存储持续时间,您返回后仍然不会看到任何更改。为什么?因为在您中,您只是将指针的副本从.onefirst_num onefirst_numcalculatorfirst_numchoosercalculatoronecalculatorfirst_numchoosercalculatorchooser

然而,虽然first_numincalculator是一个副本,但它作为其值保存的地址与 in 的指针完全相同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

如果您还有其他问题,请仔细查看并告诉我。


推荐阅读