努力理解如何在 scanf 中调用指向指针的指针
Struggling to understand how to call a pointer to pointer in scanf
我正在用 C 构建一个程序,以便 运行 为我的博士研究进行一些模拟。基本上,该程序使用一个函数来读取具有一些重要值的输入文件,然后将这些值分配给 main
函数中的变量。其中一些值需要分配给数组 x
和 par
,其大小也在输入文件中声明。为此,我需要在函数内部使用一些动态分配的内存,指向指针 *x
和 *par
.
的地址
我设法使用二维数组表示法为这些指针赋值,但我不完全理解为什么需要这样,因为函数指向的指针被初始化为 NULL
指针。
这里以最小功能代码为例:
#include <stdio.h>
#include <stdlib.h>
void read_input(char *name, int *dim, int *npar, int *np, int *ndiv, double *t, double **par, double **x);
int main(void) {
int DIM;
int nP;
int nDiv;
int nPar;
// Assign values for program parameters, system parameters and initial conditions
char *input_filename = "input.txt";
double t;
double *par = NULL;
double *x = NULL;
read_input(input_filename, &DIM, &nPar, &nP, &nDiv, &t, &par, &x);
for (int i = 0; i < DIM; i++) {
printf("x[%i] = %.15lf\n", i, x[i]);
}
for (int i = 0; i < nPar; i++) {
printf("par[%i] = %lf\n", i, par[i]);
}
free(x);
free(par);
}
void read_input(char *name, int *dim, int *npar, int *np, int *ndiv, double *t, double **par, double **x) {
// Open input file
FILE *input = fopen(name, "r");
if (input == NULL) {
printf("Input File Not Found...\n");
return;
}
// Read and assign system constants
fscanf(input, "%i", dim);
fscanf(input, "%i", npar);
// Read and assign program parameters
fscanf(input, "%i %i", np, ndiv);
// Read and assign initial time
fscanf(input, "%lf", t);
// Allocate memory for x[dim] and par[npar] vectors
*x = malloc((*dim) * sizeof(double));
*par = malloc((*npar) * sizeof(double));
// Security check for pointers
if (*x == NULL || *par == NULL) {
free(*x);
free(*par);
printf("Memory allocation for *x or *par did not complete successfully");
return;
}
// assign IC to x[dim] vector
for (int i = 0; i < *dim; i++) {
fscanf(input, "%lf ", &x[i][i]);
}
for (int i = 0; i < *dim; i++) {
for (int j = 0; j < *dim; j++) {
printf("x[%i][%i] = %lf (address: %p)\n", i, j, x[i][j], &x[i][j]);
}
}
printf("==============================\n");
// Assign values to par[npar] vector
for (int i = 0; i < *npar; i++) {
fscanf(input, "%lf\n", &par[i][i]);
}
for (int i = 0; i < *npar; i++) {
for (int j = 0; j < *npar; j++) {
printf("par[%i][%i] = %lf (address: %p)\n", i, j, par[i][j], &par[i][j]);
}
}
printf("==============================\n");
// Close input file
fclose(input);
}
此外,我检查了双指针x[i][j]
和par[i][j]
指向的地址,它们对于[i][0], ..., [i][4]
和[=22=的每个组合都是相同的]:
x[0][0] = 0.707107 (address: 0000020B01C33FC0)
x[0][1] = 0.000000 (address: 0000020B01C33FC8)
x[1][0] = 0.707107 (address: 0000020B01C33FC0)
x[1][1] = 0.000000 (address: 0000020B01C33FC8)
==============================
par[0][0] = 1.000000 (address: 0000020B01C34580)
par[0][1] = 0.150000 (address: 0000020B01C34588)
par[0][2] = 0.025000 (address: 0000020B01C34590)
par[0][3] = -0.500000 (address: 0000020B01C34598)
par[0][4] = 1.000000 (address: 0000020B01C345A0)
par[1][0] = 1.000000 (address: 0000020B01C34580)
par[1][1] = 0.150000 (address: 0000020B01C34588)
par[1][2] = 0.025000 (address: 0000020B01C34590)
par[1][3] = -0.500000 (address: 0000020B01C34598)
par[1][4] = 1.000000 (address: 0000020B01C345A0)
par[2][0] = 1.000000 (address: 0000020B01C34580)
par[2][1] = 0.150000 (address: 0000020B01C34588)
par[2][2] = 0.025000 (address: 0000020B01C34590)
par[2][3] = -0.500000 (address: 0000020B01C34598)
par[2][4] = 1.000000 (address: 0000020B01C345A0)
par[3][0] = 1.000000 (address: 0000020B01C34580)
par[3][1] = 0.150000 (address: 0000020B01C34588)
par[3][2] = 0.025000 (address: 0000020B01C34590)
par[3][3] = -0.500000 (address: 0000020B01C34598)
par[3][4] = 1.000000 (address: 0000020B01C345A0)
par[4][0] = 1.000000 (address: 0000020B01C34580)
par[4][1] = 0.150000 (address: 0000020B01C34588)
par[4][2] = 0.025000 (address: 0000020B01C34590)
par[4][3] = -0.500000 (address: 0000020B01C34598)
par[4][4] = 1.000000 (address: 0000020B01C345A0)
==============================
x[0] = 0.707106781186547
x[1] = 0.000000000000000
par[0] = 1.000000
par[1] = 0.150000
par[2] = 0.025000
par[3] = -0.500000
par[4] = 1.000000
input.txt 文件的格式如下:
2
5
1000 1000
0.0
0.707106781186547 0.0
1.0
0.15
0.025
-0.5
1.0
我在这里错过了什么?
我设法在一些文章中找到了为指针赋值的正确方法:
为此,应通过一维数组表示法访问指针,方法是将指针本身调用为:
scanf("%lf", &(*x)[i]);
而不是
scanf("%lf", &x[i][i]);
那么,就可以正确赋值了。
在二维索引中的第一个索引不是 0
的所有情况下,发布的代码都有未定义的行为。例如:
fscanf(input, "%lf ", &x[i][i]);
x
是main
函数中指向int
的指针地址。
x[i]
仅在 i
为 0
时才定义,否则您正在从内存中超出 main
局部变量的位置读取,该位置未定义行为,但可能会或可能不会导致问题。
x[i][i]
取消引用值 x[i]
,这可能是一个无效指针,因此极有可能导致崩溃。仅将此地址作为 &x[i][i]
可能仍未引起注意,但是当 fscanf()
尝试将 int
存储在那里时,取消引用 &x[i][i]
将是一个问题。
令人惊讶的是,您的程序可以毫无问题地产生输出。
这个循环的正确语法是
// assign IC to x[dim] vector
for (int i = 0; i < *dim; i++) {
fscanf(input, "%lf ", &(*x)[i]);
}
&(*x)[i]
是 *x
指向的数组的第 i
个元素的地址。还有其他的可能性,none其中令人满意的:
&x[0][i]
(*x) + i
*x + i
x[0] + i
i + *x
&0[x][i]
&i[*x]
&i[0[x]]
i+0[x]
是的,以上都是等价的...
更好的做法是在read_input
中定义正确类型的局部变量,运行成功后传回给调用者。您还可以将所有这些变量分组在一个结构中,并将指针传递给 read_input
:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int read_input(const char *name, int *pdim, int *pnpar,
int *pnp, int *pndiv, double *pt,
double **ppar, double **px)
{
// use regular variables
int dim, npar, np, ndiv;
double t;
double *par = NULL;
double *px = NULL;
// Open input file
FILE *input = fopen(name, "r");
if (input == NULL) {
printf("Cannot open file %s: %s\n", name, strerror(errno));
return -1;
}
// Read and assign system constants
if (fscanf(input, "%i %i", &dim, &npar) != 2)
goto invalid;
// Read and assign program parameters
if (fscanf(input, "%i %i", &np, &ndiv) != 2)
goto invalid;
// Read and assign initial time
if (fscanf(input, "%lf", &t) != 1)
goto invalid;
// Allocate memory for x[dim] and par[npar] vectors
x = calloc(dim, sizeof(double));
par = calloc(npar, sizeof(double));
// Security check for pointers
if (x == NULL || par == NULL) {
printf("Memory allocation for x or par did not complete successfully\n");
free(x);
free(par);
fclose(input);
return -1;
}
// assign IC to x[dim] vector
for (int i = 0; i < dim; i++) {
if (fscanf(input, "%lf", &x[i]) != 1)
goto invalid;
}
// Assign values to par[npar] vector
for (int i = 0; i < npar; i++) {
if (fscanf(input, "%lf", &par[i]) != 1)
goto invalid;
}
// Close input file
fclose(input);
// update valid data to the caller
*pdim = dim;
*pnpar = npar;
*pnp = np;
*pndiv = ndiv;
*pt = t;
*px = x;
*ppar = par;
return 0;
invalid:
printf("Invalid or missing input\n");
free(x);
free(par);
fclose(input);
return -1;
}
我正在用 C 构建一个程序,以便 运行 为我的博士研究进行一些模拟。基本上,该程序使用一个函数来读取具有一些重要值的输入文件,然后将这些值分配给 main
函数中的变量。其中一些值需要分配给数组 x
和 par
,其大小也在输入文件中声明。为此,我需要在函数内部使用一些动态分配的内存,指向指针 *x
和 *par
.
我设法使用二维数组表示法为这些指针赋值,但我不完全理解为什么需要这样,因为函数指向的指针被初始化为 NULL
指针。
这里以最小功能代码为例:
#include <stdio.h>
#include <stdlib.h>
void read_input(char *name, int *dim, int *npar, int *np, int *ndiv, double *t, double **par, double **x);
int main(void) {
int DIM;
int nP;
int nDiv;
int nPar;
// Assign values for program parameters, system parameters and initial conditions
char *input_filename = "input.txt";
double t;
double *par = NULL;
double *x = NULL;
read_input(input_filename, &DIM, &nPar, &nP, &nDiv, &t, &par, &x);
for (int i = 0; i < DIM; i++) {
printf("x[%i] = %.15lf\n", i, x[i]);
}
for (int i = 0; i < nPar; i++) {
printf("par[%i] = %lf\n", i, par[i]);
}
free(x);
free(par);
}
void read_input(char *name, int *dim, int *npar, int *np, int *ndiv, double *t, double **par, double **x) {
// Open input file
FILE *input = fopen(name, "r");
if (input == NULL) {
printf("Input File Not Found...\n");
return;
}
// Read and assign system constants
fscanf(input, "%i", dim);
fscanf(input, "%i", npar);
// Read and assign program parameters
fscanf(input, "%i %i", np, ndiv);
// Read and assign initial time
fscanf(input, "%lf", t);
// Allocate memory for x[dim] and par[npar] vectors
*x = malloc((*dim) * sizeof(double));
*par = malloc((*npar) * sizeof(double));
// Security check for pointers
if (*x == NULL || *par == NULL) {
free(*x);
free(*par);
printf("Memory allocation for *x or *par did not complete successfully");
return;
}
// assign IC to x[dim] vector
for (int i = 0; i < *dim; i++) {
fscanf(input, "%lf ", &x[i][i]);
}
for (int i = 0; i < *dim; i++) {
for (int j = 0; j < *dim; j++) {
printf("x[%i][%i] = %lf (address: %p)\n", i, j, x[i][j], &x[i][j]);
}
}
printf("==============================\n");
// Assign values to par[npar] vector
for (int i = 0; i < *npar; i++) {
fscanf(input, "%lf\n", &par[i][i]);
}
for (int i = 0; i < *npar; i++) {
for (int j = 0; j < *npar; j++) {
printf("par[%i][%i] = %lf (address: %p)\n", i, j, par[i][j], &par[i][j]);
}
}
printf("==============================\n");
// Close input file
fclose(input);
}
此外,我检查了双指针x[i][j]
和par[i][j]
指向的地址,它们对于[i][0], ..., [i][4]
和[=22=的每个组合都是相同的]:
x[0][0] = 0.707107 (address: 0000020B01C33FC0)
x[0][1] = 0.000000 (address: 0000020B01C33FC8)
x[1][0] = 0.707107 (address: 0000020B01C33FC0)
x[1][1] = 0.000000 (address: 0000020B01C33FC8)
==============================
par[0][0] = 1.000000 (address: 0000020B01C34580)
par[0][1] = 0.150000 (address: 0000020B01C34588)
par[0][2] = 0.025000 (address: 0000020B01C34590)
par[0][3] = -0.500000 (address: 0000020B01C34598)
par[0][4] = 1.000000 (address: 0000020B01C345A0)
par[1][0] = 1.000000 (address: 0000020B01C34580)
par[1][1] = 0.150000 (address: 0000020B01C34588)
par[1][2] = 0.025000 (address: 0000020B01C34590)
par[1][3] = -0.500000 (address: 0000020B01C34598)
par[1][4] = 1.000000 (address: 0000020B01C345A0)
par[2][0] = 1.000000 (address: 0000020B01C34580)
par[2][1] = 0.150000 (address: 0000020B01C34588)
par[2][2] = 0.025000 (address: 0000020B01C34590)
par[2][3] = -0.500000 (address: 0000020B01C34598)
par[2][4] = 1.000000 (address: 0000020B01C345A0)
par[3][0] = 1.000000 (address: 0000020B01C34580)
par[3][1] = 0.150000 (address: 0000020B01C34588)
par[3][2] = 0.025000 (address: 0000020B01C34590)
par[3][3] = -0.500000 (address: 0000020B01C34598)
par[3][4] = 1.000000 (address: 0000020B01C345A0)
par[4][0] = 1.000000 (address: 0000020B01C34580)
par[4][1] = 0.150000 (address: 0000020B01C34588)
par[4][2] = 0.025000 (address: 0000020B01C34590)
par[4][3] = -0.500000 (address: 0000020B01C34598)
par[4][4] = 1.000000 (address: 0000020B01C345A0)
==============================
x[0] = 0.707106781186547
x[1] = 0.000000000000000
par[0] = 1.000000
par[1] = 0.150000
par[2] = 0.025000
par[3] = -0.500000
par[4] = 1.000000
input.txt 文件的格式如下:
2
5
1000 1000
0.0
0.707106781186547 0.0
1.0
0.15
0.025
-0.5
1.0
我在这里错过了什么?
我设法在一些文章中找到了为指针赋值的正确方法:
为此,应通过一维数组表示法访问指针,方法是将指针本身调用为:
scanf("%lf", &(*x)[i]);
而不是
scanf("%lf", &x[i][i]);
那么,就可以正确赋值了。
在二维索引中的第一个索引不是 0
的所有情况下,发布的代码都有未定义的行为。例如:
fscanf(input, "%lf ", &x[i][i]);
x
是main
函数中指向int
的指针地址。x[i]
仅在i
为0
时才定义,否则您正在从内存中超出main
局部变量的位置读取,该位置未定义行为,但可能会或可能不会导致问题。x[i][i]
取消引用值x[i]
,这可能是一个无效指针,因此极有可能导致崩溃。仅将此地址作为&x[i][i]
可能仍未引起注意,但是当fscanf()
尝试将int
存储在那里时,取消引用&x[i][i]
将是一个问题。
令人惊讶的是,您的程序可以毫无问题地产生输出。
这个循环的正确语法是
// assign IC to x[dim] vector
for (int i = 0; i < *dim; i++) {
fscanf(input, "%lf ", &(*x)[i]);
}
&(*x)[i]
是 *x
指向的数组的第 i
个元素的地址。还有其他的可能性,none其中令人满意的:
&x[0][i]
(*x) + i
*x + i
x[0] + i
i + *x
&0[x][i]
&i[*x]
&i[0[x]]
i+0[x]
是的,以上都是等价的...
更好的做法是在read_input
中定义正确类型的局部变量,运行成功后传回给调用者。您还可以将所有这些变量分组在一个结构中,并将指针传递给 read_input
:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int read_input(const char *name, int *pdim, int *pnpar,
int *pnp, int *pndiv, double *pt,
double **ppar, double **px)
{
// use regular variables
int dim, npar, np, ndiv;
double t;
double *par = NULL;
double *px = NULL;
// Open input file
FILE *input = fopen(name, "r");
if (input == NULL) {
printf("Cannot open file %s: %s\n", name, strerror(errno));
return -1;
}
// Read and assign system constants
if (fscanf(input, "%i %i", &dim, &npar) != 2)
goto invalid;
// Read and assign program parameters
if (fscanf(input, "%i %i", &np, &ndiv) != 2)
goto invalid;
// Read and assign initial time
if (fscanf(input, "%lf", &t) != 1)
goto invalid;
// Allocate memory for x[dim] and par[npar] vectors
x = calloc(dim, sizeof(double));
par = calloc(npar, sizeof(double));
// Security check for pointers
if (x == NULL || par == NULL) {
printf("Memory allocation for x or par did not complete successfully\n");
free(x);
free(par);
fclose(input);
return -1;
}
// assign IC to x[dim] vector
for (int i = 0; i < dim; i++) {
if (fscanf(input, "%lf", &x[i]) != 1)
goto invalid;
}
// Assign values to par[npar] vector
for (int i = 0; i < npar; i++) {
if (fscanf(input, "%lf", &par[i]) != 1)
goto invalid;
}
// Close input file
fclose(input);
// update valid data to the caller
*pdim = dim;
*pnpar = npar;
*pnp = np;
*pndiv = ndiv;
*pt = t;
*px = x;
*ppar = par;
return 0;
invalid:
printf("Invalid or missing input\n");
free(x);
free(par);
fclose(input);
return -1;
}