如何获得char *(char数组)的实际长度和总长度?

时间:2014-01-09 14:15:21

标签: c++ c arrays 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");

16 个答案:

答案 0 :(得分:41)

你做不到。无论如何,不​​是100%准确。指针没有长度/大小,但是它自己的。它所做的只是指向内存中包含char的特定位置。如果该字符串是字符串的一部分,那么您可以使用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,它也会失败。所以使用这种方法是不可靠的,危险的,而且通常很愚蠢。别。做。它

另一个类比:
将指针视为道路标志,它指向 Town X 。标志不知道那个小镇是什么样的,它不知道或关心(或可以关心)住在那里的人。它的工作是告诉你在哪里找到 Town 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_tsizeof的返回类型)分配给int,最好写一下:

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

由于size_t是无符号类型,如果sizeof返回更大的值,length的值可能是您不期望的...

答案 1 :(得分:13)

如果char *以0结尾,您可以使用strlen

否则,无法确定该信息

答案 2 :(得分:4)

只有两种方式:

  • 如果char *指向的内存指针代表一个C字符串(也就是说,它包含用0字节标记其结尾的字符),则可以使用strlen(a)

  • 否则,您需要在某处存储长度。实际上,指针只指向一个 char。但我们可以把它看作是指向数组的第一个元素。由于该数组的“长度”未知,您需要将该信息存储在某处。

答案 3 :(得分:3)

只有指针,你不能。您必须保持传递给new[]的长度,或者更好的是,使用std::vector来跟踪长度,并在完成后释放内存。

注意:这个答案只涉及C ++,而不是C。

答案 4 :(得分: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);
}

答案 5 :(得分:2)

  

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。它具有methof大小及其同义词长度,可以随时获取数组的大小。

例如

std::string s( "aaaaa" );

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

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

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

答案 6 :(得分:2)

您可以实施自己的newdelete功能,以及其他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];
}

或者,您可以以类似的方式覆盖newdelete运算符。

答案 7 :(得分:2)

这可能听起来像Evil™,我还没有测试过,但是在分配到'\0'然后使用strlen()时,如何初始化数组中的所有值?这将为您提供所谓的实际值,因为它会在遇到的第一个'\0'时停止计数。

嗯,现在我想起来了,请不要这样做。除非,你想要陷入一堆肮脏的记忆。

此外,对于分配的内存或总内存,如果您的环境提供以下功能,您可以使用以下功能:

答案 8 :(得分:1)

所以 sizeof 运算符就是它返回存储操作数所需的存储量(以字节为单位)。

存储char所需的存储量始终为1个字节。因此sizeof(char)将始终返回1.

char a[] = "aaaaa";

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

len1len2的结果相同,因为1的除法不影响等式。

len1len2都带有值6的原因与字符串终止字符'\0'有关。这也是一个char,它增加了另一个char的长度。因此,你的长度将是6而不是你期望的5。

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

你已经提到过这里的长度是4,这是正确的。同样, sizeof 运算符返回操作数的存储量,在您的情况下,它是一个指针a。指针需要4个字节的存储空间,因此在这种情况下长度为4。因为您可能将其编译为32位二进制文​​件。如果您创建了64位二进制文​​件,则结果为8。

这个解释可能就在这里。只是想分享我的两分钱。

答案 9 :(得分:0)

你可以创建一个后卫跟踪角色,例如,你可以在你的字符串末尾附加任何特殊字符“%”,然后检查该字符的出现位置。
但这是一种非常危险的方式,因为该角色也可以在其他地方也在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* 

否则定义自定义结构以跟踪长度并分配内存。

答案 10 :(得分:0)

当new分配一个数组时,根据编译器(我使用gnu c ++),数组前面的单词包含有关分配的字节数的信息。

测试代码:

#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

我不推荐这个解决方案(向量更好),但如果你真的很绝望,你可以找到一个关系,并能够得出从堆中分配的字节数。

答案 11 :(得分:0)

您可以找到char *字符串的长度,如下所示:

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

sprintf()将mystring打印到自身上,并返回打印的字符数。

答案 12 :(得分:0)

C++17(或更高版本)中,您可以将std::string_view用作字符串文字的零开销包装。

答案 13 :(得分:0)

合法问题。我个人认为,由于字符指针(char *),人们将指针与数组混淆了,其作用与字符数组(char __ [X])几乎相同。这意味着指针和数组不相同,因此指针当然不包含特定的大小,如果可以的话,仅包含地址。但是,您仍然可以尝试类似于strlen的方法。

int ssize(const char* s)
{
    for (int i = 0; ; i++)
        if (s[i] == 0)
            return i;

    return 0;
}

答案 14 :(得分:-1)

你可以试试这个:

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

答案 15 :(得分:-3)

Strlen命令对我有用。您可以尝试以下代码。

// char * s

unsigned int  strLength=strlen(s);