按地址传递、scanf、取消引用

Pass by address, scanf, de-referencing

我编写了一个采用以下概念的程序:

我创建一个整数 x 通过地址传递给一个函数,连同一个文件名,该函数打开文件(如果可用),扫描第一行并将 pX 指向的值设置为等于到扫描线。

只是它不起作用,而且我看不出我做错了什么。据我所知,下面的代码通常是如何完成它的,但我不确定我是否没有正确使用 scanf() 指针或什么。

void foo() {
    char input[20] = "test.txt";
    int x = 1;
    bar(input, &x);
}

void bar(char *fileName, int *pX) {
    FILE *fp = fopen(fileName, "r");
    char *buffer = malloc(15 * sizeof(int));
    fgets(buffer, 15, fp);
    scanf(buffer, "%d", *pX);
    free(buffer);
    fclose(fp);
}

换行:

scanf(buffer, "%d", *pX);

至:

sscanf(buffer, "%d", pX);

您需要函数 sscanf 来完成您想要做的事情。

scanfsscanf都以指针作为参数。 pX 属于 int * 类型,因此指向 int 的指针应该适合您。您传递的 *pX 是此指针的 内容 ,换句话说,int.

此外,更改行:

char *buffer = malloc(15 * sizeof(int));

至:

char *buffer = malloc(15 * sizeof(char));

或者简单地说:

char *buffer = malloc(15);

并且总是 check the result of malloc :

if (buffer == NULL){
    ...
}

首先,C语言中没有引用传递,函数参数都是按值传递的。通过传递一个指向数据的指针,我们模拟实现了与pass-by-reference相同的效果,但这并不意味着C有任何pass-by-reference的概念。

也就是说,问题好像是

 scanf(buffer, "%d", *pX);
                     ^^^^

其中

  • 当前语法无效并调用 undefined behavior. Probably you need sscanf().

  • px 已经是指向 int 的指针。通过 px 将是正确且足够的。

故事的寓意:启用编译器警告并注意它们。他们在那里是有原因的。启用适当的警告后,您应该会看到类似

的内容

warning: format %d expects argument of type int *, but argument 3 has type int [-Wformat=]

最后,

  • 在使用文件指针之前,始终检查 fopen() 的 return 值是否成功。
  • 检查 scanf() 的 return 值以确保扫描成功。
  • 检查 fgets() 的 return 值以确保成功

...基本上,检查所有库调用的 return 值以确保它们按预期工作

你错误地使用了scanf():要么直接使用scanf解析标准输入,要么使用sscanf()解析fgets()读取的字符串。再者,pX已经是指向int的指针了,也就是sscanf()期望存放它转换的int值,直接传过去:sscanf(buffer, "%d", pX);

这是修改后的版本:

int bar(const char *fileName, int *pX) {
    char buffer[15];
    FILE *fp = fopen(fileName, "r");
    int success = 0;

    if (fp != NULL) {
        fgets(buffer, sizeof buffer, fp);
        if (sscanf(buffer, "%d", pX) == 1)
            success = 1;
        fclose(fp);
    }
    return success;
}

void foo(void) {
    int x = 1;
    bar("test.txt", &x);
    /* do something with x */
}

备注:

  • 不需要分配buf,只需要将其设为自动存储的本地数组即可。
  • char *buffer = malloc(15 * sizeof(int)); 是不正确的:您分配 space 给 15 int 而不是 15 个字符,根据定义其大小为 1。使用目标类型的大小来避免任何不一致:

    char *buffer = malloc(15 * sizeof(*buffer));
    
  • 始终检查 malloc() 的 return 值以避免潜在的未定义行为。

  • fp 读取而不检查 fopen 是否成功有潜在的未定义行为。
  • 不修改filename指向的数组内容,使之成为const char *.
  • 它可能对 bar 到 return 一个成功指标有用。
  • 在编译时启用更多警告:gcc -Wall -Wextra -Werrorclang -Weverything -Werror 可能发现了 scanf 中的错误。