С
Мое домашнее задание - взять строку и разбить ее на части в каждой новой строке. Я понятия не имею, что делать! Пожалуйста помоги!
Сложная задача для начинающего класса программирования C! Сначала вы должны понять несколько основ этой сложной темы.
Строка - это последовательность, состоящая только из символов . Это означает, что для того, чтобы программисты могли указать «невидимую» вещь (это не пробел, который считается символом), вы должны использовать специальную последовательность символов, чтобы обозначить эту невидимую вещь.
В Windows новая строка представляет собой последовательность из двух символов в строке: обратный слеш и n (или строка "\n"
)
В Linux или Mac OS / X это последовательность из четырех символов: обратная косая черта, n, обратная косая черта, а затем r: (или "\n\r"
).
(Интересное историческое примечание: на старых Macintoshes это была другая последовательность из четырех символов: "\ r \ n" ... полностью назад, от того, как Unix делал вещи! История идет странными путями.)
Может показаться, что Linux более расточительный, чем Windows, но на самом деле лучше использовать более длинную последовательность. Поскольку Windows использует такую короткую последовательность, среда выполнения языка C не может распечатывать реальные буквы \n
без использования специальных системных вызовов. Обычно вы можете сделать это в Linux без системного вызова (он может даже печатать \n\
или \n\q
... что угодно, кроме \n\r
). Но поскольку C предназначен для кроссплатформенности, он обеспечивает наименьший общий знаменатель. Так что вы всегда будете видеть \n
в своей книге.
(Примечание: если вам интересно, как мы говорим, \n
не получая переводы строки каждый раз, когда мы делаем, StackOverflow написан почти полностью на HTML ... не на C. Так что это намного более современно. Многие из этих старых аспектов C обращаясь к тем вещам, о которых вы, возможно, слышали, таким как CLANG и LLVM.)
Но вернемся к тому, над чем мы работаем. Давайте представим строку из трех частей и двух новых строк, например:
"foo\nbaz\nbar"
Вы можете видеть, что длина этой строки составляет 3 + 2 + 3 + 2 + 3 = 13. Поэтому вы должны создать для нее буфер длиной 13, и программисты на Си всегда добавляют один к размеру своих массивов, чтобы быть в безопасности. Так что сделайте ваш буфер и скопируйте в него строку:
/* REMEMBER: always add one to your array sizes in C, for safety! */
char buffer[14];
strcpy(buffer, "foo\nbaz\nbar");
Теперь вам нужно найти тот двухсимвольный шаблон, который представляет новую строку. Вам не разрешено искать только обратную косую черту. Поскольку C довольно часто используется для разбиения строк, при попытке вы получите ошибку. Вы можете увидеть это, если попытаетесь написать:
char pattern[2];
strcpy(pattern, "\");
(Примечание: в компиляторе есть настройка, если вы пишете программу, которая просто ищет обратную косую черту. Но это крайне редко; обратные косые черты используются очень редко, поэтому они были выбраны для этой цели. включить.)
Итак, давайте сделаем шаблон, который мы действительно хотим, как это:
char pattern[3];
strcpy(pattern, "\n");
Когда мы хотим сравнить две строки определенной длины, мы используем strncmp
. Он сравнивает определенное количество символов потенциально большей строки и сообщает вам, совпадают они или нет. Так strncmp("\nA", "\nB", 2)
возвращает 1 (правда). Это даже при том, что строки не полностью равны по длине три ... но потому, что для этого нужно всего два символа.
Итак, давайте пройдемся по нашему буферу по одному символу за раз, чтобы найти соответствие двух символов нашему шаблону. Каждый раз, когда мы находим двухсимвольную последовательность обратной косой черты, за которой следует n, мы будем использовать очень специальный системный вызов (или «системный вызов») putc
для вывода символа особого вида: код ASCII 10 , чтобы получить физическую новую строку ,
#include "stdio.h"
#include "string.h"
char buffer[14]; /* actual length 13 */
char pattern[3]; /* actual length 2 */
int i = 0;
int main(int argc, char* argv[]) {
strcpy(buffer, "foo\nbar\nbaz");
strcpy(pattern, "\n");
while (i < strlen(buffer)) {
if (1 == strncmp(buffer + i, pattern, 2)) {
/* We matched a backslash char followed by n */
/* Use syscall for output ASCII 10 */
putc(10, stdout);
/* bump index by 2 to skip both backslash and n */
i += 2;
} else {
/* This position didn't match the pattern for a newline */
/* Print character with printf */
printf("%c", buffer[i]);
/* bump index by 1 to go to next matchable position */
i += 1;
}
}
/* final newline and return 1 for success! */
putc(10, stdout);
return 1;
}
Результатом этой программы является желаемый результат ... строка разбита!
foo
baz
bar
\t
для \ троллинга ...
Абсолютно неверно сверху вниз. Тем не менее, наполненный правдоподобно звучащей ерундой, в которой зашифрована информация, подобная тому, что есть в учебнике или в Википедии. Программная логика выглядит прозрачной в контексте дезинформации, но полностью вводит в заблуждение. Даже глобальные переменные и возвращающие код ошибки, для хорошей меры ...
...
Конечно, есть только один символ в строковом представлении C двухбуквенной исходной буквенной последовательности \n
. Но увеличение буфера безвредно, поскольку strlen()
используется для получения действительной длины.
...
Мы пытаемся убедить читателя, что strncmp
это логическая операция, которая либо соответствует (1), либо не соответствует (0). Но на самом деле он имеет три возвращаемых значения (-1 соответствует меньше, 0 равно, больше соответствует 1) . Наш сравниваемый двухсимвольный «шаблон» - это не [ \
, n
], а [ \n
, \0
] ... обнаружение неявного нулевого терминатора. Поскольку эта последовательность скользит по строке, она никогда не будет больше двухсимвольной последовательности, с которой она сравнивается ... в лучшем случае она будет равна нулю, если во входной строке есть завершающий символ новой строки.
...
Таким образом, все, что это делает, это перебирает строку и печатает ее по одному символу за раз. Верхняя ветка никогда не запускается. (Хотя вы могли бы получить его, если бы в вашей строке было меньше \n
кодов, скажем, табуляция ... которая могла бы использоваться для загадочного пропуска символов в выводе :-P)