Консультация № 180492
29.10.2010, 19:50
52.03 руб.
0 13 2
Здравствуйте, уважаемые эксперты!
В продолжение вопроса №180480 о слиянии строк в C++.
Кое что начинает проясняться, но хотелось бы посмотреть реализацию следующего алгоритма на С++.

1. Выделяем память оператором new для последующего размещения в ней строки не более 100 байт.
2. Заносим в эту память строку "Ваше число: "
3. Добавляем к этой строке целое число из переменной типа int
4. Вызываем функцию с полученной строкой, которая в качестве аргумента принимает const char *string

Например, на Перле я бы организовал это так:
$a=10;
$str="Ваше число: $a";
func($str);

Вот как-то так.

Обсуждение

давно
Профессор
230118
3054
29.10.2010, 20:14
общий
это ответ
Здравствуйте, Калашников О.А.!

Типа const char *string не бывает. Можно использовать const char *, а можно string, который является частью библиотеки STL и подключается с помощью #include <string>. В VS можно подключить MFC и использовать класс CString, в .Net Managed C++ тоже есть класс, аналогичный такому же в С#. Строковые литералы имеют тип const char *.


Подход, типичный для чистого C
Код:

int a=10;
char* buf=malloc(100);
sprintf(buf,"vashe chislo=%d",a);
printf(buf);
free(buf);
return 0;

Если взять оператор new из С++, но старые средства вывода, получится
Код:

#include <stdlib.h>
#include <stdio.h>
void func(const char * str)
{
}

int main(int argc, char* argv[])
{
int a=10;
char* buf=new char[100];
sprintf(buf,"vashe chislo=%d",a);
printf(buf);
delete[] buf;
return 0;
}

buf константой объявлять нельзя, потому что sprintf меняет строку, и программа не компилируется. Но ее можно передать в func. Обратный случай невозможен.

В STL строка является шаблоном basic_string, имеющим специализации string и wstring. Второй можно использовать для юникода.
В качестве параметра конструктора string может выступать строковый литерал. string имеет то преимущество, что STL сама занимается проблемами выделения и освобождения памяти.


5
Благодарю! Подробное и профессиональое решение!
Неизвестный
29.10.2010, 20:34
общий
это ответ
Здравствуйте, Калашников О.А.!
К предыдущему решению могу добавить еще одно. Без оператора new и в чисто C++ стиле. Кроме того, если используете компиляторы от MS и Borland, можете попробовать нестандартную ф-ю itoa(). Либо написать собственную ф-ю преобразования, что не сложно.
Код:
/* 
* File: main.cpp
* Author: Micren
*
* Created on 29 Октябрь 2010 г., 19:08
*/
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdio>

/*
*
*/
const size_t STR_SIZE = 100;

void func(const char* const str)
{
std::cout << str << std::endl;
}

void func(const std::string& str)
{
std::cout << str << std::endl;
}

int main(int argc, char** argv)
{
int a = 10;

// 1й вариант
std::stringstream sstream;
sstream << "Ваше число: " << a;
func(sstream.str());

// 2й вариант
try
{
char* str = new char[STR_SIZE];
strcpy(str, "Ваше число: ");
sprintf(str, "%s%i", str, a);
func(str);
delete[] str;
}
catch (std::bad_alloc)
{
std::cerr << "Не могу выделить память" << std::endl;
return 1;
}

return 0;
}

Вывод программы:
Код:
Ваше число: 10
Ваше число: 10
5
Благодарю! Подробное и профессиональое решение!
давно
Руководитель
2
547
29.10.2010, 20:39
общий
Гаряка Асмик:
Благодарю за подробный ответ!

Возникло два небольших дополнения.

1. Попробовал второй вариант на С++, получил предупреждение компилятора:
warning C4996: 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead.

2. Вытекающий из 1. Оптимальный ли этот способ на Ваш взгляд? Может быть можно проделать это другими способами?
давно
Профессор
230118
3054
29.10.2010, 20:52
общий
Калашников О.А.:
Это предупреждение выдает VS, и можно послушаться компилятора и использовать sprintf_s, но я как раз хочу добавить вариант полностью STL, в котором идея в том, что строка рассматривается как поток, в который можно записать число как в cout. Однако Micren его уже написал.
давно
Старший Модератор
31795
6196
29.10.2010, 21:08
общий
Калашников О.А.:
Эх, Олег Александрович, такого ассемблерщика теряем.

Написали программу, скомпилировали и IdaIce'снули её. Там уже всё по байтикам будет разложено.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
29.10.2010, 21:12
общий
Калашников О.А.:
Ф-я sprintf() считается небезопасной только потому, что программисту самому надо контролировать размер приемного буфера и быть уверенным, что не произойдет переполнение. Т.к. ф-я сама не знает его размер. Если Вы уверены в том, что этого не произойдет то можно вообще отключить это сообщение компилятора поместив перед ней:
Код:
#pragma warning(disable:4996)

Чтоб глаза не мозолило это сообщение. Вообще, у MS много таких функций.
Неизвестный
29.10.2010, 21:13
общий
Зенченко Константин Николаевич:
Цитата: Зенченко Константин Николаевич
Эх, Олег Александрович, такого ассемблерщика теряем.
Ничего страшного. Компиляторы C++ поддерживают директиву asm
давно
Старший Модератор
31795
6196
29.10.2010, 21:42
общий
Micren:
Вопрос несколько в другом.
Компилятро С(С++) перед тем, как отдать управление функции main, производит некоторые действия, main(int argc, char* argv[]), т.к входные параметры откуда-то берутся. Вопрос в том: посмотреть как компилятор размещает данные и малость оказать ему помощь в правильном их размещении.
Уже после этого стандартное std::cout << str, без всяких там аргументов.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Руководитель
2
547
29.10.2010, 22:51
общий
Всем спасибо за полезную информацию!

Сделал следующим образом:

int a=20;
char* pbuf = new char[1024];
bytes=sprintf_s(pbuf, 1024, "Здесь число %i", a);
давно
Профессор
230118
3054
29.10.2010, 23:01
общий
А если подключить QT, там можно делать
QString str;
str.setNum(1234); // str == "1234"
или
double d = 12.34;
QString str = QString("delta: %1").arg(d, 0, 'E', 3);
// str == "delta: 1.234E+01"
Неизвестный
29.10.2010, 23:15
общий
Калашников О.А.:
Цитата: Алексей Гладенюк
Сделал следующим образом:
Не многовато для буфера 1К? Там с избытком хватит и 64. Да и разместить в стеке можно. Тогда можно записать и так.
Код:
int a=20;
char buf[64];
bytes=sprintf_s(buf, "Здесь число %i", a);

Т.к. есть соответствующая перегруженная шаблонная ф-я и задавать размер в таком случае не требуется.

P.S. С использованием безопасных функций от MS код становится непереносимым.
давно
Руководитель
2
547
29.10.2010, 23:44
общий
Micren:
Цитата: 256539
Не многовато для буфера 1К?

Размер буфера в данном примере не важен.
Меня интересовал сам код, как это сделать...
Неизвестный
01.11.2010, 07:05
общий
Зенченко Константин Николаевич:
Написали программу, скомпилировали и IdaIce'снули её. Там уже всё по байтикам будет разложено.


Потом, типа, лишнее выкинули и обратно собрали?

Ну, кстати, где-то у меня статейка валялась, как собрать наименьшее по размеру приложение на с++. Там, помнится, даже выкидывались параметры int argc, char* argv[] из main опциями компилятора или как-то так.
Форма ответа