简体   繁体   English

C样式字符串,指针,数组

[英]C style strings, Pointers, arrays

I'm having trouble understanding what a C-style string is. 我无法理解C风格的字符串是什么。 Happy early New Year 新年快乐

What I know: A pointer holds a memory address. 我所知道的:指针包含一个内存地址。 Dereferencing the pointer will give you the data at that memory location. 取消引用指针将为您提供该内存位置的数据。

int x = 50;
int* ptr = &x;    //pointer to an integer, holds memory address of x

cout << "&x: " << &x << endl;  //these two lines give the same output as expected
cout << "ptr: " << ptr << endl;

cout << "*ptr: " << dec << (*ptr) << endl;  //prints out decimal number 50
                                           //added dec, so the program doesnt 
                //continue to printout hexidecimal numbers like it did for the 
                 //the memory addresses above
cout << "&ptr: " << &ptr << endl;  //shows that a pointer, like any variable,
                                  //has its own memory address

Now to what I don't understand (using what's above as the source for my confusion): There are multiple ways to declare strings. 现在我不明白(使用上面的内容作为我的困惑的来源):有多种方式来声明字符串。 I'm learning C++, but you can also use C-style strings (good to understand, although inferior to C++ strings) 我正在学习C ++,但你也可以使用C风格的字符串(很好理解,虽然不如C ++字符串)

C++: C ++:

string intro = "Hello world!"; 
//the compiler will automatically add a null character, \0, so you don't have to
//worry about declaring an array and putting a line into it that is bigger than 
//it can hold. 

C-style: C-风格:

char version1[7] = {'H','i',' ','y','o','u','\0'};
char version2[] = "Hi you"; //using quotes, don't need null character? added for you?
char* version3 = "Hi you";

Version3 is where I'm having trouble. 版本3是我遇到麻烦的地方。 Here, there is a pointer to a char. 这里有一个指向char的指针。 I know that an array name is a pointer to the first element in an array. 我知道数组名是指向数组中第一个元素的指针。

cout << " &version3: " << &version3 << endl; //prints out location of 'H'
cout << " *version3: " << *version3 << endl; //prints out 'H'
cout << "  version3: " <<  version3 << endl; //prints out the whole string up to
                                             //automatically inserted \0

Before, in the section "what I knew," printing out the name of a pointer would print out the address that it held. 之前,在“我所知道的”部分中,打印出指针的名称会打印出它所持有的地址。 Here, printing out the name of a pointer prints out the whole string. 在这里,打印出指针的名称会打印出整个字符串。 Do the double quotes around "Hi you" somehow tell the program: "hey I know you are a pointer, and you are initialized to the location of 'H', but because I see these double quotes, skip forward 1 byte in memory location and printout everything you see until you reach a \\0" (1 byte movement because char's are 1 byte large). 围绕“嗨你”的双引号会以某种方式告诉程序:“嘿,我知道你是一个指针,你被初始化为'H'的位置,但因为我看到这些双引号,在内存位置向前跳过1个字节并打印出你看到的所有内容,直到达到\\ 0“(1字节移动,因为字符大1字节)。

How is it that printing out a pointer prints out a string? 如何打印出一个指针打印出一个字符串? Before printing out a pointer name printed out the memory address it was initialized to. 在打印出一个指针名称之前,打印出它被初始化为的内存地址。

Edit: Does cout << &version3 print out the location of 'H' or the location of the pointer, version3 , which holds the memory address of 'H'? 编辑: cout << &version3是否打印出'H'的位置或指针的位置, version3 ,其中包含内存地址'H'?

Printing out a char* with cout works differently from printing, say, an int* with cout . 使用cout打印char*工作方式与打印不同,例如,带有coutint* For compatibility with C-style strings, the overloaded version of << which takes a char* argument treats the char* as a C-style string. 为了与C风格的字符串兼容,带有char*参数的<<的重载版本将char*视为C风格的字符串。 If you want to print the memory address that a char* holds, you can cast it to a void* . 如果要打印char*所持有的内存地址,可以将其转换为void*

Yes, if you write either of 是的,如果你写任何一个

char *s1 = "hi lol";
char s2[] = "hi haha";

a NUL ( \\0 ) terminator is added for you at the end of the string. 在字符串的末尾为您添加NUL( \\0 )终结符。 The difference between these two is that s1 is a pointer to a string literal the contents of which you are not, according to the C standard, supposed to modify, whereas s2 is an array , that is, a block of memory allocated for you on the stack, which is initialized to hold the value "hi haha" , and you are free to modify its contents as you please. 这两者之间的区别在于s1是指向字符串文字的指针,根据C标准,您不应该修改内容,而s2是一个数组 ,即为您分配的内存块堆栈, 初始化为保存值"hi haha" ,您可以随意修改其内容。 The amount of memory allocated for the array is exactly enough to hold the string used as the initializer, and is determined for you automatically, which is why the square brackets can be empty. 为数组分配的内存量足以保存用作初始化程序的字符串,并自动为您确定,这就是方括号可以为空的原因。

One side note: in C, if you enter char s[3] = "abc"; 一面注意:在C中,如果输入char s[3] = "abc"; , then s will be initialized to {'a', 'b', 'c'} , without a NUL terminator! ,然后s将初始化为{'a', 'b', 'c'}没有 NUL终止符! This is because of a clause in the standard that says that strings in this context are initialized with a NUL terminator if there is room in the array (or some similar wording). 这是因为标准中的一个子句说如果数组中有空间 (或类似的措辞),则使用NUL终结符初始化此上下文中的字符串。 In C++ this is not the case. 在C ++中,情况并非如此。 For more, see No compiler error when fixed size char array is initialized without enough room for null terminator . 有关更多信息,请参阅初始化固定大小的char数组时没有编译器错误,但没有足够的空间用于null终止符

Edit, in response to your added question: If you have char *s = "..." , and you cout << &s; 编辑,以回应您添加的问题:如果您有char *s = "..." ,并且你cout << &s; , it will print the address where the pointer s is stored, rather than the address that s holds (the address of the first element of the string to which s refers). ,它将打印存储指针 s的地址,而不是s保存的地址( s引用的字符串的第一个元素的地址)。

I know that an array name is a pointer to the first element in an array. 我知道数组名是指向数组中第一个元素的指针。

No, it isn't. 不,不是。 It only gets converted into one implicitly (in most cases). 它只会隐式转换为一个(在大多数情况下)。

Do the double quotes around "Hi you" somehow tell the program: "hey I know you are a pointer, and you are initialized to the location of 'H', but because I see these double quotes, skip forward 1 byte in memory location and printout everything you see until you reach a \\0"? 围绕“嗨你”的双引号会以某种方式告诉程序:“嘿,我知道你是一个指针,你被初始化为'H'的位置,但因为我看到这些双引号,在内存位置向前跳过1个字节打印出你看到的一切,直到你达到\\ 0“?

No, they don't. 不,他们没有。 It's the type that matters. 这是重要的类型。

std::ostream::operator<< has an overload for a generic pointer ( void * ) and an overload for const char * . std::ostream::operator<<具有用于通用指针的过载( void *过载const char * So when you write cout << "some char array or pointer"; 所以当你写cout << "some char array or pointer"; , it will invoke that overload, and not the one for other pointer types. ,它将调用该重载,而不是其他指针类型的重载。 This overload behaves differently: instead of printing the numeric value of the pointer, it prints out everything until a NUL terminator. 这种重载的行为有所不同:它不是打印指针的数值,而是打印出所有内容,直到NUL终止符。

You are asking two questions here, one of which is more general and which I will answer first. 你在这里问两个问题,其中一个问题比较笼统,我将首先回答。

A pointer is a 'handle' (called an address) to a location in memory. 指针是指向内存中某个位置的“句柄”(称为地址)。 The contents of that location is a value. 该位置的内容是一个值。 How that value is interpreted is dependent on the 'type' of the pointer. 如何解释该值取决于指针的“类型”。 Think of it this way: an address is the location of a house, for example, 10 Main Street. 可以这样想:地址是房子的位置,例如10 Main Street。 The contents of 10 Main Street are the contents of the house at that address. 10 Main Street的内容是该地址的房子内容。 In C (and C++) terms: 在C(和C ++)术语中:

int *p;

Is a variable that can hold the address of an integer. 是一个可以保存整数地址的变量。

int x;

Is a variable that IS an integer. 是一个整数的变量。

p = &x;

Has p 'point to' x by storing in p the ADDRESS of x. 通过在p中存储x的ADDRESS,p'指向'x。

x = 10;

Stores in x the value 10. 在x中存储值10。

*p == x

Because *p says to 'use the contents of p' as a value and then compare it to x. 因为* p表示'使用p'的内容作为值,然后将其与x进行比较。

p == &x

Because &x says to 'use the address of x' as a value and then compare it to p, which is a variable of type pointer. 因为&x表示'使用x的地址'作为值,然后将其与p进行比较,p是类型指针的变量。

A string, which is a sequence of zero or more characters is represented in C (and C++) by the characters " and ". 字符串是零个或多个字符的序列,在C(和C ++)中用字符“和”表示。 In memory, these values are stored consecutively and are automatically terminated by a trailing null byte, which is a byte with the value 0. The string "Hello, world!" 在内存中,这些值是连续存储的,并由一个尾随的空字节自动终止,该字节是一个值为0的字节。字符串“Hello,world!” is stored in memory, assuming you are using an 8 bit ASCII character encoding, as: 假设您使用的是8位ASCII字符编码,则存储在内存中,如下所示:

65 101 108 108 111 44 32 87 111 114 108 33 0 65 101 108 108 111 44​​ 32 87 111 114 108 33 0

You can see this for yourself using the following code snippet: 您可以使用以下代码段自行查看:

char *p = "Hello, World!";
int len = strlen(p);
int i;

for (i = 0; i <= len;  ++i)
{
    std::cout << std::dec << (int) p[i] << ' ';
}
std::cout << std::endl;

Since the null (zero byte) is automatically added to a constant string by the compiler, the following two arrays are the same size: 由于null(零字节)由编译器自动添加到常量字符串,因此以下两个数组的大小相同:

char a1[7] = { 'H', 'i', ' ', 'y', 'o', 'u', '\0' };
char a2[] = "Hi you";

std::cout << strcmp(a1, a2) << std::endl

Simply put, a 'C style string' is simply an array of characters terminated by a null, which answers your first question. 简单地说,'C样式字符串'只是一个以null结尾的字符数组,它可以回答您的第一个问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM