为什么我的char *数组中的元素是两个字节而不是四个? :

时间:2011-04-08 18:10:27

标签: c

我是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");

}

4 个答案:

答案 0 :(得分:3)

你没有制作一个字符数组:你正在创建一个字符字符串的数组 - 即一个指向字符数组的指针数组。当然,我不打算为你重写整个程序,但我会从主数据结构的两个可能的正确声明开始:

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

char * letters = "abcd";

其中任何一个都声明一个包含五个字符的数组:a,b,c,d后跟0,即C中字符串的传统结尾。

答案 1 :(得分: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

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

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

解析如下:

  • letters是一个指向char的指针数组(恰好是以空字符结尾的C风格字符串),它用4个元素初始化。
  • letters类似,buffer是一个包含4个指向char但未初始化的数组的数组。

即使在printf()语句中,您实际上并没有在任何地方处理单个字符:%s说明符表示该参数是以空字符结尾的字符串。相反,你正在处理字符串(也就是指向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");

}
顺便说一下,这是家庭作业吗?

答案 2 :(得分:0)

这是运营商优先的情况。当您使用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);

答案 3 :(得分:0)

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"