C에 큰 배열이 있습니다 ( 차이가있는 경우 C ++ 이 아님 ). 동일한 값의 모든 멤버를 초기화하고 싶습니다.
나는 이것을 한 번 간단한 방법으로 알고 있다고 맹세 할 수 있었다. memset()
내 경우에는 사용할 수 있지만 C 구문에 내장 된이 작업을 수행 할 수있는 방법이 없습니까?
memset()
특정 토론 : stackoverflow.com/questions/7202411/... 나는 단지 0 작동 생각
C에 큰 배열이 있습니다 ( 차이가있는 경우 C ++ 이 아님 ). 동일한 값의 모든 멤버를 초기화하고 싶습니다.
나는 이것을 한 번 간단한 방법으로 알고 있다고 맹세 할 수 있었다. memset()
내 경우에는 사용할 수 있지만 C 구문에 내장 된이 작업을 수행 할 수있는 방법이 없습니까?
memset()
특정 토론 : stackoverflow.com/questions/7202411/... 나는 단지 0 작동 생각
답변:
해당 값이 0이 아닌 경우 (이 경우 이니셜 라이저의 일부를 생략하고 해당 요소가 0으로 초기화 됨) 쉬운 방법은 없습니다.
그러나 확실한 해결책을 간과하지 마십시오.
int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };
결 측값이있는 요소는 0으로 초기화됩니다.
int myArray[10] = { 1, 2 }; // initialize to 1,2,0,0,0...
따라서 모든 요소를 0으로 초기화합니다.
int myArray[10] = { 0 }; // all elements 0
C ++에서 빈 초기화 목록은 모든 요소를 0으로 초기화합니다 . C 에서는 사용할 수 없습니다 .
int myArray[10] = {}; // all elements 0 in C++
이니셜 라이저가 지정되지 않은 경우 정적 저장 기간을 가진 객체는 0으로 초기화됩니다.
static int myArray[10]; // all elements 0
그리고 "0"이 반드시 "all-bits-zero"를 의미하는 것은 아니므로, 위를 사용하는 것이 memset ()보다 더 우수하고 이식성이 뛰어납니다. (부동 소수점 값은 +0으로 초기화되고 널값에 대한 포인터 등)
컴파일러가 GCC 인 경우 다음 구문을 사용할 수 있습니다.
int array[1024] = {[0 ... 1023] = 5};
자세한 설명을 확인하십시오 : http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html
int
정적 데이터 에 65536 s 를 추가해야합니다. 256K는 정확히 관찰 된 크기 증가입니다.
int
처럼의, int foo1 = 1, foo2 = 1, ..., foo65536 =1;
같은 크기의 증가를 얻을 것이다.
bool array[][COLS] = { [0...ROWS-1][0...COLS-1] = true}
의 경우 전체 형식보다 읽기 쉬운 지 확실하지 않습니다.
여러 복사 붙여 넣기없이 동일한 값으로 큰 배열을 정적으로 초기화하려면 매크로를 사용할 수 있습니다.
#define VAL_1X 42
#define VAL_2X VAL_1X, VAL_1X
#define VAL_4X VAL_2X, VAL_2X
#define VAL_8X VAL_4X, VAL_4X
#define VAL_16X VAL_8X, VAL_8X
#define VAL_32X VAL_16X, VAL_16X
#define VAL_64X VAL_32X, VAL_32X
int myArray[53] = { VAL_32X, VAL_16X, VAL_4X, VAL_1X };
값을 변경해야하는 경우 한 곳에서만 교체해야합니다.
다음과 같이 쉽게 일반화 할 수 있습니다.
#define VAL_1(X) X
#define VAL_2(X) VAL_1(X), VAL_1(X)
/* etc. */
다음을 사용하여 변형을 만들 수 있습니다.
#define STRUCTVAL_1(...) { __VA_ARGS__ }
#define STRUCTVAL_2(...) STRUCTVAL_1(__VA_ARGS__), STRUCTVAL_1(__VA_ARGS__)
/*etc */
구조 또는 복합 배열과 함께 작동합니다.
#define STRUCTVAL_48(...) STRUCTVAL_32(__VA_ARGS__), STRUCTVAL_16(__VA_ARGS__)
struct Pair { char key[16]; char val[32]; };
struct Pair p_data[] = { STRUCTVAL_48("Key", "Value") };
int a_data[][4] = { STRUCTVAL_48(12, 19, 23, 37) };
매크로 이름은 협상 가능합니다.
VAL_1X
단일 정수가 아닌 목록 인 경우에도이 방법을 사용할 수 있습니다 . 마이그레이션 가능한 상태와 마찬가지로, 이는 EEPROM 또는 플래시 메모리의 초기화 값을 정의하려는 임베디드 시스템에도 적용 할 수있는 방법입니다. 두 경우 모두를 사용할 수 없습니다 memset()
.
배열의 모든 멤버가 명시 적으로 초기화되도록하려면 선언에서 차원을 생략하십시오.
int myArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
컴파일러는 이니셜 라이저 목록에서 차원을 추론합니다. 불행히도 다차원 배열의 경우 가장 바깥 쪽 차원 만 생략 할 수 있습니다.
int myPoints[][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
괜찮지 만
int myPoints[][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
아니다.
int myPoints[10][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
이 구문을 사용하는 코드를 보았습니다.
char* array[] =
{
[0] = "Hello",
[1] = "World"
};
특히 유용한 것은 열거 형을 인덱스로 사용하는 배열을 만드는 경우입니다.
enum
{
ERR_OK,
ERR_FAIL,
ERR_MEMORY
};
#define _ITEM(x) [x] = #x
char* array[] =
{
_ITEM(ERR_OK),
_ITEM(ERR_FAIL),
_ITEM(ERR_MEMORY)
};
열거 형 값 중 일부를 순서대로 작성하지 않아도 상황이 순서대로 유지됩니다.
이 기술에 대한 자세한 내용은 여기 및 여기를 참조하십시오 .
char const *array[] = { ... };
심지어 char const * const array[] = { ... };
할 수도 없습니까?
int i;
for (i = 0; i < ARRAY_SIZE; ++i)
{
myArray[i] = VALUE;
}
나는 이것이 더 낫다고 생각한다
int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5...
배열의 크기가 변경되는 경우
memset(myArray, VALUE, ARRAY_SIZE);
위에서 설명한 것처럼 전체 정적 이니셜 라이저를 수행 할 수는 있지만 배열 크기가 변경되면 배열이 커질 때 적절한 초기화 프로그램을 추가하지 않으면 쓰레기가 생길 수 있습니다.
memset은 작업 수행에 대한 런타임 적중을 제공하지만 코드 크기 적중은 배열 크기 변경에 영향을받지 않습니다. 배열이 수십 개의 요소보다 클 때 거의 모든 경우 에이 솔루션을 사용합니다.
배열을 정적으로 선언하는 것이 정말로 중요하다면 프로그램을 작성하여 빌드 프로세스의 일부로 만드는 프로그램을 작성했습니다.
memset
배열을 초기화 하는 데 사용하는 예를 추가해 주 시겠습니까?
다른 방법은 다음과 같습니다.
static void
unhandled_interrupt(struct trap_frame *frame, int irq, void *arg)
{
//this code intentionally left blank
}
static struct irqtbl_s vector_tbl[XCHAL_NUM_INTERRUPTS] = {
[0 ... XCHAL_NUM_INTERRUPTS-1] {unhandled_interrupt, NULL},
};
보다:
지정된 inits
그런 다음 질문하십시오. C 확장은 언제 사용할 수 있습니까?
위의 코드 샘플은 임베디드 시스템에 있으며 다른 컴파일러의 빛을 절대 보지 못합니다.
int 배열과 같은 '정상적인'데이터 유형을 초기화하는 경우 대괄호 표기법을 사용할 수 있지만 배열에 공간이 남아 있으면 마지막에 값이 0이됩니다.
// put values 1-8, then two zeroes
int list[10] = {1,2,3,4,5,6,7,8};
주어진 값으로 모든 유형의 배열을 초기화하는 빠른 방법이 있습니다. 큰 배열에서 잘 작동합니다. 알고리즘은 다음과 같습니다.
들면 1 000 000
소자 int
어레이는 일정한 루프 초기화 (I5, 2 개 코어, 2.3 GHz의 4GiB 메모리, 64 비트)보다 4 배 빠른 것이다 :
loop runtime 0.004248 [seconds]
memfill() runtime 0.001085 [seconds]
#include <stdio.h>
#include <time.h>
#include <string.h>
#define ARR_SIZE 1000000
void memfill(void *dest, size_t destsize, size_t elemsize) {
char *nextdest = (char *) dest + elemsize;
size_t movesize, donesize = elemsize;
destsize -= elemsize;
while (destsize) {
movesize = (donesize < destsize) ? donesize : destsize;
memcpy(nextdest, dest, movesize);
nextdest += movesize; destsize -= movesize; donesize += movesize;
}
}
int main() {
clock_t timeStart;
double runTime;
int i, a[ARR_SIZE];
timeStart = clock();
for (i = 0; i < ARR_SIZE; i++)
a[i] = 9;
runTime = (double)(clock() - timeStart) / (double)CLOCKS_PER_SEC;
printf("loop runtime %f [seconds]\n",runTime);
timeStart = clock();
a[0] = 10;
memfill(a, sizeof(a), sizeof(a[0]));
runTime = (double)(clock() - timeStart) / (double)CLOCKS_PER_SEC;
printf("memfill() runtime %f [seconds]\n",runTime);
return 0;
}
memfill()
코드는 약 1200 µs입니다. 그러나 이후 반복에서 루프는 약 900-1000 µs memfill()
가 걸리고 코드는 1000-1300 µs가 걸립니다. 첫 번째 반복은 캐시를 채우는 시간에 영향을받을 수 있습니다. 테스트를 취소하고 memfill()
처음으로 느립니다.
초기화 된 배열의 요소에 액세스하는 인덱스 순서를 언급 한 사람은 없습니다. 내 예제 코드는 이에 대한 예제를 제공합니다.
#include <iostream>
void PrintArray(int a[3][3])
{
std::cout << "a11 = " << a[0][0] << "\t\t" << "a12 = " << a[0][1] << "\t\t" << "a13 = " << a[0][2] << std::endl;
std::cout << "a21 = " << a[1][0] << "\t\t" << "a22 = " << a[1][1] << "\t\t" << "a23 = " << a[1][2] << std::endl;
std::cout << "a31 = " << a[2][0] << "\t\t" << "a32 = " << a[2][1] << "\t\t" << "a33 = " << a[2][2] << std::endl;
std::cout << std::endl;
}
int wmain(int argc, wchar_t * argv[])
{
int a1[3][3] = { 11, 12, 13, // The most
21, 22, 23, // basic
31, 32, 33 }; // format.
int a2[][3] = { 11, 12, 13, // The first (outer) dimension
21, 22, 23, // may be omitted. The compiler
31, 32, 33 }; // will automatically deduce it.
int a3[3][3] = { {11, 12, 13}, // The elements of each
{21, 22, 23}, // second (inner) dimension
{31, 32, 33} }; // can be grouped together.
int a4[][3] = { {11, 12, 13}, // Again, the first dimension
{21, 22, 23}, // can be omitted when the
{31, 32, 33} }; // inner elements are grouped.
PrintArray(a1);
PrintArray(a2);
PrintArray(a3);
PrintArray(a4);
// This part shows in which order the elements are stored in the memory.
int * b = (int *) a1; // The output is the same for the all four arrays.
for (int i=0; i<9; i++)
{
std::cout << b[i] << '\t';
}
return 0;
}
출력은 다음과 같습니다.
a11 = 11 a12 = 12 a13 = 13
a21 = 21 a22 = 22 a23 = 23
a31 = 31 a32 = 32 a33 = 33
a11 = 11 a12 = 12 a13 = 13
a21 = 21 a22 = 22 a23 = 23
a31 = 31 a32 = 32 a33 = 33
a11 = 11 a12 = 12 a13 = 13
a21 = 21 a22 = 22 a23 = 23
a31 = 31 a32 = 32 a33 = 33
a11 = 11 a12 = 12 a13 = 13
a21 = 21 a22 = 22 a23 = 23
a31 = 31 a32 = 32 a33 = 33
11 12 13 21 22 23 31 32 33
<iostream>
유효하지 않은 C
등 std::cout
, std::cin
등은의 일부 std::namespace
및 C
지원하지 않습니다 namespaces
. 사용해보십시오 <stdio.h>
위해 printf(...)
대신.
모든 채터를 살펴보면 짧은 대답은 컴파일 타임에 최적화를 켜면 다음보다 나을 것입니다.
int i,value=5,array[1000];
for(i=0;i<1000;i++) array[i]=value;
추가 보너스 : 코드는 실제로 읽을 수 있습니다 :)
사용자 Tarski
가이 질문에 비슷한 방식으로 답변 한다는 것을 알고 있지만 몇 가지 세부 정보를 추가했습니다. C ++을 사용하고 싶어하는 경향이 있기 때문에 약간의 녹슬 었으므로 C의 일부를 용서하십시오. 그러나 여기에갑니다.
미리 어레이의 크기를 알고 있다면 ...
#include <stdio.h>
typedef const unsigned int cUINT;
typedef unsigned int UINT;
cUINT size = 10;
cUINT initVal = 5;
void arrayInitializer( UINT* myArray, cUINT size, cUINT initVal );
void printArray( UINT* myArray );
int main() {
UINT myArray[size];
/* Not initialized during declaration but can be
initialized using a function for the appropriate TYPE*/
arrayInitializer( myArray, size, initVal );
printArray( myArray );
return 0;
}
void arrayInitializer( UINT* myArray, cUINT size, cUINT initVal ) {
for ( UINT n = 0; n < size; n++ ) {
myArray[n] = initVal;
}
}
void printArray( UINT* myArray ) {
printf( "myArray = { " );
for ( UINT n = 0; n < size; n++ ) {
printf( "%u", myArray[n] );
if ( n < size-1 )
printf( ", " );
}
printf( " }\n" );
}
위의 몇 가지주의 사항이 있습니다. 하나는 UINT myArray[size];
선언시 직접 초기화되지 않지만 다음 코드 블록 또는 함수 호출은 배열의 각 요소를 원하는 동일한 값으로 초기화합니다. 다른 경고는 지원할 initializing function
각각에 대해 를 작성 type
해야하며 printArray()
해당 유형을 지원 하도록 함수를 수정해야한다는 것 입니다.
나는 원래 질문에 C ++이 아닌 C를 명시 적으로 언급하지만 당신이 (나 같은) C ++ 배열에 대한 솔루션을 찾고 있다면 여기에 깔끔한 트릭이 있습니다.
컴파일러에서 fold expressions를 지원하는 경우 template magic을 사용 std::index_sequence
하고 원하는 값으로 초기화 목록을 생성 할 수 있습니다 . 그리고 당신은 심지어 constexpr
상사처럼 느낄 수 있습니다 :
#include <array>
/// [3]
/// This functions's only purpose is to ignore the index given as the second
/// template argument and to always produce the value passed in.
template<class T, size_t /*ignored*/>
constexpr T identity_func(const T& value) {
return value;
}
/// [2]
/// At this point, we have a list of indices that we can unfold
/// into an initializer list using the `identity_func` above.
template<class T, size_t... Indices>
constexpr std::array<T, sizeof...(Indices)>
make_array_of_impl(const T& value, std::index_sequence<Indices...>) {
return {identity_func<T, Indices>(value)...};
}
/// [1]
/// This is the user-facing function.
/// The template arguments are swapped compared to the order used
/// for std::array, this way we can let the compiler infer the type
/// from the given value but still define it explicitly if we want to.
template<size_t Size, class T>
constexpr std::array<T, Size>
make_array_of(const T& value) {
using Indices = std::make_index_sequence<Size>;
return make_array_of_impl(value, Indices{});
}
// std::array<int, 4>{42, 42, 42, 42}
constexpr auto test_array = make_array_of<4/*, int*/>(42);
static_assert(test_array[0] == 42);
static_assert(test_array[1] == 42);
static_assert(test_array[2] == 42);
static_assert(test_array[3] == 42);
// static_assert(test_array[4] == 42); out of bounds
질문에 요구 사항이 없으므로 솔루션은 일반적이어야합니다. 초기 멤버 값을 사용하여 지정되지 않은 가능한 구조 요소로 작성된 지정되지 않은 다차원 배열의 초기화 :
#include <string.h>
void array_init( void *start, size_t element_size, size_t elements, void *initval ){
memcpy( start, initval, element_size );
memcpy( (char*)start+element_size, start, element_size*(elements-1) );
}
// testing
#include <stdio.h>
struct s {
int a;
char b;
} array[2][3], init;
int main(){
init = (struct s){.a = 3, .b = 'x'};
array_init( array, sizeof(array[0][0]), 2*3, &init );
for( int i=0; i<2; i++ )
for( int j=0; j<3; j++ )
printf("array[%i][%i].a = %i .b = '%c'\n",i,j,array[i][j].a,array[i][j].b);
}
결과:
array[0][0].a = 3 .b = 'x'
array[0][1].a = 3 .b = 'x'
array[0][2].a = 3 .b = 'x'
array[1][0].a = 3 .b = 'x'
array[1][1].a = 3 .b = 'x'
array[1][2].a = 3 .b = 'x'
편집 :로 start+element_size
변경(char*)start+element_size
sizeof(void)
심지어 유효한지 확실하지 않습니다.
memcpy()
가 대상 공간과 겹치 므로 정의되지 않은 동작이 호출 됩니다. 순진한 구현으로 memcpy()
작동 할 수도 있지만 시스템이 작동하도록 요구할 필요는 없습니다.
그날로 돌아가서 (좋은 생각은 아닙니다) 첫 번째 요소를 설정 한 다음 :
memcpy (&element [1], &element [0], sizeof (element)-sizeof (element [0]);
그것이 더 이상 작동하지는 않지만 (memcpy의 구현에 달려 있음) 초기 요소를 다음에 반복적으로 복사하여 작동합니다-심지어 배열 배열에서도 작동합니다.
memcpy
겹치는 경우에는 상향식 또는 하향식 복사 순서 와 같지만 지정된 기능을 제공해야 하지만 그렇지 않습니다.
memmove()
작동하지 않습니다.
병렬로 의미한다면, 표현식과 함께 사용될 때 쉼표 연산자가 그렇게 할 수 있다고 생각합니다.
a[1]=1, a[2]=2, ..., a[indexSize];
또는 단일 구문을 의미하는 경우 for 루프에서 수행 할 수 있습니다.
for(int index = 0, value = 10; index < sizeof(array)/sizeof(array[0]); index++, value--)
array[index] = index;
// 인수 목록의 쉼표 연산자는 위에서 설명한 병렬 연산자가 아닙니다.
배열 편차를 초기화 할 수 있습니다.
array[] = {1, 2, 3, 4, 5};
malloc / calloc / sbrk / alloca / etc를 호출하여 객체에 고정 된 저장 영역을 할당 할 수 있습니다.
int *array = malloc(sizeof(int)*numberOfListElements/Indexes);
다음을 통해 멤버에 액세스하십시오.
*(array + index)
기타.
enum { HYDROGEN = 1, HELIUM = 2, CARBON = 6, NEON = 10, … };
과 같습니다struct element { char name[15]; char symbol[3]; } elements[] = { [NEON] = { "Neon", "Ne" }, [HELIUM] = { "Helium", "He" }, [HYDROGEN] = { "Hydrogen", "H" }, [CARBON] = { "Carbon", "C" }, … };
. 생략 부호를 제거하면…
해당 단편은 C99 또는 C11에서 컴파일됩니다.