【问题标题】:C style strings, Pointers, arraysC 风格的字符串、指针、数组
【发布时间】:2014-01-18 15:52:43
【问题描述】:

我无法理解 C 风格的字符串是什么。新年快乐

我知道的: 一个指针保存一个内存地址。取消引用指针将为您提供该内存位置的数据。

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

现在到我不明白的地方(使用上面的内容作为我困惑的根源): 有多种方法可以声明字符串。我正在学习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 风格:

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";

版本 3 是我遇到问题的地方。在这里,有一个指向 char 的指针。我知道数组名是指向数组中第一个元素的指针。

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

之前,在“我所知道的”部分中,打印出指针的名称将打印出它所持有的地址。在这里,打印出指针的名称会打印出整个字符串。 “嗨,你”周围的双引号以某种方式告诉程序:“嘿,我知道你是一个指针,你被初始化到'H'的位置,但是因为我看到这些双引号,所以在内存位置向前跳过1个字节并打印出您看到的所有内容,直到您到达 \0"(1 字节移动,因为 char 是 1 字节大)。

打印出指针如何打印出字符串?在打印出指针名称之前,打印出它被初始化的内存地址。

编辑:cout &lt;&lt; &amp;version3 是打印出“H”的位置还是指针的位置,version3,它保存着“H”的内存地址?

【问题讨论】:

  • "Happy early New Year" 里面的内容有点随意。大声笑
  • 我想说将 C 字符串称为“劣于”C++ 字符串有点强,尤其是考虑到一个(通常)是根据另一个实现的。
  • 我建议你的新年决心是在发布之前搜索 Web 和 StackOverflow!
  • 看看comp.lang.c FAQ,特别是第 4 节(指针)、第 6 节(数组和指针)和第 8 节(字符和字符串)。

标签: c++ c arrays string pointers


【解决方案1】:

cout 打印char* 与用cout 打印int* 的工作方式不同。为了与 C 风格的字符串兼容,采用 char* 参数的 &lt;&lt; 的重载版本将 char* 视为 C 风格的字符串。如果要打印char* 保存的内存地址,可以将其强制转换为void*

是的,如果你写任何一个

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

在字符串末尾为您添加了一个 NUL (\0) 终止符。这两者之间的区别在于,s1 是一个指向字符串文字的指针,根据 C 标准,您不能修改其内容,而 s2 是一个数组,也就是说,在堆栈上为您分配的一块内存,初始化以保存值"hi haha",您可以随意修改其内容。为数组分配的内存量正好足以容纳用作初始化器的字符串,并且会自动为您确定,这就是方括号可以为空的原因。

附注:在C语言中,如果你输入char s[3] = "abc";,那么s将被初始化为{'a', 'b', 'c'}没有一个NUL终止符!这是因为标准中的一个子句说,如果数组中有空间(或一些类似的措辞),则此上下文中的字符串使用 NUL 终止符初始化。在 C++ 中,情况并非如此。更多信息,请参阅No compiler error when fixed size char array is initialized without enough room for null terminator

编辑,回答您添加的问题:如果您有char *s = "...",而您有cout &lt;&lt; &amp;s;,它将打印指针 s 所在的地址存储,而不是 s 保存的地址(s 所指的字符串的第一个元素的地址)。

【讨论】:

    【解决方案2】:

    我知道数组名是指向数组中第一个元素的指针。

    不,不是。它只会隐式转换为一个(在大多数情况下)。

    “你好”周围的双引号以某种方式告诉程序:“嘿,我知道你是一个指针,并且你被初始化到'H'的位置,但是因为我看到这些双引号,向前跳过1个字节在内存位置并打印出您看到的所有内容,直到您到达 \0"?

    不,他们没有。 重要的是类型。

    std::ostream::operator&lt;&lt; 具有泛型指针 (void *) 的重载 const char * 的重载。因此,当您编写cout &lt;&lt; "some char array or pointer"; 时,它将调用该重载,而不是其他指针类型的重载。这个重载的行为不同:它不是打印指针的数值,而是打印出所有内容,直到出现 NUL 终止符。

    【讨论】:

      【解决方案3】:

      你在这里问了两个问题,其中一个比较笼统,我会先回答。

      指针是指向内存中某个位置的“句柄”(称为地址)。该位置的内容是一个值。该值的解释方式取决于指针的“类型”。可以这样想:地址是房子的位置,例如 10 Main Street。 10 Main Street 的内容是该地址的房屋的内容。用 C(和 C++)术语:

      int *p;
      

      是一个可以保存整数地址的变量。

      int x;
      

      是一个整数变量。

      p = &x;
      

      通过将 x 的地址存储在 p 中,使 p“指向”x。

      x = 10;
      

      将值 10 存储在 x 中。

      *p == x
      

      因为 *p 表示“使用 p 的内容”作为值,然后将其与 x 进行比较。

      p == &x
      

      因为 &x 说要把'x的地址'作为一个值,然后和p比较,p是指针类型的变量。

      一个字符串,它是零个或多个字符的序列,在 C(和 C++)中由字符“和”表示。在内存中,这些值是连续存储的,并由一个尾随空字节自动终止,这是一个值为 0 的字节。字符串“Hello, world!”存储在内存中,假设您使用的是 8 位 ASCII 字符编码,如:

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

      您可以使用以下代码 sn-p 自己查看:

      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;
      

      由于编译器会自动将null(零字节)添加到常量字符串中,因此以下两个数组的大小相同:

      char a1[7] = { 'H', 'i', ' ', 'y', 'o', 'u', '\0' };
      char a2[] = "Hi you";
      
      std::cout << strcmp(a1, a2) << std::endl
      

      简单地说,“C 风格字符串”只是一个以 null 结尾的字符数组,它回答了您的第一个问题。

      【讨论】:

        猜你喜欢
        • 2021-06-28
        • 1970-01-01
        • 1970-01-01
        • 2018-05-08
        • 1970-01-01
        • 2012-02-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多