2010-08-29 3 views
1

Прошло некоторое время с тех пор, как я работал с C++, сейчас я догоняю предстоящий тест на программирование. У меня есть следующая функция, которая имеет эту подпись:Обзор C++: Int to Char

void MyIntToChar(int *arrayOfInt,char* output) 

Int представляет собой массив целых чисел и символ * выход на буфер, который должен быть достаточно длинным, чтобы держать строковое представление целых чисел, которые принимают функцию.

Вот пример использования такой функции:

int numbers[3] = {11, 26, 81}; 
char* output = "";  // this I'm sure is not valid, any suggestions on how to 
          // to properly initialize this string? 
MyIntToChar(numbers,output); 
cout << output << endl; // this should print "11 26 81" or "11, 26, 81". 
          // i.e. formatting should not be a problem. 

Я просматривал мой старый C++ отмечает колледж, но я продолжаю иметь проблемы с этим. Я сейчас ненавижу себя за то, что поеду в мир Java и не работаю в этом.

Спасибо.

+5

Какая неприязнь к std :: string и std :: vector?(Хотя, если вы считаете, что такая штука выйдет в тесте, достаточно справедливо) – Yacoby

+0

Является ли 'void MyIntToChar (int * arrayOfInt, char * output)' частью присваивания, потому что он выглядит как C мне, 'void MyIntToChar (std :: vector in, std :: string out) 'больше похож на CPP для меня. Вы также должны уточнить свой вопрос. – 2010-08-29 09:25:28

+0

Я уверен, что тест пропускает std :: string и vector. Я хочу, чтобы мои базы были покрыты, а затем (если у меня есть время) просмотрите контейнеры и класс строк в STL –

ответ

0

Вы должны взглянуть на std::stringstream, или, более C-иш (как char* тип вместо string с может предложить) sprintf.

+0

Я попробую и дам вам знать. Спасибо –

+0

Все работает, sprintf работает, однако он только распечатывает последнее число в массиве. Любая идея, что может быть неправильным? –

+0

Затем постройте его в крошечных кусках. – Dario

1

Ну целое число преобразуется в строку потребуется максимум 12 байт, включая знак (предполагая, что 32-битный), так что вы можете выделить что-то вроде этого

char * output= new char[12*sizeof(numbers)/sizeof(int)]; 
+0

Я не знал, что вы можете инициализировать этот указатель таким образом. Хотя это имеет смысл, учитывая эквивалентность указателей и массивов. –

1

Прежде всего, это невозможно использовать метод, как ваш пример говорит: char* output имеет размер 1 байт (не забудьте нулевой ограничитель '\0'). Таким образом, вы не можете вставить в него целую строку. Вы получите ошибки сегментации. Итак, здесь вы собираетесь использовать кучу. Это уже реализовано в std::string и std::stringstream. Поэтому используйте их для этой проблемы.

Давайте посмотрим:

#include <string> 
#include <sstream> 
#include <iostream> 

std::string intArrayToString(int *integers, int numberOfInts) 
{ 
    std::stringstream ss; 
    for (int i = 0; i < numberOfInts; i++) 
    { 
     ss << integers[i] << ", "; 
    } 
    std::string temp = ss.str(); 
    return temp.substr(0, temp.size() - 2); // Cut of the extra ", " 
} 

И если вы хотите, чтобы преобразовать его в char*, вы можете использовать yourString.c_str();

+0

Спасибо за ваш ответ. Я не уверен, что использование stringstream и string внутри функции будет работать для меня. –

+0

@ Джонатан: Почему бы и нет? Я думаю, что это действительно лучший способ сделать это ... –

+1

Ну, я стараюсь избегать использования струнных и других классов в STL, о чем мне посоветовал программист, с которым я разговаривал. Он рекомендовал мне сосредоточиться на основах C/C++, а затем перейти к расширенным темам, таким как STL. –

0

пытались ли вы Sprintf(), он будет делать ваш work.For символ * инициализации, вы должны либо инициализировать его, вызвав malloc, либо вы можете взять его как массив символов и передать адрес функции, а не значение.

+0

Я попробую sprintf и опубликую мои выводы. Благодаря! –

+0

Все работает, sprintf работает, однако он выводит только последнее число в массиве. Любая идея, что может быть неправильным? –

2
void MyIntToChar(int *arrayOfInt, char* output); 

Это неправильно несколькими способами. Во-первых, это неправильно. Вы не можете, в общем, преобразовать целое число в один символ, потому что только десять из всех промежуточных звеньев (0 ... 9) будут вписываться в один. Поэтому я предполагаю, что вы хотите преобразовать целые числа в _strings.

Затем, если вы передаете массивы в функции, они распадаются на указатели на их первый элемент, и вся информация о размере массива теряется. Итак, когда вы передаете массивы для работы, вам также нужно передать информацию о размере.
Либо использовать путь C делать это и передать количество элементов в std::size_t (быть получены sizeof(myarray)/sizeof(myarray[0])):

void MyIntToStr(int *arrayOfInt, std::size_t arraySize, char* output); 

Или это C++ путь и пройти в двух итераторы, один указывающего на первый элемент (так называемый начинают итератор), а другой указывая на один за последний (конечный итератор):

void MyIntToStr(int *begin, int *end, char* output); 

Вы можете улучшить, что, не настаивая на итераторы будучи int*, но ничего, что, когда разыменовании дает int:

template< typename FwdIt > 
void MyIntToStr(FwdIt begin, FwdIt end, char* output); 

(. Шаблоны потребуется вам реализовать алгоритм в заголовке)

Тогда возникают проблемы с выходом. Прежде всего, вы действительно ожидаете все цифры, которые будут записаны в одна строка? Если да, то как они должны быть разделены? Ничего? Пробелы? Запятая?
Или вы ожидаете возвращения массива строк?


Предполагая, что вы действительно хотите одну строку, если я передать массив {1, 2, 3, 4, 5} в вашу функцию, она нуждается в пространстве для пяти однозначных чисел плюс пространство, необходимое для четырех сепараторов. Ваша подпись функции предполагает, что вы хотите, чтобы я выделил этот аванс, но, честно говоря, если я должен сам это рассчитать, я бы тоже сам сделал конверсии. Кроме того, я не могу сказать вам, сколько памяти это char*, поэтому вы не можете проверить, был ли я прав. Как выяснили поколения разработчиков, так сложно каждый раз получать право, что несколько компьютерных языков были изобретены, чтобы облегчить программистам работу. Одним из них является C++, который в настоящее время поставляется с динамическим изменением размера строкового класса.
Было бы намного проще (для вас и для меня), если я мог бы передать вам stirng и вы пишете в том, что:

template< typename FwdIt > 
void MyIntToChar(FwdIt begin, FwdIt end, std::string& output); 

Обратите внимание, что я это передает строку за не- const ссылки. Это позволяет вам изменить мою строку и позволить мне видеть сделанные вами изменения.
Однако после того, как мы делаем это, вы могли бы точно так же возвращают новую строку вместо requireing меня передать один к вам:

template< typename FwdIt > 
std::string MyIntToChar(FwdIt begin, FwdIt end); 

Если, однако, вы на самом деле нужен был массив строк, вы не должны брать одну строку для записи, но это значит, где их записать. Наивный способ сделать это - передать динамически переопределяемый массив динамически переопределяемой строки. В C++ это пишется std::vector<std::string>:

template< typename FwdIt > 
void MyIntToStr(FwdIt begin, FwdIt end, std::vector<std::string>& output); 

Опять же, это может быть лучше вы вернуть такой массив (хотя некоторые не согласятся, так как копирование массив строки можно считать дорогим).Однако лучший способ сделать это не потребует от меня принятия результата в виде «std :: vector». Что делать, если мне нужны строки в (связанном) списке? Или написано в какой-то поток?
Лучший способ сделать это будет для вашей функции, чтобы принять выходной итератор, к которому вы пишете свой результат:

template< typename FwdIt, typename OutIt > 
void MyIntToStr(FwdIt begin, FwdIt end, OutIt output); 

Конечно, теперь это так вообще, что это трудно понять, что он делает, так что хорошо, что мы дали ему хорошее имя. Однако, глядя на это, я сразу думаю, что это должно основываться на другой функции, которая нужна, вероятно, даже больше, чем эта: функция, которая принимает один целое число и преобразует его в один строка. Если предположить, что у нас есть такая функция:

std::string MyIntToStr(int i); 

это очень легко реализовать версии массива:

template< typename FwdIt, typename OutIt > 
void MyIntToStr(FwdIt begin, FwdIt end, OutIt output) 
{ 
    while(begin != end) 
    *output++ = MyIntToStr(*begin++); 
} 

Теперь все, что вам остается сделать, это реализовать эту функцию std::string MyIntToStr(int i);. Как уже писал кто-то еще, это легко сделать, используя строковые потоки, и у вас не должно возникнуть проблемы, чтобы найти хорошие примеры для этого. Тем не менее, это даже легче найти плохие примеры, так что я предпочел бы дать вам один здесь:

std::string MyIntToStr(int i); 
{ 
    std::ostringstream oss; 
    oss << i: 
    if(!oss) throw "bah!"; // put your error reporting mechanism here 
    return oss.str(); 
} 

Конечно, данные шаблоны, которые легко обобщается принимать что-либо, что это поточное:

template< typename T > 
std::string MyIntToStr(const T& obj); 
{ 
    std::ostringstream oss; 
    oss << obj: 
    if(!oss) throw "bah!"; // put your error reporting mechanism here 
    return oss.str(); 
} 

Обратите внимание, что, учитывая этот шаблон общей функции, MyIntToStr(), работающий с массивами, теперь автоматически работает на массивах любого типа, на которых работает шаблон функции, работающий над одним объектом.


Таким образом, в конце этого (а эпическое, я Извинения) путешествие, это то, что мы достигли: обобщенный шаблон функции для преобразования ничего (которое можно записать в поток) в строку, и обобщенный шаблон функции для преобразования содержимого любого массива объектов (который может быть записан в поток) в поток.

Обратите внимание, что, если вы имели, по крайней мере дюжину 90mins лекции на C++ и ваши преподаватели не смогли научить вас достаточно, по крайней мерепонять, что я написал здесь, у вас естьнехорошо преподавали в соответствии с современными стандартами обучения на С ++.

+0

Я считаю, что вы забыли оператора ++ в MyIntToStr. Итератор 'output' не продвигается. –

+0

@Maciej: Действительно, спасибо! Я починил это. – sbi

1

Вот возможность, если вы готовы пересмотреть изменения в прототипе функции

template<int n> 
void MyIntToChar(int (&iarr)[n], string &output){ 
    stringstream ss; 
    for(size_t id = 0; id < n; ++id){ 
     ss << iarr[id]; 
     if(id != n - 1) ss << " "; 
    } 
    output = ss.str(); 
} 

int main(){ 
    int numbers[3] = {11, 26, 81}; 
    string out = ""; 
    MyIntToChar(numbers, out); 
} 
0

звучит, как вы хотели бы использовать C Ланга. Вот пример. В конце вывода есть дополнительный «,», но он должен дать вам представление о концепции. Кроме того, я изменил тип возврата, чтобы я знал, сколько байтов вывода было использовано. Альтернативой будет инициализация вывода.

int MyIntToChar(int *arrayOfInt, char* output) { 
    int bytes_used = 0; // use to bump the address past what has been used 
    for (int i = 0 ; i < sizeof(arrayOfInt); ++i) 
     bytes_used += sprintf(output + bytes_used, "%u, ", arrayOfInt[i]); 

    return bytes_used; 
} 

int main() {  
    int numbers[5] = {5, 2, 11, 26, 81}; // to properly initialize this string? 
    char output[sizeof(int)*sizeof(numbers)/sizeof(int) + sizeof(numbers)*2]; // int size plus ", " in string 

    int bytes_used = MyIntToChar(numbers, output); 
    printf("%*s", bytes_used, output);// this should print "11 26 81" or "11, 26, 81". 
    }