开发者

Why are the elements in my char* array two bytes instead of four? :

I am new to C, so forgive me if this question is trivial. I am trying to reverse a string, in my case the letters a,b,c,d. I place the characters in a char* array, and declare a buffer which will hold the characters in the opposite order, d,c,b,a. I achieve this result using pointer arithmetic, but to my understanding each el开发者_如何转开发ement in a char* array is 4 bytes, so when I do the following: buffer[i] = *(char**)letters + 4; I am supposed to be pointing at the second element in the array. Instead of pointing to the second element, it points to the third. After further examination I figured that if I increment the base pointer by two each time I would get the desired results. Does this mean that each element in the array is two bytes instead of 4? Here is the rest of my code:

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

}


You're not making an array of characters: you're making an array of character strings -- i.e., an array of pointers to arrays of characters. I am not going to rewrite the whole program for you of course, but I'll start out with two alternative possible correct declarations for your main data structure:

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

char * letters = "abcd";

Either of these declares an array of five characters: a, b, c, d followed by 0, the traditional ending for a character string in C.


Another thing: rather than making assumptions about the size of things, use the language to tell you. For instance:

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

Another thing: understand your data structures (as noted above). You talk about chars, but your data structures are talking about strings. Your declarations:

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

get parsed as follows:

  • letters is an array of pointers to char (which happen to be nul-terminated C-style strings), and it's initialized with 4 elements.
  • Like letters, buffer is an array of 4 pointers to char, but uninitialized.

You are not actually dealing individual chars anywhere, even in the printf() statements: the %s specifier says the argument is a nul-terminated string. Rather, you're dealing with strings (aka pointers to char) and arrays of the same.

An easier way:

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

}

BTW, is this homework?


This is a case of operator precedence. When you use buffer[i] = *(char**)letters + add;, the * before the cast is performed before the +, making this code equivalent to (*(char**)letters) + add;. The first part is equivalent to the address of the first element in your array, the string "a". Since using string constant automatically adds a null byte, this points to 'a\0'. It happens that the compiler placed all four strings immediately after each other in memory, so if you go past the end of that string you flow into the next. When you add to the pointer, you are moving through this character array: 'a\0b\0c\0d\0'. Notice that each character is 2 bytes after the last. Since this is only true because the compiler placed the 4 strings directly after each other, you should never depend on it (it won't even work if you tried to re-reverse your other string). Instead, you need to put in parentheses to make sure the addition happens before the dereference, and use the 4 byte pointer size. (Of course, as pointed out by Nicholas, you shouldn't assume the size of anything. Use sizeof to get the size of a pointer instead.)

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


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

I think you didn't get the pointer arithmetic correctly. letters is an array of pointers and when incremented by 1 makes to go to next row.

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜