解决方法:ISO C90 禁止可变长度数组

Workaround: ISO C90 forbids variable length array

我正在读取一个名为 reg.dat 的文件,并将每列中的第一个变量设置为变量 Y 的索引,并将每列中的其余变量设置为 X 的索引。然后,我想要将 X 和 Y 输入 dgesv 函数以计算线性回归。

我的代码如下(分块,因为我无法一次将其全部包含在此网站上)。我在 运行 gcc -ansi -pedantic readReg.c -o readReg -llapack -lblas -lgfortran 时得到的错误如下:

readReg.c: In function ‘main’:
readReg.c:18: warning: ISO C90 forbids variable length array ‘ipiv’
readReg.c:19: warning: ISO C90 forbids variable length array ‘X1’
readReg.c:19: warning: ISO C90 forbids variable length array ‘X1’
readReg.c:19: warning: ISO C90 forbids variable length array ‘XtX’
readReg.c:19: warning: ISO C90 forbids variable length array ‘XtY’
readReg.c:48: error: subscripted value is neither array nor pointer

例如,如果文件 reg.dat 是:

5.1 3.5 1.4
4.9 3 1.4
4.7 3.2 1.3
4.6 3.1 1.5
5 3.6 1.4

然后 X = [5.1, 4.9, 4.7, 4.6, 5] 和 Y = [3.5, 1.4, 3, 1.4, 3.2, 1.3, 3.1, 1.5, 3.6, 1.4]:

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

int getCol(char *myStr);
int getRow(char *fileName);
int assignY(int nCol, int nRow, double *Y, char *fileName);
int assignX(int nCol, int nRow, double *X, char *fileName);
void dgesv_(int *n, int *nrhs, double *a, int *lda, int *ipiv, double *b, int *ldb, int *info);

int main(){
   FILE *f;
   char myStr[1000];
   int strL;
   int nCol;
   int nRow;
   char *fileName = "reg.dat";
   int i, j, k, n1=nCol, n2=1, ipiv[nCol], info;
   double X1[nRow][nCol], XtX[(nCol) * (nCol)], XtY[nCol];

   double *X;
   double *Y;

   f = fopen(fileName, "r");
   if (f == NULL) perror ("Error opening file");
   else {
     if (fgets(myStr, 1000, f) != NULL ) 
       puts(myStr); 
     fclose(f);
   }     

   strL = strlen(myStr);
   nCol = getCol(myStr);
   nRow = getRow(fileName);
   printf("Sample size and number of predictors are %d and %d respectively.\n", nRow, nCol-1);

   X = (double *) malloc(sizeof(double) * ((nCol-1) * nRow));
   Y = (double *) malloc(sizeof(double) * nRow);
   assignY(nCol, nRow, Y, fileName);
   assignX(nCol, nRow, X, fileName);

接下来,我操纵 X 和 Y...

   /* The following is for doing the dgesv function */

  /* design matrix */
  for (i=0; i<nRow; i++){
    X1[i][0] = 1;
    for (j=1; j<n1; j++)
      X1[i][j] = X[i][j-1];
  }

  /* t(X1) %*% X1 */
  for (i=0; i<n1; i++){
    for (j=0; j<n1; j++){
      XtX[i*n1+j] = 0;
      for (k=0; k<nRow; k++)
        XtX[i*n1+j] += X1[k][i] * X1[k][j];
    }
  }

  /* t(X1) %*% Y */
  for (i=0; i<n1; i++){
    XtY[i] = 0;
    for (j=0; j<nRow; j++){
      XtY[i] += X1[j][i] * Y[j];
    }
  }

接下来我打印结果

  /* XtX is symmetric, no transpose needed before passing to Fortran subrountine */
  dgesv_(&n1, &n2, XtX, &n1, ipiv, XtY, &n1, &info);
  if (info!=0)  printf("failure with error %d\n", info);

  /* print beta */
  printf("The regression coefficients: ");
  for (i=0; i<n1; i++){
    printf("%f ", XtY[i]);
  }
  printf("\n");

   return 0;
}

辅助函数...

int assignY(int nCol, int nRow, double *Y, char *fileName){
  int i=0;
  int j;
  char string[1000];
  char* data = NULL;
  FILE *f;
  f = fopen(fileName, "r");

  while(fgets(string, sizeof(string), f) != NULL){
    data = strtok(string, " ");
    for (j=0; NULL != data && j<nCol; j++){
        if (data[strlen(data) - 1] == '\n')
            data[strlen(data) - 1] = '[=15=]';

        if (j==0){
          Y[i] = atof(data);
          i++;
        }
        data = strtok(NULL, " ");
    }
  }

  for (i=0;i<nRow;i++){
    printf("%f\n", Y[i]);
  }
  return 0;
}

辅助函数...

int assignX(int nCol, int nRow, double *X, char *fileName){
  int i=0;
  int j;
  char string[1000];
  char* data = NULL;
  FILE *f;
  f = fopen(fileName, "r");

  while(fgets(string, sizeof(string), f) != NULL){
    data = strtok(string, " ");
    for (j=0; NULL != data && j<nCol; j++){
        if (data[strlen(data) - 1] == '\n')
            data[strlen(data) - 1] = '[=16=]';

        if (j!=0){
          X[i] = atof(data);
          i++;
        }
        data = strtok(NULL, " ");
    }
  }

  for (i=0;i<(nRow*(nCol-1));i++){
    printf("%f\n", X[i]);
  }
  return 0;
}

辅助函数...

int getCol(char *myStr){
    int length,i,count=0;
    char prev;
    length=strlen(myStr);
    if(length > 0){
      prev = myStr[0];
    }
    for(i=0; i<=length; i++){
      if(myStr[i]==' ' && prev != ' '){
        count++;
      }
      prev = myStr[i];
    }
    if(count > 0 && myStr[i] != ' '){
        count++;
    }
    return count;
}

int getRow(char *fileName){
  char ch;
  int count=0;
  FILE *f;
  f = fopen(fileName, "r");

  while(!feof(f)){
    ch = fgetc(f);
    if(ch == '\n')
    {
      count++;
    }
  }
fclose(f);
return count;
} 

编辑:

我现在为 X1、XtY、XtX 和 ipiv 更改为 malloc()。我现在还为 X1 使用了多维动态数组。当我 运行 gcc 时,错误都消失了,除了:

readReg.c: In function ‘main’:
readReg.c:62: error: subscripted value is neither array nor pointer

下面是更新后的主函数:

int main(){
   FILE *f;
   char myStr[1000];
   int strL;
   int nCol;
   int nRow;
   char *fileName = "reg.dat";
   int i, j, k, n1=nCol, n2=1, info;

   double *X;
   double *Y;
   double **X1;
   double *XtX;
   double *XtY;
   int *ipiv;
   double *temp;

   f = fopen(fileName, "r");
   if (f == NULL) perror ("Error opening file");
   else {
     if (fgets(myStr, 1000, f) != NULL )
       puts(myStr);
     fclose(f);
   }

   strL = strlen(myStr);
   nCol = getCol(myStr);
   nRow = getRow(fileName);
   printf("Sample size and number of predictors are %d and %d respectively.\n", nRow, nCol-1);

   X = (double *) malloc(sizeof(double) * ((nCol-1) * nRow));
   Y = (double *) malloc(sizeof(double) * nRow);
   XtX = (double *) malloc(sizeof(double) * (nCol*nCol));
   XtY = (double *) malloc(sizeof(double) * nCol);
   ipiv = (int *) malloc(sizeof(int) * nCol);

   assignY(nCol, nRow, Y, fileName);
   assignX(nCol, nRow, X, fileName);

   X1 = malloc(nRow * sizeof(double*));
   temp = malloc(nRow * nCol * sizeof(double));
   for (i= 0; i < nRow; i++) {
      X1[i] = temp + (i * nCol);
   }

...
}

您首先声明 nRow 和 nCol 而不分配任何值:

int nCol;
int nRow;

...现在定义四个使用 nRow 和 nCol 的可变长度数组:

int i, j, k, n1=nCol, n2=1, ipiv[nCol], info;
double X1[nRow][nCol], XtX[(nCol) * (nCol)], XtY[nCol];

首先,C90禁止使用变长数组。对这些使用 malloc()。根据您的代码,您似乎知道如何使用 malloc()

其次,在为 nColnRow 赋值之前声明数组时,您如何期望编译器知道数组有多大?

你的一个数组是多维的。有关如何使用动态多维数组的详细信息,请参阅 How do I work with dynamic multi-dimensional arrays in C?