Как получить реальную и общую длину char * (массив char)?

Для char []Я могу легко получить его длину:

char a[] = "aaaaa";
int length = sizeof(a)/sizeof(char); // length=6

Тем не менее, я не могу сделать так, чтобы получить длину char * от:

char *a = new char[10];
int length = sizeof(a)/sizeof(char);

потому что я знаю, a вот указатель, такой что length здесь всегда будет 4 (или что-то другое в разных системах).

Мой вопрос заключается в том, как я могу получить длину char * после этого? Я знаю, что кто-то может бросить мне вызов, что вы уже знаете его 10 потому что вы только что создали это. Я хочу знать это, потому что этот шаг получения его длины может пройти долгий путь от его создания, и я не хочу возвращаться далеко назад, чтобы проверить это число. Кроме того, я также хочу знать его реальную длину.

Чтобы быть более конкретным

  • как я могу получить его реально length=5?
  • как я могу получить его общее length=10?

для следующего примера:

char *a = new char[10];
strcpy(a, "hello");

36

Решение

Ты не можешь Во всяком случае, не со 100% точностью. Указатель не имеет длины / размера, но имеет свои. Все, что он делает, это указывает на определенное место в памяти, которое содержит символ. Если этот символ является частью строки, то вы можете использовать strlen определить, какие символы следуют за указанным в данный момент, но это не означает, что массив в твоем случае такой большой.
В принципе:

указатель это не массив, так что это не необходимость знать, каков размер массива. Указатель может указывать на одно значение, поэтому указатель может существовать, даже не будучи массивом. Его даже не волнует, где находится память, на которую он указывает (только чтение, куча или стек … не имеет значения). Указатель не имеет длины, отличной от себя. Указатель просто …
Учти это:

char beep = '\a';
void alert_user(const char *msg, char *signal);//for some reason
alert_user("Hear my super-awsome noise!", &beep);//passing pointer to single char!
//
void alert_user(const char *msg, char *signal)
{
printf("%s%c\n", msg, *signal);
}

Указатель может быть одним символом, а также началом, концом или серединой массива …

Думайте о символах как о структурах. Иногда вы выделяете одну структуру в куче. Это также создает указатель без массива.

Используя только указатель, определить, на какой массив он указывает, невозможно. Самое близкое, к которому вы можете добраться, это использование calloc и подсчет количества последовательных символов \ 0, которые вы можете найти через указатель. Конечно, это не сработает, если вы присвоили / переназначили материал для ключей этого массива, и это также даст сбой, если память просто вне массива случается держать \0, тоже. Поэтому использование этого метода ненадежно, опасно и просто глупо. Не. Делать. Это.

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

Итак, используя указатель, вы можете только:

char a_str[] = "hello";//{h,e,l,l,o,\0}
char *arr_ptr = &a_str[0];
printf("Get length of string -> %d\n", strlen(arr_ptr));

Но это, конечно, работает, только если массив / строка заканчивается \ 0.

В качестве помощника:

int length = sizeof(a)/sizeof(char);//sizeof char is guaranteed 1, so sizeof(a) is enough

на самом деле присваивает size_t (возвращаемый тип sizeof) для intЛучше всего написать:

size_t length = sizeof(a)/sizeof(*a);//best use ptr's type -> good habit

поскольку size_t тип без знака, если sizeof возвращает большие значения, значение length может быть что-то, чего ты не ожидал …

39

Другие решения

Если char * 0-терминатор, вы можете использовать strlen

В противном случае невозможно определить эту информацию.

13

Есть только два способа:

  • Если указатель памяти на ваш char * представляет строку C (то есть, она содержит символы, которые имеют 0-байт, чтобы отметить его конец), вы можете использовать strlen(a),

  • В противном случае вам нужно где-то хранить длину. На самом деле указатель указывает только на один char, Но мы можем обращаться с ним так, как будто он указывает на первый элемент массива. Поскольку «длина» этого массива неизвестна, вам нужно где-то хранить эту информацию.

4

Учитывая только указатель, вы не можете. Вы должны будете держать длину, которую вы прошли new[] или лучше используйте std::vector чтобы следить за длиной, и освободить память, когда вы закончили с ним.

Примечание: этот ответ касается только C ++, но не C.

3
  • В C ++:

Просто используйте std::vector<char> которые сохраняют (динамический) размер для вас. (Бонус, управление памятью бесплатно).

Или же std::array<char, 10> которые сохраняют (статический) размер.

  • В чистом C:

Создайте структуру для хранения информации, например:

typedef struct {
char* ptr;
int size;
} my_array;

my_array malloc_array(int size)
{
my_array res;
res.ptr = (char*) malloc(size);
res.size = size;
return res;
}

void free_array(my_array array)
{
free(array.ptr);
}
3

char * a = новый символ [10];

Мой вопрос заключается в том, как я могу получить длину символа *

Это очень просто. 🙂 Достаточно добавить только одно утверждение

size_t N = 10;
char *a = new char[N];

Теперь вы можете получить размер выделенного массива

std::cout << "The size is " << N << std::endl;

Многие упоминали здесь C стандартную функцию std :: strlen. Но он не возвращает фактический размер массива символов. Возвращает только размер хранимого строкового литерала.

Разница в следующем. если взять в качестве примера фрагмент кода

char a[] = "aaaaa";
int length = sizeof(a)/sizeof(char); // length=6

тогда std :: strlen (a) вернет 5 вместо 6, как в вашем коде.

Таким образом, вывод прост: если вам нужно динамически выделить массив символов, рассмотрите использование класса std::string, Он имеет размер metaof и длину синонима, что позволяет в любой момент получить размер массива.

Например

std::string s( "aaaaa" );

std::cout << s.length() << std::endl;

или же

std::string s;
s.resize( 10 );

std::cout << s.length() << std::endl;
2

Это может звучать как Зло ™, и я не проверял его, но как насчет инициализации всех значений в массиве при выделении '\0' а затем с помощью strlen() ? Это даст вам ваш так называемый реальная стоимость так как он перестанет считать на первом '\0' это встречает.

Что ж, теперь, когда я думаю об этом, пожалуйста, никогда не делайте этого. Если только вы не захотите приземлиться в кучу грязной памяти.

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

2

Вы можете реализовать свой собственный new а также delete функции, а также дополнительный get-size функция:

#define CEIL_DIV(x,y) (((x)-1)/(y)+1)

void* my_new(int size)
{
if (size > 0)
{
int* ptr = new int[1+CEIL_DIV(size,sizeof(int))];
if (ptr)
{
ptr[0] = size;
return ptr+1;
}
}
return 0;
}

void my_delete(void* mem)
{
int* ptr = (int*)mem-1;
delete ptr;
}

int my_size(void* mem)
{
int* ptr = (int*)mem-1;
return ptr[0];
}

Кроме того, вы можете переопределить new а также delete операторы аналогичным образом.

2
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector