Почему элементы в моем массиве char * два байта вместо четырех? : - PullRequest
1 голос
/ 08 апреля 2011

Я новичок в C, так что прости меня, если этот вопрос тривиален.Я пытаюсь перевернуть строку, в моем случае это буквы a, b, c, d.Я помещаю символы в массив char * и объявляю буфер, который будет содержать символы в обратном порядке, d, c, b, a.Я достигаю этого результата, используя арифметику указателей, но, насколько я понимаю, каждый элемент в массиве char * составляет 4 байта, поэтому, когда я делаю следующее: buffer[i] = *(char**)letters + 4; Я должен указывать на второй элемент в массиве.Вместо того, чтобы указывать на второй элемент, он указывает на третий.После дальнейшего изучения я решил, что если я увеличу базовый указатель на два каждый раз, я получу желаемые результаты.Означает ли это, что каждый элемент в массиве составляет два байта вместо 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 ]

3 голосов
/ 08 апреля 2011

Вы не создаете массив символов: вы создаете массив символов strings - т.е. массив указателей на массивы символов.Я, конечно, не собираюсь переписывать всю программу для вас, но начну с двух альтернативных возможных правильных объявлений для вашей основной структуры данных:

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

char * letters = "abcd";

Любой из них объявляет массив из пяти символов: a, b, c, d, за которым следует 0, традиционное окончание строки символов в C.

2 голосов
/ 08 апреля 2011

Другое дело: вместо того, чтобы делать предположения о размере вещей, используйте язык, чтобы рассказать вам.Например:

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 указателей на символ, но не инициализирован.

На самом деле вы нигде не имеете дело с отдельными символамидаже в операторах 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");

}

Кстати, это домашняя работа?

0 голосов
/ 08 апреля 2011
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"
0 голосов
/ 08 апреля 2011

Это случай приоритета оператора.Когда вы используете buffer[i] = *(char**)letters + add;, * перед приведением выполняется перед +, что делает этот код эквивалентным (*(char**)letters) + add;.Первая часть эквивалентна адресу первого элемента вашего массива, строки «a».Поскольку использование строковой константы автоматически добавляет нулевой байт, это указывает на 'a\0'.Бывает, что компилятор помещает все четыре строки сразу после друг друга в память, поэтому, если вы пройдете конец этой строки, вы попадете в следующую.Когда вы добавляете к указателю, вы перемещаетесь через этот массив символов: 'a\0b\0c\0d\0'.Обратите внимание, что каждый символ занимает 2 байта после последнего.Так как это верно только потому, что компилятор поместил 4 строки непосредственно друг за другом, вы никогда не должны зависеть от этого (это даже не сработает, если вы попытаетесь перевернуть другую строку).Вместо этого вам нужно заключить в скобки, чтобы убедиться, что добавление происходит перед разыменованием, и использовать 4-байтовый размер указателя.(Конечно, как указал Николас, вы не должны принимать размер чего-либо. Вместо этого используйте sizeof, чтобы получить размер указателя.)

buffer[i] = *((char**)letters + add);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...