Да, ваш код довольно неэффективен. Это хорошая возможность узнать о том, как символы и строки работают вместе в C. Зная это, мы можем написать гораздо более сложную версию. Он будет работать намного быстрее, и в качестве бонуса может быть несколько проще писать и читать.
(Примечание: ваш массив hexadecimal
был слишком мал. Нам нужно место для '#'
, плюс 6 шестнадцатеричных цифр, плюс завершающий '\0'
. Поэтому он должен быть char hexadecimal[8]
.)
Мы собираемся создать строку hexadecimal
, используя символы, а не строки. Таким образом, вместо hex
, являющегося массивом строк, давайте получим массив символов:
char hex[16];
hex[0] = '0';
hex[1] = '1';
/* ... */
Но подождите, массив символов - это строка. Поэтому вместо этого мы можем написать:
char hex[16] = "0123456789ABCDEF";
или просто:
char hex[] = "0123456789ABCDEF";
(Между ними есть небольшая разница, но для этой программы это не имеет значения, так или иначе.)
И теперь, вместо использования strcat
для объединения hex[r]
строк в строящуюся строку, мы собираемся поместить символы hex[r]
непосредственно в строящуюся строку:
for (i = 0; i < 6; i++) {
r = rand() % 16;
hexadecimal[i+1] = hex[r];
}
Вы заметите, что я присвоил hexadecimal[i+1]
, а не hexadecimal[i]
. Мы должны «сдвинуть все вправо» на единицу, потому что строка уже содержит начальный '#'
. Еще один способ сделать это (хотя и необычно в C) - использовать цикл на основе 1:
for (i = 1; i <= 6; i++) {
r = rand() % 16;
hexadecimal[i] = hex[r];
}
Кроме того, поскольку мы строим строку символ за раз, явно, мы могли бы также сделать наш ведущий символ '#'
таким же образом, вернувшись назад и изменив
strcpy(hexadecimal, "#");
до
hexadecimal[0] = '#';
Есть еще одна вещь, которую мы должны сделать. Поскольку мы строили строку символ за раз, вручную, мы должны также позаботиться о нулевом завершении вручную:
hexadecimal[7] = '\0';
Но, в конце концов, это будет делать то же самое: генерировать правильно сформированную строку hexadecimal
, содержащую шесть случайных шестнадцатеричных цифр:
printf("%s\n", hexadecimal);
И, прежде чем я уйду, сноска об эффективности. Я сказал: «Да, ваш код довольно неэффективен», и я заявил, что моя перезапись будет выполняться «гораздо быстрее». И хотя это правда, все относительно. Даже «неэффективная» версия будет работать намного быстрее, чем вы можете измерить, и разница между двумя версиями будет почти незаметна.
Я, в любом случае, я бы написал версию для персонажа, потому что я парень из старой школы С, и я так думаю. Но если бы была какая-то причина предпочесть версию strcat
- если ее было легче или быстрее писать, или легче читать, или легче сразу понять - мы могли бы предпочесть ее в любом случае, и просто не волнуйтесь о его "неэффективности".
Ради интереса я скомпилировал и запустил обе версии на своем ноутбуке. «Неэффективная» версия занимала 0,002 с пользовательского времени, что измерялось командой «время» Unix. «Более эффективная» версия заняла ... 0,002 с. Так что, какова бы ни была разница, она меньше миллисекунды и затоплена проблемами, связанными с накладными расходами, такими как время, затраченное на запуск программы вообще.
Итак, я добавил еще один цикл в обе программы, чтобы они генерировали 1 000 000 случайных шестнадцатеричных строк. Теперь появилась разница: неэффективная версия заняла 0,404 с, а эффективная версия - 0,263 с. (Подумайте об этом: один миллион случайных строк менее чем за полсекунды. Компьютеры работают очень и очень быстро.) Если разделить, неэффективная версия заняла 0,404 ÷ 1000000 = .000000404 с за итерацию, или 404 наносекунд . С другой стороны, эффективная версия заняла всего 263 наносекунды. Так что да, эффективная версия более эффективна - но если вам не понадобится лот из этих случайных шестнадцатеричных значений, вы никогда не заметите разницу.
Еще одна сноска. Существует серьезная потенциальная проблема с линией
r = rand() % 16;
Самое неприятное, что существуют реализации rand()
, которые не очень случайны в младших битах. Поэтому, если вы берете только младшие биты, как здесь, вы можете получить последовательность, которая совершенно не случайна, и каждый раз проходит через одну и ту же последовательность из 16 значений.
Самый простой способ исправить это (при условии, что он доступен для вас) - переключиться на лучшую функцию random()
:
r = random() % 16;
Если вы сделаете это, вам нужно использовать сопутствующую функцию srandom
:
srandom((unsigned) time(&t));
(Дополнительный вопрос: когда была обнаружена проблема с rand()
, почему кто-то просто не исправил ее, вместо того, чтобы оставить ее сломанной и изобрести более новую, но чуть менее стандартную функцию, которая работает лучше, и надеясь, что все помнят об использовании это вместо этого? Я, честно говоря, не знаю.)
Если random()
вам недоступен, вы можете увернуться от проблемы rand
, используя биты старшего разряда, например:
r = rand() / (RAND_MAX / 16 + 1);
См. Также список часто задаваемых вопросов C , вопросы 13.16 и 13.18 .