#c #putchar
#c #putchar
Вопрос:
Я не понимаю, почему при запуске этой программы в стандартный вывод записывается слишком много пробелов.
int main(int argc, char **argv)
{
argv ;
for (int i = 0; i < argc - 1; i )
{
for (int j = 0; j < strlen(*argv); j )
{
putchar(*(*(argv i) j));
}
printf("n");
}
}
Вывод:
(base) benjamin@benjamin-G5-5587:~$ ./uecho hello world baby yoyoyo
hello
world
baby
//whitespace?
yoyoy
Комментарии:
1. более того, я не понимаю, почему последний символ ‘yoyoyo’ не записывается!
Ответ №1:
Ваше условие внутреннего цикла неверно, из-за чего вы читаете за пределами. Это всегда ограничено strlen(*argv)
первым аргументом (благодаря предыдущему argv
), даже при обработке второго и последующих аргументов. Поскольку вы считываете до длины "hello"
, вы перечитываете "baby"
и не можете прочитать все "yoyoyo"
. Перечитывание baby
на один символ приводит к записи NUL
to stdout
, которую, я предполагаю, ваш терминал интерпретирует аналогично новой строке.
Я бы предложил:
- Исправление проблемы, чтобы вы использовали длину каждого аргумента для его печати, и
- Замена трудной для понимания арифметики указателей простым синтаксисом индексации массива
Конечный результат будет выглядеть так:
int main(int argc, char **argv)
{
for (int i = 1; i < argc; i ) // Adjust bounds to loop over provided args without mucking with argv directly
{
for (int j = 0; j < strlen(argv[i]); j ) // Loop to length of current arg
{
putchar(argv[i][j]);
}
printf("n");
}
}
Комментарии:
1. Спасибо за ваш ответ! Мне любопытно, есть ли у вас какое-либо представление о том, есть ли какое-либо преимущество в изучении арифметики указателей по сравнению с более читаемой записью в скобках?
2. @BenJenney: Полезно изучить его как часть разработки основы того, как компьютеры на самом деле реализуют конструкции более высокого уровня. Но на самом деле от его использования в реальном коде относительно мало пользы. В старых компиляторах с плохими оптимизаторами это потенциально может повысить производительность; в современных компиляторах с включенной оптимизацией они могут сами выполнять преобразование почти все время, а в некоторых случаях, которые я видел, достигают лучшей производительности, когда у них есть индексация логического контекста с помощью общей переменной, которая обеспечивает арифметику для отдельных указателейне делает.
3. Я думаю, что у меня был один реальный вариант использования арифметики указателей, где это действительно принесло некоторую пользу, и даже тогда это было сомнительно (просто дешевый хак для улучшения локальности кэша путем выделения одного непрерывного блока памяти, который представлял несмежные данные, при этом арифметика указателей использовалась для вычисления базовых указателей для каждого логическогонепрерывный блок). Я использовал аналогичный трюк в обратном порядке для
mmap
связки файлов (длиной в несколько страниц) последовательно по смежным адресам (так что 1000 файлов выглядели как один большой массив), что было удобно для рассматриваемого варианта использования.4. В обоих случаях это было умно и интересно писать (и
mmap
случай на самом деле значительно упростил код, одновременно улучшив время запуска, избегая чрезмерного поглощения файлов), но фактический выигрыш в производительности был минимальным.