배열이 정의되지 않았거나 초기 크기가 없음을 선언하려면 어떻게 해야 합니까?
다음을 사용하여 수행할 수 있다는 것을 알고 있습니다.malloc
하지만 아직 사용법을 모릅니다.
예를 들어, 나는 사용자가 스톱을 넣기 위해 Sentinel과 함께 무한 루프를 사용하여 여러 개의 숫자를 입력하기를 원했지만(예: -1), 나는 아직 그/그녀가 몇 개를 입력할지 모르기 때문에 초기 크기가 없는 배열을 선언해야 합니다.하지만 이 인트라[]처럼 작동하지 않는다는 것도 알고 있습니다. 컴파일할 때는 정해진 수의 요소가 있어야 하기 때문입니다.
intar[1000]와 같이 과장된 크기로 선언하면 효과가 있겠지만, 멍청하게 느껴집니다(그리고 1000 정수 바이트를 메모리에 할당하기 때문에 메모리가 낭비됩니다). 이를 수행하는 더 우아한 방법을 알고 싶습니다.
이것은 포인터를 사용하고 힙에 메모리를 할당하는 것입니다.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]);
}
}
바로 그겁니다.다음은 이것이 작동하는 이유에 대한 더 관련된 설명입니다 :)
당신이 C 포인터를 얼마나 잘 알고 있는지 모르겠지만, C의 어레이 액세스(예:array[2]
)는 실제로 포인터를 통해 메모리에 액세스하기 위한 단축형입니다.가 가리키는 메모리에 액세스하려면data
니가 쓰는*data
이를 포인터 참조 해제라고 합니다.부터data
유형의int *
,그리고나서*data
유형의int
다음은 중요한 정보입니다.(data + 2)
의미는 "2 int의 바이트 크기를 다음이 가리키는 주소에 추가합니다.data
".
C의 배열은 인접 메모리에 있는 일련의 값일 뿐입니다. array[1]
바로 옆에 있습니다array[0]
따라서 큰 메모리 블록을 할당하고 어레이로 사용하려면 내부의 모든 요소에 직접 주소를 지정할 수 있는 쉬운 방법이 필요합니다.다행히도 C는 포인터에서도 배열 표기법을 사용할 수 있게 해줍니다. data[0]
와 같은 의미입니다.*(data+0)
즉, "가 가리키는 기억에 접근합니다.data
".data[2]
수단*(data+2)
그리고 세 번째에 접속합니다.int
메모리 블록에 있습니다.
이러한 작업 방식은 다음과 같습니다.
- 일부 초기(약간 작은) 크기의 배열을 할당합니다.
- 얼마나 많은 요소를 읽었는지 기록하면서 이 배열을 읽습니다.
- 어레이가 가득 차면 재할당하여 크기를 두 배로 늘리고 콘텐츠를 보존(즉, 복사)합니다.
- 끝날 때까지 반복합니다.
저는 이 패턴이 꽤 자주 나타나는 것을 발견했습니다.
이 방법의 흥미로운 점은 이 방법을 사용하면 다음을 삽입할 수 있다는 것입니다.N
된 요소를하빈배분열상할다로 빈 배열로 .O(N)
사이에 이 흐르다N
미리
C99라고도 하는 현대 C에는 가변 길이 배열인 VLA가 있습니다.안타깝게도 모든 컴파일러가 이를 지원하는 것은 아니지만, 만약 당신의 컴파일러가 이를 지원한다면 대안이 될 것입니다.
링크된 목록과 같은 동적 데이터 구조 구현 시도
여기 다음과 같은 샘플 프로그램이 있습니다.stdin
필요에 따라 증가하는 메모리 버퍼로.이것은 매우 간단해서 여러분이 이런 종류의 일을 어떻게 처리할 수 있는지에 대한 통찰력을 제공할 것입니다.실제 프로그램에서 다르게 수행되는 한 가지 방법은 각 할당에서 어레이가 어떻게 증가해야 하는지입니다. 디버거에서 작업을 수행하려는 경우 더 단순하게 유지하기 위해 여기에 작은 크기로 유지했습니다.실제 프로그램은 아마도 훨씬 더 큰 할당 증분을 사용할 것입니다(보통 할당 크기가 두 배로 증가하지만, 그렇게 하려면 적절한 크기로 증가를 '상한'해야 합니다. 수백 메가바이트에 도달할 때 할당을 두 배로 늘리는 것은 말이 안 될 수도 있습니다.).
또한 여기서는 버퍼에 대한 인덱스 액세스를 예로 들었지만 실제 프로그램에서는 그렇지 않을 것입니다.
#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);
}
이 예제와 다른 답변의 예제를 결합하면 낮은 수준에서 이러한 종류의 작업이 어떻게 처리되는지에 대한 아이디어를 얻을 수 있습니다.
제가 상상할 수 있는 한 가지 방법은 사용자가 루프 종료를 나타내는 것을 입력하기 전에 모든 숫자를 입력해야 하는 경우 링크된 목록을 사용하여 그러한 시나리오를 구현하는 것입니다.(첫 번째 옵션으로 사용자 입력에 대해 이 작업을 수행한 적이 없기 때문에 흥미로워 보였습니다.낭비적이지만 예술적)
또 다른 방법은 버퍼링된 입력을 하는 것입니다.루프가 계속되면 버퍼를 할당하고, 버퍼를 채우고, 다시 할당합니다(우아하지는 않지만 주어진 사용 사례에 가장 합리적임).
하지만 저는 묘사된 것이 우아하다고 생각하지 않습니다.아마도, 저는 (가장 합리적인) 사용 사례를 변경할 것입니다.
언급URL : https://stackoverflow.com/questions/4352768/how-do-i-declare-an-array-of-undefined-or-no-initial-size
'programing' 카테고리의 다른 글
SQL - 열의 고유한 조합을 카운트하는 방법 (0) | 2023.07.08 |
---|---|
Oracle Client란 무엇입니까? (0) | 2023.07.03 |
UI 팬 제스처 인식기 - 수직 또는 수평만 (0) | 2023.07.03 |
Quartz 사용법메일을 트리거하는 작업을 예약하기 위해 ASP.NET을 사용하는 net? (0) | 2023.07.03 |
MongoClient.connect()를 사용할 때 sslprep 주의 (0) | 2023.07.03 |