очищення масиву символів c


104

Думав, встановивши перший елемент на нуль, очистить весь вміст масиву char.

char my_custom_data[40] = "Hello!";
my_custom_data[0] = '\0';

Однак це встановлює лише перший елемент.

або

my_custom_data[0] = 0; 

а не використовувати memset, я вважав, що два наведені вище приклади повинні очистити всі дані.


1
Джареде, чому ти встановив тег c ++? він говорив про "C" і не додав жодних тегів, пов’язаних із C ++.
Йоханнес Шауб - ліб

1
Це однаково добре застосовується до масивів символів у C ++, навіть якщо він не вказав.
Адам Хоуз

4
Я видалив тег C ++, щоб уникнути того, що ми вже бачили з людьми, які пропонують специфічні для C ++ рішення
Alnitak

Відповіді:


113

Це залежить від того, як ви хочете переглянути масив. Якщо ви переглядаєте масив як ряд символів, то єдиний спосіб очистити дані - це торкнутися кожного запису. memsetце, мабуть, найефективніший спосіб досягти цього.

З іншого боку, якщо ви вирішите розглядати це як нульовий завершений рядок C / C ++, встановлення першого байта 0 буде ефективно очищати рядок.


4
Вони є ключовим словом у відповіді "ефективно". Тільки перший елемент починається з 0, а решта все ще мають невизначені значення, але якщо ви обробляєте масив як нульовий завершений рядок, а перший елемент є нульовим, то рядок вважається порожнім.
Арнольд Спенс

Дійсно, це відповідь людей.
Йоханнес Шауб - ліб

@caparcode, точно. Ось чому дуже важливо зрозуміти, як використовується масив.
JaredPar

Так, це я повинен був сказати у своєму першому дописі. Значок - це завершений рядок. тож або вони зроблять цю хитрість. char [0] = '\ 0'; або char [0] = 0. Я не впевнений, але почув, що використовувати "\ 0" краще для використання нульових завершених рядків.
ant2009

@robUK, так, ти прав. Технічно "\ 0" дорівнює 0 (в ассії), але вам слід використовувати "\ 0", оскільки це робить ваш намір зрозумілим
Марк Теста

70

Масив на C - це просто місце в пам'яті, тому дійсно ваше my_custom_data[0] = '\0';призначення просто встановлює перший елемент нульовим і залишає інші елементи неушкодженими.

Якщо ви хочете очистити всі елементи масиву, вам доведеться відвідати кожен елемент. Це те, що memsetдля:

memset(&arr[0], 0, sizeof(arr));

Це взагалі найшвидший спосіб подбати про це. Якщо ви можете використовувати C ++, розгляньте замість std :: fill:

char *begin = &arr;
char *end = begin + sizeof(arr);
std::fill(begin, end, 0);

1
Я вважаю, що друга версія повинна бути: std :: fill (arr, arr + sizeof (arr) / sizeof (arr [0]), 0);
David Rodríguez - dribeas

Уточнення: не використовуйте sizeof з заливкою, тому що пізніше ви потрапите в проблеми з масивами int, long, double або тим, що у вас є.
Зан Лінкс

Я віддаю перевагу: std :: fill (& arr [0], & arr [arr_len], 0);
Зан Лінкс

Зан Лінкс, це невизначена поведінка. ви не можете зробити & arr [arr_len]. але ви повинні зробити std :: fill (arr, arr + sizeof arr, 0); або якщо у вас довжина десь std :: fill (arr, arr + arr_len, 0); припускаючи масив char
Йоханнес Шауб - ліб

Він дійсний лише на С. хоча питання чітко спрямоване на C (інший хлопець додав тег C ++, я не маю поняття чому), std :: fill демонструє спорідненість C ++ :)
Йоханнес Шауб - ліб

25

Чому ви думаєте, якщо встановлення одного елемента очистить весь масив? Особливо мало часто буває, коли програміст прямо не програмує це. Якщо ви встановите перший елемент на нуль (або будь-яке значення), то ви зробили саме це, і нічого більше.

При ініціалізації ви можете встановити масив у нуль:

char mcd[40] = {0}; /* sets the whole array */

Інакше я не знаю жодної техніки, крім мессета, чи чогось подібного.


Я думаю, це залежить від компілятора, який ви використовуєте
cocoafan

1
@cocoafan: Ні, це не залежить від компілятора. Це частина мовної специфікації. Будь-який компілятор, який поводиться інакше, не дотримується мови C.
абеленький

Я цього не знав, дякую. Я не міг знайти жодного ресурсу, де б міг прочитати цей особливий випадок. Було б добре, щоб це було як закладка.
какаофан

1
Це називається частковою ініціалізацією. У мене немає специфікації C99, але ось два джерела: bit.ly/enBC2m "Вам не потрібно ініціалізувати всі елементи в масиві. Якщо масив частково ініціалізується, елементи, які не ініціалізовані, отримують значення 0 відповідний тип. " bit.ly/f9asHH "Якщо в масиві менше ініціалізаторів, ніж елементів, решта елементів автоматично ініціалізуються до 0"
abelenky

Це не стосується масиву, який вже був оголошений і присвоєний значеннями, чи не так?
skinnedKnuckles

10

Використання:

memset(my_custom_data, 0, sizeof(my_custom_data));

Або:

memset(my_custom_data, 0, strlen(my_custom_data));

1
Другий варіант ( memset(my_custom_data, 0, strlen(my_custom_data));) очистить лише перший '\ 0', який може бути поза кінцем масиву. Це може бути, а може й не гаразд.
brewmanz

9

Спробуйте наступний код:

void clean(char *var) {
    int i = 0;
    while(var[i] != '\0') {
        var[i] = '\0';
        i++;
    }
}

2
FYI - відступ коду на 4 пробіли або виберіть його та натисніть кнопку 'code', яка має вигляд двох дворядкових рядків.
meagar

Відмінне рішення, якщо ви не хочете включати string.h для memset ().
Акаш Агарвал

7

Чому б не використовувати memset()? Ось як це зробити.

Якщо встановити перший елемент, залишок пам’яті залишається недоторканим, але функції str вважатимуть дані порожніми.


1
Не використовуйте MemSet над читання: stackoverflow.com/questions/453432 / ...
Йоганн Gerell

1
і яка у вас відповідь тоді?
mkb

6

Знайдіть нижче, де я пояснив дані в масиві після випадку 1 та випадку 2.

char sc_ArrData[ 100 ];
strcpy(sc_ArrData,"Hai" );

Випадок 1:

sc_ArrData[0] = '\0';

Результат:

-   "sc_ArrData"
[0] 0 ''
[1] 97 'a'
[2] 105 'i'
[3] 0 ''

Випадок 2:

memset(&sc_ArrData[0], 0, sizeof(sc_ArrData));

Результат:

-   "sc_ArrData"
[0] 0 ''
[1] 0 ''
[2] 0 ''
[3] 0 ''

Хоча встановлення першого аргументу на NULL зробить трюк, доцільно використовувати memset


4

Ні. Все, що ви робите, - це встановити перше значення на "\ 0" або 0.

Якщо ви працюєте з нульовими завершеними рядками, то в першому прикладі ви отримаєте поведінку, яка імітує те, що ви очікуєте, однак пам'ять все одно встановлена.

Якщо ви хочете очистити пам'ять, не використовуючи memset, використовуйте цикл for.


Я кажу "ні" на циклі "for". Намагайтеся не писати власні «покращені» (а зазвичай ні) функції бібліотеки. Насправді, memset та memcpy є досить особливими, вони часто вкладаються у спеціальний машинний код для центрального процесора, виходячи з того, що відомо про вирівнювання даних та довжину.
Зан Лінкс

@Zan OP не хоче використовувати мемсет (можливо, він вбудований і його немає). Але так, мемсет зазвичай є оптимальним і, ймовірно, швидшим, ніж цикл for.
Адам Хоуз

Щоправда, проте він не хотів використовувати мессет, тому я запропонував цикл.
Алан

3

Вам слід використовувати мемсет. Якщо встановити лише перший елемент, не вийде, вам потрібно встановити всі елементи - якщо ні, як ви могли встановити лише перший елемент на 0?


MemSet не слід використовувати більш читаності: stackoverflow.com/questions/453432 / ...
Йоганн Gerell

2

Запис нульового символу до першого символу робить саме це. Якщо ви ставитесь до нього як до рядка, код, що підпорядковується символу нульового припинення, розглядає його як нульовий рядок, але це не те саме, що очищення даних. Якщо ви хочете фактично очистити дані, вам потрібно буде використовувати мессет.



1

Думав, встановивши перший елемент на нуль, очистить весь вміст масиву char.

Це не правильно, як ви виявили

Однак це встановлює лише перший елемент.

Саме так!

Для очищення всіх даних вам потрібно використовувати memset, недостатньо встановити одну з записів на нуль.

Однак, якщо встановлення елемента масиву для null означає щось особливе (наприклад, при використанні нульового завершального рядка в), можливо, буде достатньо встановити перший елемент на null. Таким чином, будь-який користувач масиву зрозуміє, що він порожній, хоча масив все ще включає в пам'ять старі символи


Не використовуйте «MemSet» над читання: stackoverflow.com/questions/453432 / ...
Йоганн Gerell

1

встановити перший елемент на NULL. друк масиву char не поверне нічого.



-3
void clearArray (char *input[]){
    *input = ' '; 
}

1
Це НЕ ЧИСЛЕННЯ, це просто встановлення першого символу на ""! Я думаю, ви хотіли написати * input = '\ 0'
stviper

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.