I know it could be done using malloc, but I do not know how to use it yet.
我知道可以用malloc完成,但是我还不知道如何使用它。
For example, I wanted the user to input several numbers using an infinite loop with a sentinel to put a stop into it (i.e. -1), but since I do not know yet how many he/she will input, I have to declare an array with no initial size, but I'm also aware that it won't work like this int arr[]; at compile time since it has to have a definite number of elements.
例如,我希望用户输入几个数字使用无限循环和一个哨兵停止(即1),但由于我还不知道有多少他/她将输入,我必须声明一个数组没有初始大小,但我也知道它不会这样的int[]的arr工作;在编译时,因为它必须有一定数量的元素。
Declaring it with an exaggerated size like int arr[1000]; would work but it feels dumb (and waste memory since it would allocate that 1000 integer bytes into the memory) and I would like to know a more elegant way to do this.
用像int arr[1000]这样夸张的尺寸来声明它;可以工作,但它感觉很笨(并且浪费内存,因为它将把1000个整数字节分配到内存中),我想知道一种更优雅的方法。
7 个解决方案
#1
27
This can be done by using a pointer, and allocating memory on the heap using malloc
. Note that there is no way to later ask how big that memory block is. You have to keep track of the array size yourself.
这可以通过使用指针和使用malloc在堆上分配内存来实现。注意,以后没有办法问这个内存块有多大。你必须自己跟踪数组的大小。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv)
{
/* declare a pointer do an integer */
int *data;
/* we also have to keep track of how big our array is - I use 50 as an example*/
const int datacount = 50;
data = malloc(sizeof(int) * datacount); /* allocate memory for 50 int's */
if (!data) { /* If data == 0 after the call to malloc, allocation failed for some reason */
perror("Error allocating memory");
abort();
}
/* at this point, we know that data points to a valid block of memory.
Remember, however, that this memory is not initialized in any way -- it contains garbage.
Let's start by clearing it. */
memset(data, 0, sizeof(int)*datacount);
/* now our array contains all zeroes. */
data[0] = 1;
data[2] = 15;
data[49] = 66; /* the last element in our array, since we start counting from 0 */
/* Loop through the array, printing out the values (mostly zeroes, but even so) */
for(int i = 0; i < datacount; ++i) {
printf("Element %d: %d\n", i, data[i]);
}
}
That's it. What follows is a more involved explanation of why this works :)
就是这样。以下是一个更复杂的解释,解释了为什么这行得通:
I don't know how well you know C pointers, but array access in C (like array[2]
) is actually a shorthand for accessing memory via a pointer. To access the memory pointed to by data
, you write *data
. This is known as dereferencing the pointer. Since data
is of type int *
, then *data
is of type int
. Now to an important piece of information: (data + 2)
means "add the byte size of 2 ints to the adress pointed to by data
".
我不知道您对C指针了解多少,但是C中的数组访问(如数组[2])实际上是通过指针访问内存的一种简写。要访问数据指向的内存,需要编写*data。这被称为禁用指针。由于数据类型为int *,则*data类型为int.现在有一个重要的信息:(data + 2)表示“将2 ints的字节大小添加到数据指向的地址中”。
An array in C is just a sequence of values in adjacent memory. array[1]
is just next to array[0]
. So when we allocate a big block of memory and want to use it as an array, we need an easy way of getting the direct adress to every element inside. Luckily, C lets us use the array notation on pointers as well. data[0]
means the same thing as *(data+0)
, namely "access the memory pointed to by data
". data[2]
means *(data+2)
, and accesses the third int
in the memory block.
C中的数组只是相邻内存中的值序列。数组[1]就在数组[0]的旁边。因此,当我们分配一个大的内存块并想把它用作数组时,我们需要一种简单的方法来获得内部每个元素的直接地址。幸运的是,C还允许我们在指针上使用数组表示法。数据[0]表示与*(数据+0)相同的东西,即“访问由数据指向的内存”。数据[2]表示*(data+2),访问内存块中的第三个int。
#2
11
The way it's often done is as follows:
通常的做法是:
- allocate an array of some initial (fairly small) size;
- 分配一个初始(相当小)大小的数组;
- read into this array, keeping track of how many elements you've read;
- 读取到这个数组中,跟踪已读取的元素数量;
- once the array is full, reallocate it, doubling the size and preserving (i.e. copying) the contents;
- 一旦数组满了,重新分配它,将大小加倍并保存(即复制)内容;
- repeat until done.
- 重复,直到完成。
I find that this pattern comes up pretty frequently.
我发现这种模式经常出现。
What's interesting about this method is that it allows one to insert N
elements into an empty array one-by-one in amortized O(N)
time without knowing N
in advance.
这个方法的有趣之处在于,它允许在平摊O(N)时间内将N个元素逐个插入一个空数组,而不事先知道N。
#3
5
Modern C, aka C99, has variable length arrays, VLA. Unfortunately, not all compilers support this but if yours does this would be an alternative.
现代的C,即C99,有可变长度数组VLA。不幸的是,并不是所有的编译器都支持这一点,但是如果您的编译器支持这一点,那么这将是一种替代方法。
#5
1
malloc()
(and its friends free()
and realloc()
) is the way to do this in C.
malloc()(及其friends free()和realloc()))是在C语言中实现这一点的方法。
#6
1
Here's a sample program that reads stdin
into a memory buffer that grows as needed. It's simple enough that it should give some insight in how you might handle this kind of thing. One thing that's would probably be done differently in a real program is how must the array grows in each allocation - I kept it small here to help keep things simpler if you wanted to step through in a debugger. A real program would probably use a much larger allocation increment (often, the allocation size is doubled, but if you're going to do that you should probably 'cap' the increment at some reasonable size - it might not make sense to double the allocation when you get into the hundreds of megabytes).
这是一个示例程序,它将stdin读入一个内存缓冲区,该缓冲区根据需要增长。它很简单,应该能让你对如何处理这类事情有所了解。在真正的程序中,有一件事情可能会以不同的方式来完成,那就是数组在每次分配中必须如何增长——我在这里将它保持在较小的位置,以便在调试器中进行调试时使事情更简单。一个真正的程序可能会使用一个更大的分配增量(通常,分配规模翻了一番,但是如果你要做,你应该“帽”增加一些合理的大小——它可能没有意义的两倍分配当你进入几百兆字节)。
Also, I used indexed access to the buffer here as an example, but in a real program I probably wouldn't do that.
同样,我在这里使用了对缓冲区的索引访问作为一个例子,但是在真正的程序中,我可能不会这样做。
#include <stdlib.h>
#include <stdio.h>
void fatal_error(void);
int main( int argc, char** argv)
{
int buf_size = 0;
int buf_used = 0;
char* buf = NULL;
char* tmp = NULL;
char c;
int i = 0;
while ((c = getchar()) != EOF) {
if (buf_used == buf_size) {
//need more space in the array
buf_size += 20;
tmp = realloc(buf, buf_size); // get a new larger array
if (!tmp) fatal_error();
buf = tmp;
}
buf[buf_used] = c; // pointer can be indexed like an array
++buf_used;
}
puts("\n\n*** Dump of stdin ***\n");
for (i = 0; i < buf_used; ++i) {
putchar(buf[i]);
}
free(buf);
return 0;
}
void fatal_error(void)
{
fputs("fatal error - out of memory\n", stderr);
exit(1);
}
This example combined with examples in other answers should give you an idea of how this kind of thing is handled at a low level.
这个示例与其他答案中的示例结合在一起,应该可以让您了解如何在较低的级别处理此类事情。
#7
0
One way I can imagine is to use a linked list to implement such a scenario, if you need all the numbers entered before the user enters something which indicates the loop termination. (posting as the first option, because have never done this for user input, it just seemed to be interesting. Wasteful but artistic)
我可以想象的一种方法是使用一个链表来实现这样的场景,如果您需要在用户输入指示循环终止的东西之前输入所有的数字。(作为第一个选项发布,因为从来没有这样做过用户输入,这看起来很有趣。浪费但艺术)
Another way is to do buffered input. Allocate a buffer, fill it, re-allocate, if the loop continues (not elegant, but the most rational for the given use-case).
另一种方法是做缓冲输入。如果循环继续(不是很优雅,但是对于给定的用例来说是最合理的),那么就分配一个缓冲区,填充它,重新分配。
I don't consider the described to be elegant though. Probably, I would change the use-case (the most rational).
我不认为所描述的是优雅的。我可能会改变用例(最合理的)。
#1
27
This can be done by using a pointer, and allocating memory on the heap using malloc
. Note that there is no way to later ask how big that memory block is. You have to keep track of the array size yourself.
这可以通过使用指针和使用malloc在堆上分配内存来实现。注意,以后没有办法问这个内存块有多大。你必须自己跟踪数组的大小。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv)
{
/* declare a pointer do an integer */
int *data;
/* we also have to keep track of how big our array is - I use 50 as an example*/
const int datacount = 50;
data = malloc(sizeof(int) * datacount); /* allocate memory for 50 int's */
if (!data) { /* If data == 0 after the call to malloc, allocation failed for some reason */
perror("Error allocating memory");
abort();
}
/* at this point, we know that data points to a valid block of memory.
Remember, however, that this memory is not initialized in any way -- it contains garbage.
Let's start by clearing it. */
memset(data, 0, sizeof(int)*datacount);
/* now our array contains all zeroes. */
data[0] = 1;
data[2] = 15;
data[49] = 66; /* the last element in our array, since we start counting from 0 */
/* Loop through the array, printing out the values (mostly zeroes, but even so) */
for(int i = 0; i < datacount; ++i) {
printf("Element %d: %d\n", i, data[i]);
}
}
That's it. What follows is a more involved explanation of why this works :)
就是这样。以下是一个更复杂的解释,解释了为什么这行得通:
I don't know how well you know C pointers, but array access in C (like array[2]
) is actually a shorthand for accessing memory via a pointer. To access the memory pointed to by data
, you write *data
. This is known as dereferencing the pointer. Since data
is of type int *
, then *data
is of type int
. Now to an important piece of information: (data + 2)
means "add the byte size of 2 ints to the adress pointed to by data
".
我不知道您对C指针了解多少,但是C中的数组访问(如数组[2])实际上是通过指针访问内存的一种简写。要访问数据指向的内存,需要编写*data。这被称为禁用指针。由于数据类型为int *,则*data类型为int.现在有一个重要的信息:(data + 2)表示“将2 ints的字节大小添加到数据指向的地址中”。
An array in C is just a sequence of values in adjacent memory. array[1]
is just next to array[0]
. So when we allocate a big block of memory and want to use it as an array, we need an easy way of getting the direct adress to every element inside. Luckily, C lets us use the array notation on pointers as well. data[0]
means the same thing as *(data+0)
, namely "access the memory pointed to by data
". data[2]
means *(data+2)
, and accesses the third int
in the memory block.
C中的数组只是相邻内存中的值序列。数组[1]就在数组[0]的旁边。因此,当我们分配一个大的内存块并想把它用作数组时,我们需要一种简单的方法来获得内部每个元素的直接地址。幸运的是,C还允许我们在指针上使用数组表示法。数据[0]表示与*(数据+0)相同的东西,即“访问由数据指向的内存”。数据[2]表示*(data+2),访问内存块中的第三个int。
#2
11
The way it's often done is as follows:
通常的做法是:
- allocate an array of some initial (fairly small) size;
- 分配一个初始(相当小)大小的数组;
- read into this array, keeping track of how many elements you've read;
- 读取到这个数组中,跟踪已读取的元素数量;
- once the array is full, reallocate it, doubling the size and preserving (i.e. copying) the contents;
- 一旦数组满了,重新分配它,将大小加倍并保存(即复制)内容;
- repeat until done.
- 重复,直到完成。
I find that this pattern comes up pretty frequently.
我发现这种模式经常出现。
What's interesting about this method is that it allows one to insert N
elements into an empty array one-by-one in amortized O(N)
time without knowing N
in advance.
这个方法的有趣之处在于,它允许在平摊O(N)时间内将N个元素逐个插入一个空数组,而不事先知道N。
#3
5
Modern C, aka C99, has variable length arrays, VLA. Unfortunately, not all compilers support this but if yours does this would be an alternative.
现代的C,即C99,有可变长度数组VLA。不幸的是,并不是所有的编译器都支持这一点,但是如果您的编译器支持这一点,那么这将是一种替代方法。
#4
#5
1
malloc()
(and its friends free()
and realloc()
) is the way to do this in C.
malloc()(及其friends free()和realloc()))是在C语言中实现这一点的方法。
#6
1
Here's a sample program that reads stdin
into a memory buffer that grows as needed. It's simple enough that it should give some insight in how you might handle this kind of thing. One thing that's would probably be done differently in a real program is how must the array grows in each allocation - I kept it small here to help keep things simpler if you wanted to step through in a debugger. A real program would probably use a much larger allocation increment (often, the allocation size is doubled, but if you're going to do that you should probably 'cap' the increment at some reasonable size - it might not make sense to double the allocation when you get into the hundreds of megabytes).
这是一个示例程序,它将stdin读入一个内存缓冲区,该缓冲区根据需要增长。它很简单,应该能让你对如何处理这类事情有所了解。在真正的程序中,有一件事情可能会以不同的方式来完成,那就是数组在每次分配中必须如何增长——我在这里将它保持在较小的位置,以便在调试器中进行调试时使事情更简单。一个真正的程序可能会使用一个更大的分配增量(通常,分配规模翻了一番,但是如果你要做,你应该“帽”增加一些合理的大小——它可能没有意义的两倍分配当你进入几百兆字节)。
Also, I used indexed access to the buffer here as an example, but in a real program I probably wouldn't do that.
同样,我在这里使用了对缓冲区的索引访问作为一个例子,但是在真正的程序中,我可能不会这样做。
#include <stdlib.h>
#include <stdio.h>
void fatal_error(void);
int main( int argc, char** argv)
{
int buf_size = 0;
int buf_used = 0;
char* buf = NULL;
char* tmp = NULL;
char c;
int i = 0;
while ((c = getchar()) != EOF) {
if (buf_used == buf_size) {
//need more space in the array
buf_size += 20;
tmp = realloc(buf, buf_size); // get a new larger array
if (!tmp) fatal_error();
buf = tmp;
}
buf[buf_used] = c; // pointer can be indexed like an array
++buf_used;
}
puts("\n\n*** Dump of stdin ***\n");
for (i = 0; i < buf_used; ++i) {
putchar(buf[i]);
}
free(buf);
return 0;
}
void fatal_error(void)
{
fputs("fatal error - out of memory\n", stderr);
exit(1);
}
This example combined with examples in other answers should give you an idea of how this kind of thing is handled at a low level.
这个示例与其他答案中的示例结合在一起,应该可以让您了解如何在较低的级别处理此类事情。
#7
0
One way I can imagine is to use a linked list to implement such a scenario, if you need all the numbers entered before the user enters something which indicates the loop termination. (posting as the first option, because have never done this for user input, it just seemed to be interesting. Wasteful but artistic)
我可以想象的一种方法是使用一个链表来实现这样的场景,如果您需要在用户输入指示循环终止的东西之前输入所有的数字。(作为第一个选项发布,因为从来没有这样做过用户输入,这看起来很有趣。浪费但艺术)
Another way is to do buffered input. Allocate a buffer, fill it, re-allocate, if the loop continues (not elegant, but the most rational for the given use-case).
另一种方法是做缓冲输入。如果循环继续(不是很优雅,但是对于给定的用例来说是最合理的),那么就分配一个缓冲区,填充它,重新分配。
I don't consider the described to be elegant though. Probably, I would change the use-case (the most rational).
我不认为所描述的是优雅的。我可能会改变用例(最合理的)。