Подтвердить что ты не робот

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

При a 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");
4b9b3361

Ответ 1

Ты не можешь Во всяком случае, не со 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. Поэтому использование этого метода ненадежно, опасно и просто глупо. Не. Делать. Это.

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

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

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 type -> good habit

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

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

  • В С++:

Просто используйте 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);
}

Ответ 6

char * a = new char [10];

Мой вопрос: как я могу получить длину char *

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

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. Он имеет размер метода и длину его синонима, что позволяет в любой момент получить размер массива.

Например

std::string s( "aaaaa" );

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

или

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

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

Ответ 7

Вы можете реализовать свои собственные функции 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 аналогичным образом.

Ответ 8

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

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

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

Ответ 9

Итак, с оператором sizeof заключается в том, что он возвращает вам объем памяти, необходимый в байтах для хранения операнда.

Объем памяти, необходимый для хранения char, всегда 1 байт. Таким образом, sizeof(char) всегда будет возвращать 1.

char a[] = "aaaaa";

int len1 = sizeof(a)/sizeof(char); // length = 6
int len2 = sizeof(a);              // length = 6;

Это то же самое для len1 и len2, потому что это деление 1 не влияет на уравнение.

Причина, по которой обе len1 и len2 несут значение 6, связано с завершением строки char '\0'. Который также является char, который добавляет еще char к длине. Поэтому ваша длина будет 6 вместо 5, которые вы ожидали.

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

Вы уже упоминали, что длина получается здесь 4, что верно. Опять же, оператор sizeof возвращает сумму хранения для операнда, а в вашем случае это указатель a. Указатель требует 4 байта памяти, поэтому длина в этом случае равна 4. Так как вы, вероятно, скомпилируете его в 32-битный двоичный файл. Если вы создали 64-битный двоичный код, результат будет равен 8.

Это объяснение может быть здесь уже здесь. Просто хочу поделиться двумя центами.

Ответ 10

Вы можете сделать обратный трекер, например, вы могли бы добавить какой-либо специальный символ, скажем "%" в конец строки, а затем проверить появление этого символа.
Но это очень рискованный способ, поскольку этот символ может быть в других местах также в char *

char* stringVar = new char[4] ; 
stringVar[0] = 'H' ; 
stringVar[1] = 'E' ; 
stringVar[2] = '$' ; // back-tracker character.
int i = 0 ;
while(1)
{
   if (stringVar[i] == '$')
     break ; 
   i++ ; 
}
//  i is the length of the string.
// you need to make sure, that there is no other $ in the char* 

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

Ответ 11

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

Код проверки:

#include <stdio.h>
#include <stdlib.h>

int
main ()
{
    int arraySz;
    char *a;
    unsigned int *q;

    for (arraySz = 5; arraySz <= 64; arraySz++) {

        printf ("%02d - ", arraySz);

        a = new char[arraySz];
        unsigned char *p = (unsigned char *) a;

        q = (unsigned int *) (a - 4);
        printf ("%02d\n", (*q));

        delete[] (a);

    }
}

на моей машине выгружается:

05 - 19
06 - 19
07 - 19
08 - 19
09 - 19
10 - 19
11 - 19
12 - 19
13 - 27
14 - 27
15 - 27
16 - 27
17 - 27
18 - 27
19 - 27
20 - 27
21 - 35
22 - 35
23 - 35
24 - 35
25 - 35
26 - 35
27 - 35
28 - 35
29 - 43
30 - 43
31 - 43
32 - 43
33 - 43
34 - 43
35 - 43
36 - 43
37 - 51
38 - 51
39 - 51
40 - 51
41 - 51
42 - 51
43 - 51
44 - 51
45 - 59
46 - 59
47 - 59
48 - 59
49 - 59
50 - 59
51 - 59
52 - 59
53 - 67
54 - 67
55 - 67
56 - 67
57 - 67
58 - 67
59 - 67
60 - 67
61 - 75
62 - 75
63 - 75
64 - 75

Я бы не рекомендовал это решение (вектор лучше), но если вы действительно в отчаянии, вы можете найти связь и уметь заключить количество байтов, выделенных из кучи.

Ответ 12

Вы можете найти длину строки типа char * следующим образом:

char* mystring = "Hello World";
int length = sprintf(mystring, "%s", mystring);

sprintf() печатает mystring на себя и возвращает количество напечатанных символов.

Ответ 13

В C++17 (или новее) вы можете использовать std::string_view как оболочку с нулевыми накладными расходами для строковых литералов.

Ответ 14

Вы можете попробовать следующее:

int lengthChar(const char* chararray) {
   int n = 0;
   while(chararray[n] != '\0')
     n ++;
   return n;  
}

Ответ 15

Команда Strlen работает для меня. Вы можете попробовать следующий код.

//char * s

unsigned int  strLength=strlen(s);