Здесь ИНДИВ можно назвать поиск символа c
в строке divs
, например:
inDiv('x', "is there an x character in here somewhere?') will return 1
inDiv('x', "ahhh... not this time') will return 0
Работа через него:
int inDiv(char c, char * divs)
{
char * p_divs = divs; // remember which character we're considering
char tmp;
while(tmp = *p_divs++) // copy that character into tmp, and move p_divs to the next character
// but if tmp is then 0/false, break out of the while loop
if (tmp == c) return 1; // if tmp is the character we're searching for, return "1" meaning found
return 0; // must be here because tmp == 0 indicating end-of-string - return "0" meaning not-found
}
Мы можем сделать вывод, что о reverse
глядя на месте вызова:
int main()
{
char source[MAS_SIZE], dest[MAS_SIZE], divs[MAS_SIZE];
printf("String : ");
gets(source);
printf("Dividers : ");
gets(divs);
reverse(source, dest, divs);
printf("Reversed string : %s", dest);
Мы можем видеть, что gets()
вызывается для чтения со стандартного ввода в массивы символов source
и divs
-> эти входы затем предоставляются на номер reverse()
. Путь dest
напечатан, это явно предназначено для назначения для разворота строки в source
. На этом этапе нет понимания значимости divs
.
Давайте посмотрим на источник ...
void reverse(char * source, char * dest, char * divs)
{
*dest = '\0'; //what does this pointer do?
int source_len = strlen(source); //what is source
if (source_len == 0) return;
char* p_source = source + source_len - 1;
char* p_dest = dest;
while(p_source >= source)
{
while((p_source >= source) && (inDiv(*p_source, divs))) p_source--;
Здесь *dest = '\0'
записывает символ NUL в массив символов dest
- это нормальное значение сторожевого кодирующая конца-строки позиции - положить его в на первый символ *dest
подразумевает, что мы хотим, чтобы пункт назначения был очищен. Мы знаем, что source
- это текстовый ввод, который мы будем реверсировать - strlen()
установит source_len
на количество символов в нем. Если символов нет, то return
, так как нет работы, и вывод уже завершен с помощью NUL. В противном случае создается новый указатель p_source
до source + source_len - 1
->, что означает, что он указывает на последний символ не-NUL в источнике. p_dest
указывает на символ NUL в начале буфера назначения.
Тогда петля говорит: while (p_source >= source)
- для этого, чтобы сделать что-нибудь p_source
должен быть изначально >= source
- это имеет смысл, как p_source
точек на последнем символе и source
является первым адресом символа в буфере; сравнение подразумевает, что мы будем перемещать один или оба друг к другу, пока они не переберутся, - делая какую-то работу каждый раз. Что приводит нас к:
while((p_source >= source) && (inDiv(*p_source, divs))) p_source--;
Это тот же самый тест, который мы только что видели, - но на этот раз мы только перемещение p_source
назад к началу строки, а inDiv(*p_source, divs)
также верно ... это означает, что символ в *p_source
является одним из символов в строке divs
. Это означает, что в основном: перемещение назад, пока вы не прошли старт строки (хотя этот тест имеет неопределенное поведение, как отмечает Майкл Берр в комментариях, и действительно может не работать, если строка будет выделена по адресу 0 - даже если относительно некоторого определенного сегмента данных, поскольку указатель мог бы перейти от 0 к чему-то вроде FFFFFFFF hex без когда-либо кажущегося меньше 0) или до тех пор, пока вы не найдете символ, который не является одним из символов «разделителя».
Здесь мы получаем некоторое представление о том, что делает код ... разделяя входные слова на «слова», разделенные любым набором символов в входе divs
, а затем записывая их в обратном порядке с разделителями пробелов в место назначения буфер. Это становится впереди себя немного - но давайте отслеживать его через:
Следующая строка ...
if (p_source < source) break;
... что означает, если петля возбужденных Поддержав мимо переднюю часть исходной строки , затем вырваться из всех циклов (смотря вперед, мы видим, что код просто добавляет новый NUL в конец уже сгенерированного вывода и возвращает - но это то, что мы ожидаем?), если бы мы продержались через «hello» в «hello world», тогда мы бы нажали на начало строки и закончили цикл, не копируя это последнее «привет» слово на выход! На выходе всегда будут все слова на входе - кроме первого слово - обратное - это не поведение, описанное автором).
В противном случае:
char* w_end = p_source; // remember where the non-divider character "word" ends
// move backwards until there are no more characters (p_source < source) or you find a non-divider character
while((p_source >= source) && (!inDiv(*p_source, divs))) p_source--;
// either way that loop exited, the "word" begins at p_source + 1
char * w_beg = p_source + 1;
// append the word between w_beg and w_end to the destination buffer
for(char* p = w_beg; p <= w_end; p++) *p_dest++ = *p;
// also add a space...
*p_dest++ = ' ';
Это постоянно происходит для каждого «слова» на входе, то последняя строка добавляет терминатор NUL к месту назначения.
*p_dest = '\0';
Теперь, вы сказали:
согласно [к] писатель пишет нитка привет мир, то существует функция в нем, что также изменяет строку мира привет
Ну, учитывая входы «hello world» и разделительные символы, включая пробел (но ни один из других символов на входе), тогда выход будет «hello world» (обратите внимание на пространство в конце).
Для чего это стоит - этот код не так уж плох ... это довольно нормально для обработки C буферов ASCIIZ, хотя предположения о длительности ввода опасны, и в нем отсутствует первое слово ....
** Как исправить неопределенное поведение **
Относны неопределенное поведение - наималейшее изменение адреса, который должен изменить петлю, чтобы они заканчиваются, когда в начале буфера, и имеют следующую строку явным образом проверяю, почему он прекратил работу и выяснил, какое поведение требуется. Это будет немного уродливо, но это не ракетостроение ....
«Мой квест - это то, что делает этот код?» Учитывая, что он использует 'gets', ответ таков: он ставит под угрозу вашу систему по самому ее существованию. По крайней мере, ИМО, попросив кого-то проанализировать этот код, это как дать кому-то 5-галлоновую ведро сточных вод и спросить, откуда все это. Код - уродливый беспорядок. Если вы хотите знать, как выполнять задачи, которые он якобы делает, вы должны спросить об этом напрямую, поэтому кто-то может объяснить, как это сделать. Этот код следует игнорировать, кроме (возможно) в качестве примера того, чего следует избегать. –
@JerryCoffin: Ого, это довольно грубо. Я видел намного худший код. –
@MichaelBurr: Я тоже видел хуже, но, чтобы читать слова и печатать их в обратном порядке, это все еще * ерунда * отправная точка. Легко понять задачу, начиная с чистого листа. –