在过去的几年里,我并没有非常使用过C语言.当我今天读到这个问题时,我遇到了一些我不熟悉的C语法.
显然在C99中,以下语法有效:
void foo(int n) {
int values[n]; //Declare a variable length array
}
Run Code Online (Sandbox Code Playgroud)
这似乎是一个非常有用的功能.有没有关于将它添加到C++标准的讨论,如果是这样,为什么它被省略?
一些潜在的原因:
C++标准规定数组大小必须是常量表达式(8.3.4.1).
是的,当然我意识到在玩具示例中可以使用std::vector<int> values(m);,但这会从堆中分配内存而不是堆栈.如果我想要一个多维数组,如:
void foo(int x, int y, int z) {
int values[x][y][z]; // Declare a variable length array
}
Run Code Online (Sandbox Code Playgroud)
该vector版本变得很笨拙:
void foo(int x, int y, int z) {
vector< vector< vector<int> > > values( /* Really painful expression here. */);
}
Run Code Online (Sandbox Code Playgroud)
切片,行和列也可能遍布整个内存.
看一下comp.std.c++这个问题的讨论很明显,这个问题在争论的两个方面都有一些非常重要的名字引起争议.毫无疑问,a std::vector总是更好的解决方案.
使用可变长度数组有一些开销吗?可以在运行时通过命令行参数传递数组的大小吗?与自动和动态分配数组相比,为什么会引入它?
假设这些代码编译成g++:
#include <stdlib.h>
int main() {
int a =0;
goto exit;
int *b = NULL;
exit:
return 0;
}
Run Code Online (Sandbox Code Playgroud)
g++ 会抛出错误:
goto_test.c:10:1: error: jump to label ‘exit’ [-fpermissive]
goto_test.c:6:10: error: from here [-fpermissive]
goto_test.c:8:10: error: crosses initialization of ‘int* b’
Run Code Online (Sandbox Code Playgroud)
似乎goto无法跨越指针定义,但gcc编译好,没有任何抱怨.
修复错误之后,我们必须在任何goto语句之前声明所有指针,也就是说你必须声明这些指针,即使你现在不需要它们(并且违反了一些原则).
什么原因设计考虑g++禁止有用的尾部goto声明?
更新:
goto可以交叉变量(任何类型的变量,不限于指针)声明,但除了那些获得初始化值.如果我们删除NULL上面的任务,g++请立即保持沉默.因此,如果要声明goto-cross-area 之间的变量,请不要初始化它们(并且仍然违反某些原则).
我从许多人那里听说,在C99中引入的可变长度阵列非常糟糕.IRC的一些人在一分钟之前说过"我不认为C++会得到VLA,而strousoup对他们做了一些非常负面的评论".
这些人讨厌VLA的原因是什么?
我已经阅读了很多alloca过时的地方,不应该使用,而应该使用可变长度数组.
我的问题是:alloca可变长度数组是否完全可以替换?
在我的特定实例中,我有一些看起来像这样的东西:
typedef struct {
int *value;
size_t size;
} some_type;
void SomeExternalFunction(some_type);
...
void foo(){
//What I thought to do
some_type bar;
bar.value=alloca(sizeof(int)*10);
SomeExternalFunction(bar);
//what should be done without alloca
some_type fizz;
int tmp[10];
fizz.value=tmp;
SoemExternalFunction(fizz);
}
Run Code Online (Sandbox Code Playgroud)
我错过了什么或者这是对alloca的实际使用吗?另外假设这个例子由于某种原因我想要在堆栈上分配值
我想问一下 C 中的 struct 声明。例如,
struct Person
{
char name[50];
int citNo;
float salary;
} prsn[20];
Run Code Online (Sandbox Code Playgroud)
有什么作用[20]?这是什么意思?是将名称限制为 20(从 50)还是将prsnfrom限制prsn[1]为prsn[20]?
如果我写这样的代码:
struct Person
{
char name[50];
int citNo;
float salary;
};
struct Person prsn[20];
Run Code Online (Sandbox Code Playgroud)
它做同样的事情吗?
从我们的嵌入式系统代码中删除对malloc和calloc的所有调用后,我惊讶地发现malloc仍然被链接.调用图指向一个没有显式*alloc调用的函数,并且没有调用任何可能分配的库函数,比如strdup.
我必须查看生成的程序集才能意识到它是由于包含VLA的内联函数.
我认为VLA必须是堆栈分配的.这个编译器坏了吗?
我从书中读到:«C Primer Plus»告诉我C99标准,可以使用如下的语法:
int b=4;
char a[b];
Run Code Online (Sandbox Code Playgroud)
但是当我把这段代码放到vs2013中时,它告诉我"表达式必须有一个常量值".
这本书错了吗?或者有一些我不知道的关于vs2013的新功能?
int LCS_length(char* x, char* y)
{
int m = strlen(x);
int n = strlen(y);
char b[m + 1][n + 1];
char c[m + 1][n + 1];
}
Run Code Online (Sandbox Code Playgroud)
在这段代码中,我想声明一个新的二维数组,但我的编译器给我写了这个错误:
表达式必须具有常量值
谁知道我能做什么,因为编译器不允许我用 C 语言执行此语句?
注意:它只是代码的一部分,后面有 return 语句。
什么时候用 calloc 实例化可变长度数组比用 C 中的“普通”数组声明更好?
考虑“数组声明”方法:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int n = atoi(argv[1]);
int x[n];
for(int i = 1; i < n; i++){
x[i] = i;
printf("%i", x[i]);
printf("\n");
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
与 calloc 方法相比:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int n = atoi(argv[1]);
int * x = (int*) calloc(n, sizeof(int));
for(int i = 1; i < n; i++){
x[i] = i;
printf("%i", x[i]);
printf("\n");
}
return …Run Code Online (Sandbox Code Playgroud) 我只是想知道为什么
students[x].firstName=(char*)malloc(sizeof(char*));
Run Code Online (Sandbox Code Playgroud)
这个不需要字符串的长度。
完整代码(来自互联网上的某个地方):
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
typedef struct
{
char* firstName;
char* lastName;
int rollNumber;
} STUDENT;
int numStudents=2;
int x;
STUDENT* students = (STUDENT *)malloc(numStudents * sizeof *students);
for (x = 0; x < numStudents; x++)
{
students[x].firstName=(char*)malloc(sizeof(char*));
printf("Enter first name :");
scanf("%s",students[x].firstName);
students[x].lastName=(char*)malloc(sizeof(char*));
printf("Enter last name :");
scanf("%s",students[x].lastName);
printf("Enter roll number :");
scanf("%d",&students[x].rollNumber);
}
for (x = 0; x < numStudents; x++)
printf("First Name: %s, Last Name: %s, Roll number: …Run Code Online (Sandbox Code Playgroud) 通常,当我们事先不知道所需的大小时,我们使用 malloc() ,如下所示(删除检查/错误处理等):
FILE * fp = fopen(path, "rb");
fseek(fp, 0, SEEK_END);
ssize_t length = ftell(fp);
rewind(fp);
char* buffer = malloc(length * sizeof(char));
fread(buffer, 1, *length, fp);
fclose(fp);
free(buffer);
Run Code Online (Sandbox Code Playgroud)
我们需要使用char* buffer = malloc(length * sizeof(char));而不是char buffer[length];因为堆栈的大小非常有限。我的问题是,由于 C 支持可变长度数组,至少对于局部变量来说,是什么阻止我们使堆栈变得更大而只使用堆栈内存呢?
我确实在这里找到了答案。它提出了一个有效的观点:malloc有一个接口可以报告内存的不可用性。但这是唯一char* buffer = malloc(length * sizeof(char));;有效和char buffer[length];无效的原因吗?
让我总结一下评论/答案提出的一些观点:
malloc()返回NULL表示分配失败,而VLA没有这种设计,所以只有系统内存耗尽时程序才会崩溃;realloc()动态调整VLA的大小;(但如上面的例子所示,在很多情况下,我们只是想要一个巨大的本地VLA,其大小在运行时已知,但一旦知道就永远不会改变。但我们仍然必须使用malloc()它)
编辑: 许多人发现问题的意图不清楚,“为什么这么麻烦而不只是使用 …