C ++, как правильно считать символы в константном символе? - PullRequest
1 голос
/ 17 февраля 2012

У меня есть константный символ, который создается конкатенацией следующим образом:

const char *fileName = "background1";

std::stringstream sstm;
sstm << fileName << "-hd.png";
fileName = sstm.str().c_str();

Моя проблема в том, что следующая инструкция:

printf("const char = %s size = %d", fileName, sizeof(fileName));

возвращает:

"const char = background1-hd.png size = 4"

в то время как я ожидаю, что он возвращает:

"const char = background1-hd.png size = 19"

Например, следующее дает удобный результат (так как нет конкатенации):

const char *fileName2 = "background1-hd";
printf("const char = %s size = %d", fileName2, sizeof(fileName2));

возвращает:

"const char = background1-hd.png size = 19"

Как избежать этой проблемы и гарантировать, что символы будут правильно подсчитаны в моем сцепленном символе?

Спасибо !!

Ответы [ 6 ]

8 голосов
/ 17 февраля 2012

sizeof() возвращает количество байтов, которое переменная занимает в памяти (в этом случае возвращает размер указателя fileName).

strlen() возвращает длину строки (чтовам нужно).

Вы также можете попробовать что-то вроде:

#include <iostream>
#include <cstdio>

int main()
{
    std::string fileName("background1");
    fileName.append("-hd.png");
    printf("const char = %s size = %d", fileName.c_str(), fileName.length());

    return 0;
}
3 голосов
/ 17 февраля 2012

sizeof возвращает размер переменной, которую вы ей передаете; он оценивается во время компиляции. «4» - это размер указателя в вашей системе. Вы хотите использовать strlen() для определения длины строки.

2 голосов
/ 17 февраля 2012

sizeof вычисляет размер типа данных в байтах, а не размер его содержимого (на что он указывает). В вашем примере вы вычисляете sizeof char*, что составляет 4 байта в вашей системе. Чтобы получить длину строки C, используйте strlen .

2 голосов
/ 17 февраля 2012

Результат sizeof(fileName) связан с fileName указателем, а не массивом. Он буквально возвращает размер указателя на строку константных символов, а в 32-разрядной системе все указатели являются 32-разрядными (поэтому sizeof == 4).

Вместо этого вы должны использовать strlen или аналогичный, который будет подсчитывать символы в строке до конечного нуля и возвращать его. Результаты с strlen вместо sizeof будут примерно такими, как вы ожидаете.

Относительно стороны, со строками const char всегда есть только один символ на "ячейку" (фактически байт). Существуют наборы символов, содержащие несколько байтов на символа , но упаковка нескольких символов в один байт встречается довольно редко, по крайней мере, в языках семейства C.

1 голос
/ 17 февраля 2012

strlen уже предлагалось несколько раз, и для этого случая это, вероятно, совершенно разумно.

Существует альтернатива, которая позволит вам использовать sizeof, хотя:

char fileName[] = "background1";

std::cout << sizeof(fileName) << "\n";

Поскольку вы делаете fileName массивом, он обладает всеми характеристиками массива, включая тот факт, что ваша более поздняя попытка присвоения ему:

fileName = sstm.str().c_str();

... потерпит неудачу (даже не скомпилируется, если fileName определен как массив). Однако я должен добавить, что мне кажется, что вам лучше использовать std::string:

std::string fileName("background1");
std::stringstream sstm;
sstm << fileName << "-hd.png";
fileName = sstm.str();

В этом случае вы можете использовать строковый член size() или length().

1 голос
/ 17 февраля 2012

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

Как это вообще относится к вашему коду?

Ну, строковый литерал на самом деле представляет собой массив константных символов, а не указатель на символ (ы).При инициализации const char *fileName = "background1"; вы создаете переменную pointer , которая указывает на первый элемент массива ("background1" - это , затухающий в указатель на первый элемент), и изв переменной, которой вы управляете, есть указатель , а не литерал.

Если вы смешаете это с фактом, что sizeof сообщит вам размер переменной, вы получите это вплатформа с 32-битными указателями и 8-битными символами, sizeof( const char* ) всегда равно 4, независимо от объекта, на который указывает этот указатель (если он есть).

Теперь, если вы рассматривали литерал какчто на самом деле вам повезет:

const char filename[] = "background1";
assert( sizeof filename == 12 );       // note: NUL character is counted!
const char *fname = filename;
assert( sizeof filename == sizeof( void* ) );

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

...