Проблема с fputs и printf
Я получил следующий код:
char* writeSpace(int i)
{
fputs(" " + (30-i), stdout);
}
printf("#%i key: %s%svalue: %s%s value2: %s", id, key, writeSpace(10), value, writeSpace(8), value2);
мой вывод должен выглядеть примерно так:
#1 key: foo value: bar value2: foobar
но это не так. это выглядит как:
#1 key: foo(null)value: bar(null)value2: foobar(null)
Что не так с моим кодом?
5 ответов
Ну ты fput
привязать все эти пробелы к консоли, чтобы вы сначала получили их.
Затем вы выводите все остальное, так что вы получите это дальше.
Возможно, вы имели в виду writeSpace
вернуть строку в стиле C, а не выводить ее на консоль.
Но будьте уверены, что вы выделите для этого место! Поскольку владение буферами памяти становится немного странным, лучше всего выделять пространство вне функции.
void writeSpace(char* buf, int i) {
fputs(" " + (30-i), buf);
}
char spaceBuf1[30];
writeSpace(spaceBuf1, 10);
char spaceBuf2[30];
writeSpace(spaceBuf2, 8);
printf("#%i key: %s%svalue: %s%s value2: %s",
id, key, spaceBuf1, value, spaceBuf2, value2);
И подумайте об использовании реальных функций C++, таких как iostreams и std::string
, Это будет намного проще:
std::cout << "#" << id << " "
<< " key: " << std::setw(30) << key
<< " value: " << std::setw(30) << value
<< " value2: " << value2;
Я рекомендую эти ресурсы для изучения идиоматического C++.
Вы объявили writeSpace()
вернуть char*
, но вы ничего не вернули.
Ваш writeSpace
Функция не возвращает новую строку (даже если вы объявили ее таким образом), но пишет напрямую в терминал. Так как вы называете это в качестве аргумента в вашем printf
вызов, writeSpace
сначала вызывается, печатает свои вещи, а затем printf
печатает свои вещи. Вы должны сделать это так:
char* writeSpace(int i)
{
char *ret = NULL;
asprintf(ret, " " + (30-i));
return ret;
}
Конечно, это требует от вас free
память (в противном случае у вас будет утечка памяти). Вы можете сделать это так:
char *spaces = writeSpace(10);
printf("%s%i", spaces, 42);
free(spaces);
Альтернативой является использование статической переменной, которую сама функция очищает при следующем вызове:
char* writeSpace(int i)
{
static char *ret = NULL;
if (ret != NULL) free(ret);
asprintf(ret, " " + (30-i));
return ret;
}
Но это имеет тот недостаток, что вы можете использовать только один вызов writeSpace
в вашем printf
аргументы, так как второй очистит память предыдущего вызова. Все еще может быть то, что вы хотите.
Кстати, The + (30-i)
часть зла То, что вы, вероятно, хотите, это вместо этого:
asprintf(ret, "%*s", i, ""); // Prints i spaces
Если вы хотите отформатировать переменную ws'и вам абсолютно необходимо использовать простой C, вы можете использовать строки такого формата (%*c, где * - это число ws, а c - символ, который нужно установить (' 'в этом случае, конечно)):
sprintf(buffer, "%*cafterspace", 30, ' '); // Will print 30 ws and then "afterspace".
sprintf(buffer, "%*cafterspace", 15, ' '); // Will print 15 ws and then "afterspace".
Но вы все равно должны подготовить буфер, как объяснил Томалак!
Другие предоставленные ответы имеют правильный ответ, который вы ищете. Тем не менее, я хотел бы попытаться добавить небольшое объяснение симптомов, которые вы видели, чтобы помочь вам избежать их в будущем.
когда ваш оператор printf выполняется:
printf("#%i key: %s%svalue: %s%s value2: %s", id, key, writeSpace(10), value, writeSpace(8), value2);
Два вызова метода writeSpace() выполняются до того, как сам printf что-либо сделает. Причина этого заключается в том, что возвращаемое значение этих методов используется в качестве аргументов для метода printf. Итак, последовательность выполнения для приведенной выше строки кода:
- writeSpace (10), который печатает некоторые пробелы в стандартный вывод и возвращает нулевой указатель.
- writeSpace (8), который печатает еще несколько пробелов для стандартного вывода, а также возвращает нулевой указатель.
- наконец, printf вызывается со следующими аргументами: printf("#%i ключ: %s%svalue: %s%s значение2: %s", id, ключ, ноль, значение, ноль, значение2);
Вот почему вы видите пробелы, напечатанные в начале, а также почему вы видите, что "(ноль)" появляется в ваших выходных данных.
Таким образом, урок здесь заключается в том, что во время выполнения программы аргументы метода разрешаются до вызова самого метода.