簡體   English   中英

如何獲取char *(char數組)的真實長度和總長度?

[英]How to get the real and total length of char * (char array)?

對於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");

你不能。 無論如何,不​​是 100% 准確。 指針沒有長度/大小,只有它自己的. 它所做的只是指向內存中保存字符的特定位置。 如果該字符是字符串的一部分,那么您可以使用strlen來確定當前指向的字符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_tsizeof的返回類型)分配給int ,最好寫:

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

由於size_t是無符號類型,如果sizeof返回更大的值,則length的值可能是您沒想到的......

如果char *以 0 結尾,則可以使用strlen

否則,無法確定該信息

只有兩種方式:

  • 如果您的char *指向的內存指針表示一個 C 字符串(即,它包含以 0 字節標記其結尾的字符),您可以使用strlen(a)

  • 否則,您需要將長度存儲在某處。 實際上,指針只指向一個char 但是我們可以把它當作指向數組的第一個元素來對待。 由於該數組的“長度”未知,因此您需要將該信息存儲在某處。

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

只給指針,你不能。 您必須保持傳遞給new[]的長度,或者更好地使用std::vector來跟蹤長度,並在完成后釋放內存。

注意:這個答案只針對 C++,而不是 C。

字符 *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 它有 methof size 和它的同義詞長度,允許隨時獲取數組的大小。

例如

std::string s( "aaaaa" );

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

或者

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

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

所以sizeof運算符的作用是返回存儲操作數所需的存儲量(以字節為單位)。

存儲字符所需的存儲量始終為 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,這是正確的。 同樣, sizeof運算符返回操作數的存儲量,在您的情況下,它是一個指針a 一個指針需要 4 個字節的存儲空間,因此在這種情況下長度為 4。 因為您可能將其編譯為 32 位二進制文​​件。 如果您創建了 64 位二進制文​​件,則結果將為 8。

這個解釋可能已經在這里了。 只想分享我的兩分錢。

您可以實現自己的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運算符。

這聽起來可能是 Evil™,我還沒有測試過,但是如何在分配到'\\0'初始化數組中的所有值,然后使用strlen()呢? 這將為您提供所謂的實際價值,因為它會在遇到的第一個'\\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* 

否則定義一個自定義結構來跟蹤長度並分配內存。

當 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

我不會推薦這個解決方案(向量更好),但如果你真的很絕望,你可以找到一個關系並能夠得出從堆分配的字節數。

C++17 (或更新版本)中,您可以使用std::string_view作為字符串文字的零開銷包裝器。

合法的問題。 我個人認為,由於字符指針 (char*) 的作用,人們將指針與數組混淆,它們的用途與字符數組 (char __[X])幾乎相同。 這意味着指針和數組是不一樣的,所以指針當然不包含特定的大小,如果我可以這么說,只包含一個地址。 但是,您仍然可以嘗試類似於 strlen 的東西。

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

    return 0;
}

您可以像這樣找到 char* 字符串的長度:

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

sprintf() 將 mystring 打印到自身上,並返回打印的字符數。

你可以試試這個:

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

Strlen 命令對我有用。 您可以嘗試以下代碼。

// 字符 *s

unsigned int  strLength=strlen(s);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM