【问题标题】:Why are the elements in my char* array two bytes instead of four? :为什么我的 char* 数组中的元素是两个字节而不是四个? :
【发布时间】:2026-02-18 20:35:01
【问题描述】:

我是 C 的新手,如果这个问题是微不足道的,请原谅我。我正在尝试反转一个字符串,在 我的情况是字母a,b,c,d。我将字符放在 char* 数组中,并声明一个缓冲区 它将以相反的顺序保存字符,d,c,b,a。我使用 指针算法,但据我了解,char* 数组中的每个元素都是 4 个字节,所以当我执行以下操作时:buffer[i] = *(char**)letters + 4; 我应该指向 数组中的第二个元素。它不是指向第二个元素,而是指向第三个元素。经过进一步检查,我发现如果我将基指针增加 2 每次我都会得到想要的结果。这是否意味着数组中的每个元素 是两个字节而不是 4?这是我的其余代码:

#include <stdio.h>

int main(void)
{

  char *letters[] = {"a","b","c","d"};
  char *buffer[4];
  int i, add = 6;

  for( i = 0 ; i < 4 ; i++ )
  {
    buffer[i] = *(char**)letters + add;
    add -= 2;
  }

  printf("The alphabet: ");

  for(i = 0; i < 4; i++)
  {
    printf("%s",letters[i]);
  }

  printf("\n");

  printf("The alphabet in reverse: ");

  for(i = 0; i < 4; i++)
  {
    printf("%s",buffer[i]);
  }

  printf("\n");

}

【问题讨论】:

    标签: c


    【解决方案1】:

    你不是在创建一个字符数组:你是在创建一个字符数组strings——即一个指向字符数组的指针数组。当然,我不会为您重写整个程序,但我将从您的主要数据结构的两种可能的正确声明开始:

    char letters[] = {'a','b','c','d, 0};
    
    char * letters = "abcd";
    

    其中任何一个都声明了一个由五个字符组成的数组:a、b、c、d,后跟 0,这是 C 中字符串的传统结尾。

    【讨论】:

    • 我想他知道。这就是为什么它是 char* 数组而不是 char 数组的原因,也是为什么他希望每个是 4 个字节,而不是 1 个。
    • 这个答案有一个严重的错误,加上典型的C新手的误解,是相当有害的。 char *letters[]; 不是字符串数组。它是一个指向字符串的指针数组。 char * 不是字符串。它是一个可以指向字符串开头的指针。 string 是一个 array 类型 对象。
    • @R:你说得对,我的措辞很糟糕,尽管我不确定我会称之为“严重”还是“有害”。我已经澄清了我的帖子。
    【解决方案2】:

    另一件事:不要对事物的大小做出假设,而是用语言告诉你。例如:

    char   *my_array[]            = { "foo" , "bar" , "baz" , "bat" , } ;
    // the size of an element of my_array
    size_t  my_array_element_size = sizeof(my_array[0]) ;
    size_t  alt_element_size      = size(*my_array) ; // arrays are pointers under the hood
    // the number of elements in my_array
    size_t  my_array_element_cnt  = sizeof(my_array) / sizeof(*myarray ;
    // the size of a char
    size_t  char_size             = sizeof(*(my_array[0])) ; // size of a char
    

    另一件事:了解您的数据结构(如上所述)。您谈论的是字符,但您的数据结构是在谈论 strings。您的声明:

    char *letters[] = {"a","b","c","d"};
    char *buffer[4];
    

    得到如下解析:

    • letters 是一个指向 char 的指针数组(恰好是以 nul 结尾的 C 风格字符串),它被初始化为 4 个元素。
    • letters 一样,buffer 是一个由 4 个指向 char 的指针组成的数组,但未初始化。

    您实际上并没有在任何地方处理单个字符,即使在 printf() 语句中:%s 说明符表示该参数是一个以 nul 结尾的字符串。相反,您正在处理字符串(也就是指向 char 的指针)和相同的数组。

    更简单的方法:

    #include <stdio.h>
    
    int main(void)
    {
    
      char   *letters[]  = { "a" , "b" , "c" , "d" , }    ;
      size_t  letter_cnt = size(letters)/sizeof(*letters) ;
      char   *buffer[sizeof(letters)/sizeof(*letters)]    ;
    
      for ( int i=0 , j=letter_cnt ; i < letter_cnt ; ++i )
      {
        buffer[--j] = letters[i] ;
      }
    
      printf("The alphabet: ");
      for( int i = 0 ; i < letter_cnt ; ++i )
      {
        printf("%s",letters[i]);
      }
      printf("\n");
    
      printf("The alphabet in reverse: ");
      for( int i=0 ; i < letter_cnt ; i++ )
      {
        printf("%s",buffer[i]);
      }
      printf("\n");
    
    }
    

    顺便说一句,这是作业吗?

    【讨论】:

    • 不,这不是家庭作业,只是为了我自己的消遣。我知道如何使用汇编器处理指针等,但是在汇编器中本身没有数据类型,你使用原始字节。所以 C,特别是这个例子,似乎是一个很好的起点。
    • 如果你是一名汇编程序员,你会喜欢 C。你可以称它为干净、抽象的汇编语言 —没有 [大部分] 通常与汇编程序相关的头痛。祝你好运!
    【解决方案3】:

    这是运算符优先级的情况。当您使用buffer[i] = *(char**)letters + add; 时,转换前的*+ 之前执行,使此代码等效于(*(char**)letters) + add;。第一部分相当于数组中第一个元素的地址,即字符串“a”。由于使用字符串常量会自动添加一个空字节,这指向'a\0'。碰巧编译器将所有四个字符串紧挨着放在内存中,所以如果你越过那个字符串的末尾,你就会进入下一个。当您添加到指针时,您将在此字符数组中移动:'a\0b\0c\0d\0'。请注意,每个字符在最后一个字符之后是 2 个字节。因为这只是因为编译器将 4 个字符串直接放在彼此之后,所以你永远不应该依赖它(如果你试图重新反转你的另一个字符串,它甚至不会工作)。相反,您需要放入括号以确保添加发生在取消引用之前,并使用 4 字节指针大小。 (当然,正如 Nicholas 所指出的,你不应该假设任何东西的大小。使用 sizeof 来获取指针的大小。)

    buffer[i] = *((char**)letters + add);
    

    【讨论】:

      【解决方案4】:
      char *letters[] = {"a","b","c","d"};
      

      我认为你没有正确地得到指针算法。 letters 是一个指针数组,当递增 1 时会转到下一行。

      letters + 1 ; // Go to starting location of 2 row, i.e., &"b"
      

      char *letters[] = { "abc" , "def" } ;
      
      (letters + 1) ; // Point to the second row's first element, i.e., &"d"
      
      *((*letters) + 1) ;  // Get the second element of the first row. i.e., "b"
      

      【讨论】:

        最近更新 更多