كيفية تهيئة جميع أعضاء مجموعة إلى نفس القيمة ؟
-
03-07-2019 - |
سؤال
لدي مجموعة كبيرة في ج (وليس C++ إذا كان هذا يحدث فرقا).أريد أن تهيئة جميع الأعضاء على نفس القيمة.أقسم كنت أعرف طريقة بسيطة للقيام بذلك.يمكنني استخدام memset()
في حالتي, ولكن ليس هناك طريقة للقيام بذلك هو أن يبنى الحق في C syntax ؟
المحلول
وإذا لم هذه القيمة هي 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. هذا هو href="https://stackoverflow.com/a/17589839"> باستخدام C:
int myArray[10] = {}; // all elements 0 in C++
وتذكر أن الكائنات مع مدة التخزين الثابتة وتهيئة إلى 0 إذا لم يتم تحديد مهيئ:
static int myArray[10]; // all elements 0
وأن "0" لا يعني بالضرورة "كل بت من الصفر"، وذلك باستخدام ما سبق هو أفضل وأكثر المحمولة من memset (). (العائمة القيم نقطة سيكون تهيئة إلى +0، مؤشرات إلى قيمة فارغة، الخ.)
نصائح أخرى
إذا المترجم الخاص بك هو GCC يمكنك استخدام بناء الجملة التالي:
int array[1024] = {[0 ... 1023] = 5};
وراجع صفا مفصلا: http://gcc.gnu.org/onlinedocs/gcc -4.1.2 / دول مجلس التعاون الخليجي / مخصصة لل-Inits.html
لتهيئة ثابت مجموعة كبيرة بنفس القيمة، دون متعددة النسخ واللصق، يمكنك استخدام وحدات الماكرو:
#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) };
وأسماء ماكرو قابلة للتفاوض.
إذا كنت تريد التأكد من أن كل عضو من أعضاء مجموعة يتم تهيئة صراحة، فقط تجاهل البعد عن إعلان:
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} };
وليس
ورأيت بعض التعليمات البرمجية التي تستخدم بناء الجملة التالي:
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)
};
وهذا يبقي الامور في النظام، حتى لو كنت يحدث لكتابة بعض من تعداد القيم من النظام.
والمزيد من المعلومات حول هذه التقنية يمكن العثور على هنا و هنا .
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...
وطارئ حجم التغييرات صفيف.
ويمكنك أن تفعل الشيء كله ثابت شيء مهيئ كما هو موضح أعلاه، ولكنه يمكن أن يكون المشكله الحقيقية عندما التغييرات حجم مجموعة (عندما embiggens مجموعة الخاص بك، إذا كنت لا إضافة المهيآت إضافية مناسبة تحصل القمامة).
و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
ونموذج التعليمات البرمجية أعلاه هو في نظام جزءا لا يتجزأ من ولن ترى النور من مترجم آخر.
لتهيئة أنواع البيانات "العادية" (مثل المصفوفات الباحث)، يمكنك استخدام رمز براكيت، لكنه لن الصفر القيم بعد آخر إذا كان لا يزال هناك مساحة في مجموعة:
// put values 1-8, then two zeroes
int list[10] = {1,2,3,4,5,6,7,8};
وA قليلا اللسان في خده الجواب. كتابة بيان
array = initial_value
وفي المفضلة لديك لغة مجموعة قادرة (الألغام هو فورتران، ولكن هناك العديد من الآخرين)، وربطه إلى رمز C الخاص بك. ربما كنت ترغب في الانتهاء من ذلك أن تكون وظيفة الخارجية.
إذا يحدث المصفوفة أن يكون صحيح أو أي شيء مع حجم كثافة أو حجم الخاصة بك ذاكرة نمط ليناسب الأوقات الدقيقة إلى عدد صحيح (أي جميع أصفار أو 0xA5A5A5A5)، فإن أفضل طريقة هي استخدام <لأ href = "HTTP: //www.cplusplus.com/reference/clibrary/cstring/memset.html "يختلط =" noreferrer "> memset () .
والدعوة وإلا memcpy () في حلقة تحريك المؤشر.
هناك طريقة سريعة إلى تهيئة مجموعة من أي نوع مع إعطاء قيمة.أنه يعمل بشكل جيد جدا مع صفائف كبيرة.الخوارزمية هي كما يلي:
- تهيئة العنصر الأول من الصفيف (الطريقة المعتادة)
- نسخ الجزء الذي تم تعيين إلى الجزء الذي لم يتم تعيين مضاعفة حجم مع كل عملية نسخ
بالنسبة 1 000 000
عناصر int
مجموعة 4 مرات أسرع من العادي حلقة التهيئة (i5, 2 النوى 2.3 غيغاهرتز ، 4GiB الذاكرة 64 بت):
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;
}
لقد ذكر أحد على ترتيب فهرس للوصول إلى عناصر مجموعة تهيئته. سوف بلدي على سبيل المثال كود تعطي مثالا توضيحيا لذلك.
#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
وقطع من خلال جميع الثرثرة، والجواب القصير هو أنه إذا قمت بتشغيل الأمثل في وقت الترجمة فلن نفعل ما هو أفضل من هذا:
int i,value=5,array[1000];
for(i=0;i<1000;i++) array[i]=value;
وأضاف المكافأة: هو رمز مقروءا في الواقع:)
- إذا كان الصفيف الخاص بك هو أعلن ثابتة أو عالمية ، كل العناصر في مجموعة بالفعل الافتراضي القيمة الافتراضية 0.
- بعض المجمعين مجموعة مجموعة الافتراضي إلى 0 في وضع التصحيح.
- فمن السهل أن تعيين الافتراضي إلى 0 :الباحث مجموعة[10] = {0};
- ومع ذلك ، من أجل قيم أخرى ، يجب استخدام memset() أو حلقة ؛
على سبيل المثال:الباحث مجموعة[10];memset(مجموعة -1, 10 *sizeof(int));
#include<stdio.h>
int main(){
int i,a[50];
for (i=0;i<50;i++){
a[i]=5;// set value 5 to all the array index
}
for (i=0;i<50;i++)
printf("%d\n",a[i]);
return 0;
}
وسوف يعطي س / ص 5 5 5 5 5 5 ...... حتى حجم مجموعة كاملة
وأنا أعلم أن 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()
لدعم تلك الأنواع.
ويمكنك أن تجرب هذا الرمز مع المطيع على الانترنت وجدت هنا .
لتأخر التهيئة (أي الطبقة عضوا منشئ التهيئة) النظر فيما يلي:
int a[4];
unsigned int size = sizeof(a) / sizeof(a[0]);
for (unsigned int i = 0; i < size; i++)
a[i] = 0;
مرة في اليوم (و أنا لا أقول أنها فكرة جيدة) ، كنا مجموعة العنصر الأول ثم:
memcpy (&element [1], &element [0], sizeof (element)-sizeof (element [0]);
ولا حتى التأكد من انها تعمل أي أكثر (هذا يعتمد على تنفيذ memcpy) لكنه يعمل من قبل مرارا وتكرارا نسخ العنصر الأولي التالي - حتى يعمل صفائف من الهياكل.
وأنا لا أرى أي الشروط الواردة في السؤال، لذلك يجب أن يكون حل عام: تهيئة مجموعة ربما متعددة الأبعاد غير محددة بنيت من عناصر بنية غير محددة وربما مع قيمة عضوا الأولية:
#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
وأنا أعلم أن السؤال الأصلي يذكر صراحة C ++ C ولا، ولكن إذا (مثلي) جاء الى هنا بحثا عن حل للصفائف C ++، وهنا خدعة متقنة:
إذا يدعم المترجم الخاص بك أضعاف تعبيرات ، يمكنك استخدام قالب السحر و 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
ويمكنك إلقاء نظرة على في العمل (وفي Wandbox)