Целое число как char * для чайников - PullRequest
0 голосов
/ 29 июля 2011

Вопрос задавался раньше, но я все еще немного растерялся относительно лучшего способа. У меня есть целое число, и я хотел бы получить символ * для использования в качестве члена структуры.

Подобные вопросы, например, здесь или здесь . Я бы предпочел не использовать stringstream или lexical_cast. Который, насколько я вижу, в основном оставляет itoa, sprintf и snprintf.

Полагаю, что часть моей проблемы в том, что я не совсем понимаю, как работают указатели на символы.

  1. Если я запрашиваю char str[12], это резервирует 12 символов?
  2. Я предполагаю, что память была назначена?
  3. Так как же работает нулевое завершение?
  4. Это в конце 12 символов (с пробелами?), Или если число использует только 2 символа, произойдет ли это после двух?
  5. Имеет ли значение размер буфера или я должен просто пойти с некоторым максимумом (30 или около того я верю для 32 бит)?
  6. И если я позже воспользуюсь указателем в простой структуре, будет ли память очищаться автоматически или мне нужен деструктор?
  7. Нужно ли деструктору знать размер буфера инициализации?
  8. Почему никто не удосужился вычислить длину буфера из фактический номер?
  9. Рекомендуется ли snprintf поверх itoa?

Спасибо

Ответы [ 2 ]

2 голосов
/ 29 июля 2011

Если я запрашиваю строку символов [12], которая резервирует 12 символов?

Да, это резервирует 12 символов (байтов) в стеке .

Я предполагаю, что память была назначена?

str теперь указывает на начало 12 байтов непрерывной памяти, которая была выделена в стеке.

Так как же работает нулевое завершение?Это в конце 12 символов (с пробелами?), Или если число использует только 2 символа, это произойдет после двух?

В этом случае вы должны завершить нулемСтрока самостоятельно (это не происходит автоматически при объявлении этого типа).

Поэтому, если вы хотите, чтобы str содержал какое-либо (заканчивающееся нулем) строковое значение, вы бы сделали следующее:

str[0] = 'c';
str[1] = 'a';
str[2] = 't';
str[3] = '\0';

Другой способ получить строку с нулевым символом в конце - это сделать следующее:

char *str = "cat"; // this is null-terminated

Нет автоматического заполнения пробелами.

И если яиспользовать указатель позже в простой структуре, очистится ли память автоматически или мне нужен деструктор?

Если указатель указывает на часть памяти, выделенную в стеке, то память будетбыть восстановленным, когда стек вытолкнут.В противном случае, если вы выделите память в куче, например:

char *newStr    = new char[12];
char *mallocStr = (char*) malloc(sizeof(char) * 12);

Тогда вам придется отменить выделение памяти с помощью delete или free (в зависимости от того, какой метод вы использовали).

Нужно ли деструктору знать размер инициализируемого буфера?

В этом контексте мы говорим о выделенной памяти кучи, и поэтому ответ - нет.Система знает, сколько памяти было выделено.Вот почему вы просто указываете на delete и free без указания размера.

Почему никто не удосужился вычислить длину буфера из фактического числа?

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

Рекомендуется ли snprintf поверх itoa?

Я бы сказал да, потому что snprintf считается «безопасным», потому что он учитывает размер буфера, который вы ему даете, тогда как itoa успешно заполнит ваш буфер, не проверяя его размер (возможно, пробегая выделенное пространство и перезаписывая другую память).

int   num = 12345;
char *str = new char[4];

// this is bad because str is not big enough to hold the number
// itoa does not check buffer size and will overrun the buffer (overwriting other data)
str = itoa(num, str);

// snprintf takes the buffer size as one of it's arguments
// in this case the whole number will not fit, but at least we don't overrun the buffer
snprintf(str, 4, "%i", num);

И snprintf, и itoa завершат строки для вас нулем.

0 голосов
/ 29 июля 2011

Если вы действительно не хотите использовать std::stringstream или lexical_cast, вам следует использовать snprintf, поскольку он имеет аргумент размера буфера.itoa не является функцией ISO C.

Нуль (символ '\ 0', значение 0) может появляться в любой точке буфера, большинство функций, которые работают со строками, игнорируют все в буфере после этоготочка, так что это своего рода «потраченное впустую» пространство.

Скажем, у вас было что-то вроде

char str[] = { 'a', 'b', 'c', '\0', 'd' };

Последний элемент все еще там, хотя такие функции, как printf прекращают обработку данных, когдаони встречают 0. Однако не каждая функция делает это.

Нет конструкторов или деструкторов для массивов (или любых других примитивных типов данных).Вам нужно беспокоиться об освобождении выделенной памяти только в том случае, если вы выделяете ее самостоятельно, используя new, new[], malloc или что-то подобное.

Размер буфера, конечно, имеет значение, если он слишком мал, он может 'удерживать каждый символ числа, и если оно слишком большое, память будет потрачена впустую.22 символа должны быть в состоянии содержать каждое 64-битное целое число (но не числа с плавающей запятой / двойные числа!).

Наилучшим вариантом будет использование std::stringstream или std/boost::lexical_cast и std::string, это позаботится обо всехэти вопросы для вас.

Предлагаю вам прочитать ссылку от Martinho, очень информативно.(Массивы не указатели!)

...