Арифметика указателя — подсчет точек

#c

#c

Вопрос:

Не удается заставить ни один из операторов if запускать и печатать что-либо в main. Я не понимаю, что делать дальше.

Не могли бы вы найти, где я ошибся в этой проблеме. Мне нужно подсчитать количество точек и тире (я упростил это, чтобы сначала работать с точками).

Вопрос должен быть решен с использованием арифметики указателей, и функция была предоставлена

 void analyse(char* code, int* p_dots, int* p_dashes);
  

^

 #include <stdio.h>
#include <string.h>

void analyse(char* code, int* p_dots)
{
char *current = code;
int k = 0;

if ((*current   k) == '.')
{
    p_dots  ;
    k  ;
}
if ((*current   k) == '-')
{
    //p_dashes  ;
    k  ;
}
if ((*current   k) ==' ')
{
    //p_dashes  ;
    k  ;
}
}

int main(void)
{
char* morse[] =
{
    "... --- ..."                           // SOS
//  "-- --- .-. ... .",                     // MORSE
//  "-.-. --- -.. .",                       // CODE
//  "-.-. --- -- .--. ..... ----- -----",   // COMP500
//  ". -. ... . ..... ----- .----"          // ENSE501
};

char* code = *morse;
int*p_dots=0;
//int*p_dashes = 0;

analyse(code, p_dots);

printf("Line 1 has %d dots", *p_dots);

return 0;
}
  

Комментарии:

1. Вы в курсе *current k (*current) k , не *(current k) так ли?

2. Нет, я видел кое-что об этом на слайдах лекции и не был уверен, что это значит.

3. Использование [] -operator является самым простым (и при этом безопасным) подходом для доступа к элементу массива.

4. не используйте k ни current то, ни другое, просто сделайте *code

5. «Арифметика указателей» — это нечто другое — это не означает «считать с помощью указателя». И если есть ограничения на то, что вы можете сделать, пожалуйста, укажите это в вопросе.

Ответ №1:

Вот другой подход:

 #include <stdio.h>

void analyse(char *code, int *p_dots, int *p_dashes)
  {
  for( ; *code ;   code)
    {
    if (*code == '.')
      *p_dots  = 1;

    if (*code == '-')
      *p_dashes  = 1;
    }
  }

int main(void)
  {
  int dots;
  int dashes;
  char *morse[] =
    {
    "... --- ...",                          // SOS
    "-- --- .-. ... .",                     // MORSE
    "-.-. --- -.. .",                       // CODE
    "-.-. --- -- .--. ..... ----- -----",   // COMP500
    ". -. ... . ..... ----- .----"          // ENSE501
    };

  for(int i = 0 ; i < sizeof(morse) / sizeof(char *) ;   i)
    {
    dots = 0;
    dashes = 0;

    analyse(morse[i], amp;dots, amp;dashes);

    printf("Line %d ('%s') has %d dots and %d dashesn", i, morse[i], dots, dashes);
    }

  return 0;
  }
  

Указатель — это переменная, которая содержит адрес чего-либо. Используя указатель, вы можете посмотреть и / или изменить то, на что он указывает. Если вы увеличиваете указатель, вы меняете адрес в указателе, и, таким образом, вы меняете то, на что он указывает.

В этом коде вся арифметика указателей выполняется в for цикле for( ; *code ; code) в analyse функции. Здесь мы говорим о том, что А) нет раздела инициализации (перед первым ; в инструкции нет кода for ); Б) мы хотим продолжать до тех пор, пока то, что указано на code указатель, не равно нулю *code в «тестовой» части for инструкции; и В)после каждого прохождения цикла мы хотим увеличивать code указатель ( code в разделе «increment» for инструкции).

Если бы вы хотели, вы могли бы заменить for цикл на analyse :

 while(*code <> 0)
  {
  if (*code == '.')
    *p_dots  = 1;

  if (*code == '-')
    *p_dashes  = 1;

  code  = 1;
  }
  

При просмотре подобного кода я считаю полезным мысленно произносить «объект указателя» всякий раз, когда я вижу звездочку, используемую с переменной указателя, поэтому я бы прочитал первую строку приведенного выше кода как

 While object of pointer "code" is not equal to zero...
  

затем следующие строки читаются как

 if object of pointer "code" is equal to the character "period"
  then add one to object of pointer "p_dots"

if object of pointer "code" is equal to the character "dash"
  then add one to object of pointer "p_dashes"

add one to the variable "code"
  

Вместо «объекта указателя», возможно, вы могли бы прочитать его как «цель указателя», чтобы напомнить себе, что указатель указывает на что-то, и вы манипулируете тем, на что указывает указатель, или, другими словами, вы манипулируете указателями «target».

Я считаю, что подобные вещи помогают мне немного лучше понимать код на основе указателей. Возможно, это вам тоже поможет.

Комментарии:

1. Спасибо, это немного прояснило ситуацию. Но теперь я не уверен, как мне включить строки, которые я закомментировал. Поскольку указатель увеличивается, как я смогу заставить его остановиться в конце строки и снова перезапустить счетчик?

2. В сторону: sizeof(morse) / sizeof(char *) —> sizeof morse / sizeof morse[0] менее хрупкий.

3. @UltraInstinctMessi — вы должны сделать то, что я сделал в моем примере кода — вы увеличиваете указатель только после того, как выполнили все необходимые тесты для каждого отдельного символа.

4. @UltraInstinctMessi — Я добавил немного больше объяснений того, как я читаю код, который использует указатели и манипулирует ими. Возможно, это поможет.

Ответ №2:

Измените все вхождения этого:

 (*current   k) == '-'  
  

к этому:

 *(current   k) == '-'  
  

(что означает то же самое, что и следующее:)

 current[k] = '-'  
  

Также в main() вашем коде необходимо обновить значение an int , поэтому просто создайте обычный int , а затем передайте его адрес:

 int p_dots = 0;
...  
analyse(code, amp;p_dots);//sends the address so the value can be updated
  

Кроме того, для правильного суммирования всех значений в функции void analyse(char* code, int* p_dots) analyze необходим цикл while: ниже приведен ваш код с циклом while и некоторыми упрощениями: (он только отслеживает p_dots )

 void analyse(char* code, int* p_dots)
{
    char *current = code;
    int k = 0;

    while(*current)//check for NULL character
    {
        if (*current == '.')
        {
            (*p_dots)  ;
        }
        if (*current  == '-')
        {
            k  ;
        }
        if (*current ==' ')
        {
            k  ;
        }
        current  ; //increment pointer to next position
    }
}
  

Кстати, один из способов отслеживать каждый из символов ( . , - . ) — это создать структуру, а затем передать ее адрес для обновления значений элементов. Пример кода для этого приведен ниже:

 typedef struct {
    int dot;
    int dash;
    int space;
} count_s;

void analyse(char* code, count_s *c)//new prototype to track `.`, `-` and ` `
{
    char *current = code;
    int k = 0;

    while(*current)
    {
        if (*current == '.')
        {
            (*c).dot  ;
        }
        if (*current  == '-')
        {
            (*c).dash  ;
        }
        if (*current ==' ')
        {
            (*c).space  ;
        }
        current  ;
    }
}

int main(void)
{
    char* morse[] =
    {
        "... --- ..."                           // SOS
    //  "-- --- .-. ... .",                     // MORSE
    //  "-.-. --- -.. .",                       // CODE
    //  "-.-. --- -- .--. ..... ----- -----",   // COMP500
    //  ". -. ... . ..... ----- .----"          // ENSE501
    };

    char* code = *morse;
    //int p_dots;
    count_s count;
    //int*p_dashes = 0;

    analyse(code, amp;count);

    printf("Line 1 has %d dotsn", count.dot);
    printf("Line 1 has %d dashesn", count.dash);
    printf("Line 1 has %d spacesn", count.space);

    return 0;
}
  

ОТРЕДАКТИРУЙТЕ, чтобы ответить на вопрос в комментариях: Как бы мне сделать это для следующих строк, которые я закомментировал?

Создайте массив строковых литералов

  const char *morse[] = {{"... --- ..."},
                   {"-- --- .-. ... ."},
                   {"-.-. --- -.. ."},
                   {"-.-. --- -- .--. ..... ----- -----"},
                   {". -. ... . ..... ----- .----"}};
  

Новое main()

 int main(void)
{
    char* code = NULL;//will be used to point to each array line.
    count_s count = {0};//instance of struct with accumulators

    // place declaration of const char *morse[] here as illustrated above

    for(int i=0;i<sizeof(morse)/sizeof(morse[0]);i  )
    {
        code = morse[i];//set pointer to successive array elements 0-4
        analyse(code, amp;count);//count will accumulate values as loop progresses.
    }

    printf(" %d dotsn", count.dot);
    printf(" %d dashesn", count.dash);
    printf(" %d spacesn", count.space);

    return 0;
}
  

Комментарии:

1. Как бы мне сделать это для следующих строк, которые я закомментировал?

2. Сохраните его в виде массива строковых литералов (который у вас есть) или 2D-массива (любой из них будет работать), затем выполните цикл по каждой строке массива. (См. Редактирование и создание main с помощью цикла, прочитайте комментарии для получения разъяснений того, что происходит.)

Ответ №3:

У вас возникли проблемы с приращением точек и сканированием строки, см. p_dots Обновление в main. Я меняю p_dots значение на int, чтобы оно было в стеке (я думаю, его следует переименовать). В вашем коде вам нужно выделить немного памяти.

Для сканирования строки: просто увеличьте указатель для чтения символа за символом в бесконечном цикле, используйте переключатель для будущего сканирования ‘-‘, остановитесь на нулевом символе.

code указывает на начало строки, switch (*code ) считывает текущий символ и перемещает указатель на следующий.

Начать:

 "... --- ..." 
 ^
 code
  

Считывание . и перемещение кода

 "... --- ..." 
  ^
  code
  

и так далее

 #include <stdio.h>
#include <string.h>

void analyse(char* code, int* p_dots)
{
    while (42) {
        switch (*code  ) {
          case '.':
            (*p_dots)  ;
            break;
          case '-':
            break;
          case '':
            return;
          default:
            break;
        }
    }
}

int main(void)
{
    char* morse[] =
    {
        "... --- ..."                           // SOS
            //  "-- --- .-. ... .",                     // MORSE
            //  "-.-. --- -.. .",                       // CODE
            //  "-.-. --- -- .--. ..... ----- -----",   // COMP500
            //  ". -. ... . ..... ----- .----"          // ENSE501
    };

    char* code = *morse;
    int p_dots=0;
    //int*p_dashes = 0;

    analyse(code, amp;p_dots);

    printf("Line 1 has %d dotsn", p_dots);

    return 0;
}
  

Комментарии:

1. Вопрос заключается в том, чтобы конкретно использовать арифметику указателей. Весь этот указатель проходит у меня над головой =

2. Хорошо, я добавлю больше деталей

3. Спасибо, весь этот указатель был удален. Потратил на это дни и просто не могу понять … все еще есть qsort, bsearch, побитовые и двоичные файлы для покрытия..