如何得到实数和总长度的 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 *的长度

具体点说

  • 我怎样才能得到它真正的 length=5
  • 我怎样才能得到它的总 length=10

例如:

char *a = new char[10];
strcpy(a, "hello");
339746 次浏览

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

否则,就没有办法确定这些信息

您可以创建一个后向跟踪字符,例如,您可以在字符串的末尾附加任何特殊字符,比如“%”,然后检查该字符的出现情况。
但是这是一种非常危险的方式,因为字符可以在字符 * 中的其他位置

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*

否则,定义一个自定义结构来跟踪长度并分配内存。

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

注意: 这个答案只针对 C + + ,而不是 C。

Strlen 命令正在为我工作。您可以尝试以下代码。

//char * s

unsigned int  strLength=strlen(s);

只有两种方法:

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

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

你不能。至少不是100% 准确。指针 只有它自己的长度/大小。它所做的只是指向内存中保存字符的特定位置。如果这个字符是字符串的一部分,那么您可以使用 strlen来确定当前指向的字符之后是什么字符,但是这并不意味着在您的例子中 数组有那么大。
基本上:

指针不是 < em > array ,所以它不知道数组的大小。指针可以指向单个值,因此指针可以存在,甚至不需要数组。它甚至不在乎它所指向的内存位于何处(只读、堆或堆栈... ... 无关紧要)。指针只有指针本身的长度。一个指针就是..。
想想这个:

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

由于 size_t是一个无符号类型,如果 sizeof返回更大的值,那么 length的值可能是您意想不到的..。

Char * a = new char [10] ;

我的问题是如何得到一个字符的长度 *

它非常简单:)只添加一个语句就足够了

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

现在您可以得到分配的数组的大小

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

许多人在这里提到了 C 标准函数 std: : strlen。但它不返回字符数组的实际大小。它只返回存储的字符串文字的大小。

区别在于下面的.if 以您的代码片段为例

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

然后 std: : strlen (a)将返回5,而不是代码中的6。

所以结论很简单: 如果需要动态分配字符数组,请考虑使用 std::string类。它具有 method size 及其同义词长度,允许在任何时候获取数组的大小。

比如说

std::string s( "aaaaa" );


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

或者

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


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

您可以实现自己的 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操作符。

  • 在 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);
}

这可能听起来很邪恶,我还没有测试过,但是如何在分配给 '\0'的时候初始化数组中的所有值,然后使用 strlen()?这将给你你所谓的 真正的价值,因为它会停止计数的第一个 '\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

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

所以 大小操作符的问题在于它返回存储操作数所需的存储量(以字节为单位)。

存储一个 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'有关。这也是一个字符,增加了另一个字符的长度。因此你的长度是6而不是你期望的5。

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

您已经提到过,这里的长度是4,这是正确的。同样,大小操作符返回操作数的存储量,在您的示例中它是一个指针 a。指针需要4个字节的存储空间,因此在本例中指针的长度为4。因为您可能将其编译为32位二进制文件。如果您创建了一个64位的二进制文件,那么结果将是8。

这个解释可能在这里已经在这里。只是想分享我的两点意见。

你可以试试这个:

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

你可以找到字符串的长度如下:

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

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

合理的问题。我个人认为人们把指针和数组 作为字符指针(char *)的结果混淆了,后者的作用几乎与 字符数组(char _ _ [ X ])相同。这意味着指针和数组是不一样的,所以指针当然不包含特定的大小,如果我可以这样说的话,只包含一个地址。尽管如此,你还是可以尝试一些类似 Strlen 的东西。

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


return 0;
}