为什么在动态创建变量时会出现未声明的标识符错误?

时间:2021-01-28 09:44:36

I've seen this question and I noticed that I get errors when I declare variables in the middle of the main() function, but I thought that creating variables dynamically wouldn't cause an error, because it can be done anywhere and anytime during run-time (as far as I know).

我已经看到了这个问题,并且注意到在main()函数的中间声明变量时出现了错误,但是我认为动态创建变量不会导致错误,因为在运行时(据我所知)可以在任何地方和任何时间执行它。

However, I still get:

然而,我仍然得到:

error C2065: 'i' : undeclared identifier
error C2065: 'z' : undeclared identifier
error C2065: 'intArr' : undeclared identifier

My code:

我的代码:

int main()
{
  ..... 
  .....
  ..... 

  printf("Type the array size:\t");
  int *z = (int *)malloc(sizeof(int));
  scanf("%d", z);
  int *intArr = (int *)malloc((*z) * sizeof(int));

  int *i = (int *)malloc(sizeof(int));

  for (*i = 0; *i < *z; ((*i)++))
  {
      printf("Type a number\t");
      scanf("%d", (intArr+(*i)));
  }

  printArr(intArr);
}

void printArr(int *arr)
{
    int i; 
    for (i = 0; i < (sizeof(arr) / sizeof(*arr)); ++i)
        printf("%d ", *(arr+i));
}

1 个解决方案

#1


1  

(I'm not sure why @Blood deleted his answer; it was essentially correct.)

(我不知道为什么@Blood删除了他的答案;它本质上是正确的。)

When I compile your program using gcc, it compiles with no errors. I had to add

当我使用gcc编译您的程序时,它没有任何错误。我已经添加

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

to the top, and delete the three ..... lines.

最上面,删除三个……行。

When I compile the same program using Microsoft's Visual C++ 2010 Express, I get a number of errors. Several of them complain about undeclared identifiers, but that's a common side effect of syntax errors; if the compiler can't parse your source file, it's likely to become "confused" as it tries to recover. The most relevant error is:

当我使用微软的Visual c++ 2010 Express编译相同的程序时,我得到了许多错误。其中一些抱怨未声明的标识符,但这是语法错误的常见副作用;如果编译器不能解析您的源文件,它可能会在试图恢复时变得“混乱”。最相关的错误是:

syntax error : missing ';' before 'type'

on line 10:

10号线:

printf("Type the array size:\t");     // line 9
int *z = (int *)malloc(sizeof(int));  // line 10

The problem is that the 1989/1990 version of the C standard doesn't permit mixing declarations and statements within a block; it requires all declarations to appear first, followed by all statements. The 1999 C standard changed that, but Microsoft's C compiler has very limited support for any C standard past the 1990 one (and they've said they have no intention of changing that). (I expect they might permit mixed declarations and statements in a future version, since that's a C++ feature as well.)

问题是,1989/1990年版的C标准不允许在一个块中混合声明和语句;它需要首先出现所有声明,然后是所有语句。1999年的C标准改变了这一点,但是微软的C编译器在1990年以后对任何C标准的支持都非常有限(他们说他们无意改变)。(我希望在将来的版本中,它们可能允许混合声明和语句,因为这也是一个c++特性。)

(I'm assuming from the form of the error messages that you're using a Microsoft compiler.)

(我从错误消息的形式假设您正在使用Microsoft编译器。)

You can rearrange your code to satisfy the Microsoft compiler's restrictions. In some cases, you might need to change something like

您可以重新排列代码以满足Microsoft编译器的限制。在某些情况下,您可能需要更改如下内容

int *var = initial_value;

to

int *var;
// ...
var = initial_value;

Another suggestion, not related to your question:

另一个与你的问题无关的建议:

In C, you shouldn't cast the result of malloc(). The malloc() function returns a value of type void*, which can be implicitly converted to any pointer-to-object type. (C++ doesn't have this implicit conversion, but you probably shouldn't be using malloc() in C++ anyway.)

在C语言中,不能使用malloc()的结果。函数的作用是:返回void*类型的值,可以隐式地转换为任何指针到对象的类型。(c++没有这种隐式转换,但您可能不应该在c++中使用malloc())。)

Rather than this:

而不是:

int *z = (int *)malloc(sizeof(int));
...
int *intArr = (int *)malloc((*z) * sizeof(int));

you can write this:

你可以这样写:

int *z = malloc(sizeof *z);
...
int *intArr = malloc(*z * sizeof *intArr);

Dropping the unnecessary cast can avoid certain errors; for example, with some compilers a cast can mask a necessary error message if you've forgotten the required #include <stdlib.h>. And applying sizeof to *z or *intArr, rather than naming the size explicitly, means that you won't have to change the call if the type of the pointer changes. If you write, for example:

删除不必要的cast可以避免某些错误;例如,如果您忘记了必需的#include ,那么对于某些编译器,强制转换可以屏蔽必要的错误消息。将sizeof应用到*z或*intArr,而不是显式地命名大小,这意味着如果指针的类型发生变化,您不必更改调用。如果你写作,例如:

double *p = malloc(sizeof (int)); // incorrect

then you're allocating the wrong size, but the compiler won't warn you about it.

然后您分配了错误的大小,但是编译器不会警告您。

Also, if you're allocating a single int value using malloc(), as you're doing with your i and z pointers, you're doing unnecessary work. Unless your purpose is to practice using malloc(), you might as well just make i and z int variables, and drop the malloc() calls. You'll just have to pass their addresses to scanf. In other words, you can change this:

另外,如果使用malloc()分配一个int值,就像使用i和z指针一样,那么您就在做不必要的工作。除非您的目的是使用malloc()进行实践,否则您最好只创建i和z int变量,并删除malloc()调用。你只需要把他们的地址传递给scanf。换句话说,你可以改变这一点:

int *z = (int *)malloc(sizeof(int));
...
scanf("%d", z);

to this:

:

int z;
...
scanf("%d", &z);

One more point: your program has no error checking. malloc() can fail if there isn't enough memory to allocate; it returns a null pointer (NULL) when this happens. scanf() can fail if there's an input error, or if you type hello when it's expecting to read an int. scanf() returns the number of items it successfully scanned; you should verify that it did so (in this case, it returns 1 on success). For a simple program like this, aborting the program with an error message:

还有一点:你的程序没有错误检查。如果没有足够的内存来分配,malloc()可能会失败;当发生这种情况时,它返回一个空指针(null)。如果有输入错误,或者当您输入hello时,它希望读取int. scanf(),那么scanf()可能会失败;您应该验证它这样做了(在本例中,它在成功时返回1)。对于这样的简单程序,使用错误消息中止程序:

fprintf(stderr, "Call to ... failed\n");
exit(EXIT_FAILURE);

is probably good enough.

可能是不够好。

#1


1  

(I'm not sure why @Blood deleted his answer; it was essentially correct.)

(我不知道为什么@Blood删除了他的答案;它本质上是正确的。)

When I compile your program using gcc, it compiles with no errors. I had to add

当我使用gcc编译您的程序时,它没有任何错误。我已经添加

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

to the top, and delete the three ..... lines.

最上面,删除三个……行。

When I compile the same program using Microsoft's Visual C++ 2010 Express, I get a number of errors. Several of them complain about undeclared identifiers, but that's a common side effect of syntax errors; if the compiler can't parse your source file, it's likely to become "confused" as it tries to recover. The most relevant error is:

当我使用微软的Visual c++ 2010 Express编译相同的程序时,我得到了许多错误。其中一些抱怨未声明的标识符,但这是语法错误的常见副作用;如果编译器不能解析您的源文件,它可能会在试图恢复时变得“混乱”。最相关的错误是:

syntax error : missing ';' before 'type'

on line 10:

10号线:

printf("Type the array size:\t");     // line 9
int *z = (int *)malloc(sizeof(int));  // line 10

The problem is that the 1989/1990 version of the C standard doesn't permit mixing declarations and statements within a block; it requires all declarations to appear first, followed by all statements. The 1999 C standard changed that, but Microsoft's C compiler has very limited support for any C standard past the 1990 one (and they've said they have no intention of changing that). (I expect they might permit mixed declarations and statements in a future version, since that's a C++ feature as well.)

问题是,1989/1990年版的C标准不允许在一个块中混合声明和语句;它需要首先出现所有声明,然后是所有语句。1999年的C标准改变了这一点,但是微软的C编译器在1990年以后对任何C标准的支持都非常有限(他们说他们无意改变)。(我希望在将来的版本中,它们可能允许混合声明和语句,因为这也是一个c++特性。)

(I'm assuming from the form of the error messages that you're using a Microsoft compiler.)

(我从错误消息的形式假设您正在使用Microsoft编译器。)

You can rearrange your code to satisfy the Microsoft compiler's restrictions. In some cases, you might need to change something like

您可以重新排列代码以满足Microsoft编译器的限制。在某些情况下,您可能需要更改如下内容

int *var = initial_value;

to

int *var;
// ...
var = initial_value;

Another suggestion, not related to your question:

另一个与你的问题无关的建议:

In C, you shouldn't cast the result of malloc(). The malloc() function returns a value of type void*, which can be implicitly converted to any pointer-to-object type. (C++ doesn't have this implicit conversion, but you probably shouldn't be using malloc() in C++ anyway.)

在C语言中,不能使用malloc()的结果。函数的作用是:返回void*类型的值,可以隐式地转换为任何指针到对象的类型。(c++没有这种隐式转换,但您可能不应该在c++中使用malloc())。)

Rather than this:

而不是:

int *z = (int *)malloc(sizeof(int));
...
int *intArr = (int *)malloc((*z) * sizeof(int));

you can write this:

你可以这样写:

int *z = malloc(sizeof *z);
...
int *intArr = malloc(*z * sizeof *intArr);

Dropping the unnecessary cast can avoid certain errors; for example, with some compilers a cast can mask a necessary error message if you've forgotten the required #include <stdlib.h>. And applying sizeof to *z or *intArr, rather than naming the size explicitly, means that you won't have to change the call if the type of the pointer changes. If you write, for example:

删除不必要的cast可以避免某些错误;例如,如果您忘记了必需的#include ,那么对于某些编译器,强制转换可以屏蔽必要的错误消息。将sizeof应用到*z或*intArr,而不是显式地命名大小,这意味着如果指针的类型发生变化,您不必更改调用。如果你写作,例如:

double *p = malloc(sizeof (int)); // incorrect

then you're allocating the wrong size, but the compiler won't warn you about it.

然后您分配了错误的大小,但是编译器不会警告您。

Also, if you're allocating a single int value using malloc(), as you're doing with your i and z pointers, you're doing unnecessary work. Unless your purpose is to practice using malloc(), you might as well just make i and z int variables, and drop the malloc() calls. You'll just have to pass their addresses to scanf. In other words, you can change this:

另外,如果使用malloc()分配一个int值,就像使用i和z指针一样,那么您就在做不必要的工作。除非您的目的是使用malloc()进行实践,否则您最好只创建i和z int变量,并删除malloc()调用。你只需要把他们的地址传递给scanf。换句话说,你可以改变这一点:

int *z = (int *)malloc(sizeof(int));
...
scanf("%d", z);

to this:

:

int z;
...
scanf("%d", &z);

One more point: your program has no error checking. malloc() can fail if there isn't enough memory to allocate; it returns a null pointer (NULL) when this happens. scanf() can fail if there's an input error, or if you type hello when it's expecting to read an int. scanf() returns the number of items it successfully scanned; you should verify that it did so (in this case, it returns 1 on success). For a simple program like this, aborting the program with an error message:

还有一点:你的程序没有错误检查。如果没有足够的内存来分配,malloc()可能会失败;当发生这种情况时,它返回一个空指针(null)。如果有输入错误,或者当您输入hello时,它希望读取int. scanf(),那么scanf()可能会失败;您应该验证它这样做了(在本例中,它在成功时返回1)。对于这样的简单程序,使用错误消息中止程序:

fprintf(stderr, "Call to ... failed\n");
exit(EXIT_FAILURE);

is probably good enough.

可能是不够好。