программа for loop вылетает

Только начал с tinyduino(tinycircuits) и пытаюсь разработать игру про палача. У меня есть этот фрагмент кода, который случайным образом выбирает слово из моего массива. Я опустил часть кода для удобства чтения.

char* words[] = {"Fortran", "Cobol", "Python", "Java", "Javascript", "Kotlin", "Swift", "Golang", "Typescript"};
long word1;
char* generatedWord1;
int k;
int i;
int wordLength;

void setup(void) {
  randomSeed(analogRead(5));
  hangman();

void hangman(){
  word1 = random(sizeof(words)/sizeof(char*));
  k = 1;

  if (k == 1) {
    display.setCursor(10, 50);
    generatedWord1 = words[word1];

    for (i = 0; generatedWord1[i]; i++) {
      generatedWord1[i] = "_";
    }
}

Когда я загружаю это на плату, символы подчеркивания не отображаются в зависимости от длины случайно выбранного слова. Повторная загрузка не работает и после этого обычно требует перезагрузки tinyduino. Следовательно, я пришел к выводу, что мой код приводит к сбою. Но когда я заменяю generatedWord1[i] = "_"; в цикле for на display.print("_"); программа продолжает работу и печатает правильное количество знаков подчеркивания.

Однако это не соответствует моей цели замены букв символами подчеркивания, так как display.print("_"); вместо этого просто печатает символы подчеркивания на основе длины случайного слова. Мне нужно, чтобы это было таким образом, чтобы я мог сравнить ввод пользователя со случайным словом и заменить подчеркивание, если введенная буква соответствует любой букве в слове.

Что и как мне изменить в моем коде, чтобы он работал как таковой?

Примечание. В контексте всего этого скетча я пытаюсь использовать ввод данных от пользователя через bluetooth и сравнивать, соответствует ли ввод какой-либо из букв из случайного слова, а затем заменить подчеркивание вводом. письмо. Завершение слова означает победу в игре согласно палачу.

EDIT: я добавил весь скетч ниже для справки на тот случай, если я пропустил что-то важное для своего вопроса.

#include <SPI.h>
#include <STBLE.h>
#include <Wire.h>
#include <SPI.h>
#include <TinyScreen.h>
#include <string.h>

//Вывод отладки добавляет дополнительные требования к флэш-памяти и памяти!
#ifndef BLE_DEBUG
#define BLE_DEBUG true
#endif

#if defined (ARDUINO_ARCH_AVR)
#define SerialMonitorInterface Serial
#elif defined(ARDUINO_ARCH_SAMD)
#define SerialMonitorInterface SerialUSB
#endif


uint8_t ble_rx_buffer[21];
uint8_t ble_rx_buffer_len = 0;
uint8_t ble_connection_state = false;
#define PIPE_UART_OVER_BTLE_UART_TX_TX 0

TinyScreen display = TinyScreen(TinyScreenDefault);

// объявления
const char* words[] = {"Fortran", "Cobol", "Python", "Java", "Javascript", "Kotlin", "Swift", "Golang", "Typescript"};
long word1;
const char* generatedWord1;
int k;
int i;
int length;





void setup(void) {
  Serial.begin(9600);
  randomSeed(analogRead(5));
  BLEsetup();

  Wire.begin();
  display.begin();
  display.setBrightness(10);
  hangman();
}

void hangman(){
  display.clearScreen();
  display.setFont(thinPixel7_10ptFontInfo);
  display.setCursor(10,20);

  display.print("Ready to hang?");
  delay(2000);

  display.setCursor(5,20);
  display.print("generating word...");
  delay(1000);

  display.clearScreen();

  // слово1 — это мой индекс, поэтому вывод слова1 даст вам случайный индекс из массива
  word1 = random(sizeof(words)/sizeof(char*));
  k = 1;

  if (k == 1) {

    display.setCursor(10, 50);
    generatedWord1 = words[word1];

    length = strlen(generatedWord1);
    char user_input[length+1] = "";

    for (i=0; i < length; i++) {
      user_input[i] = "";
      user_input[length] = 0;
    }   

    display.setCursor(30, 30);
    display.print("|");
    
    display.setCursor(30, 20);
    display.print("|");

    display.setCursor(30, 10);
    display.print("|");

    display.setCursor(30, 0);
    display.print("____");

    // не забудьте убрать это из оператора if
    // Если пользователь угадывает неправильную букву (1)
    display.setCursor(50, 10);
    display.print("|");

    // Если пользователь угадывает неправильную букву (2)
    display.setCursor(49, 15);
    display.print("o");

    // Если пользователь угадывает неправильную букву (3)
    display.setCursor(50, 25);
    display.print("|");

    // Если пользователь угадывает неправильную букву (4)
    display.setCursor(43, 21);
    display.print("-");

    // Если пользователь угадывает неправильную букву (5)
    display.setCursor(54, 21);
    display.print("-");

    // ЕСЛИ пользователь угадал неправильную букву (6)
    display.setCursor(43, 30);
    display.print("/");

    // Если пользователь угадывает неправильную букву (7)
    display.setCursor(52, 30);
    display.print("\\"); 
  }

}


void displayScreen(char phone_input[21]) {

  display.clearScreen();

  int width=display.getPrintWidth(phone_input);
  display.setFont(thinPixel7_10ptFontInfo);
  display.setCursor(48-(width/2),32);
  display.fontColor(TS_8b_White,TS_8b_Black);
  display.print(phone_input);
}

void loop() {
  aci_loop();//Обрабатывать любые команды или события ACI от основного обработчика BLE NRF8001, должен выполняться часто. Держите основной цикл коротким.
  if (ble_rx_buffer_len) {//Проверить, доступны ли данные
    delay(10);
    displayScreen((char*)ble_rx_buffer);
    ble_rx_buffer_len = 0;//очистить после чтения
  }

}



, 👍2


1 ответ


Лучший ответ:

4

Забавно, я только что написал ответ о проблеме, которая у вас есть, около 45 минут назад. И проблема в том, что вы пытаетесь изменить строковый литерал. Это неопределенное поведение в C++.

Когда вы объявляете массив слов с помощью

char* words[] = {"Fortran", "Cobol", "Python", "Java", "Javascript", "Kotlin", "Swift", "Golang", "Typescript"};

фактически вы определяете массив указателей. Компилятор поместит эти строки в ОЗУ и поместит их адреса памяти в массив. Затем вы объявляете другой указатель char и устанавливаете его на одно из слов:

char* generatedWord1;
generatedWord1 = words[word1];

Теперь generatedWord1 также будет указывать на один из строковых литералов. А потом вы пытаетесь написать в этот строковый литерал:

generatedWord1[i] = "_";

Но, как уже упоминалось, строковые литералы не предназначены для изменения. Такая попытка приводит к неопределенному поведению, и да, это может привести к сбоям.

Что теперь делать? Вы можете определить массив char (не указателей char) в качестве буфера и заполнить его числом знаков подчеркивания, равных длине строкового литерала. При определении массива вы можете выбрать длину строкового литерала (плюс 1 для размещения нулевого символа) в качестве размера, хотя - в зависимости от потока вашей программы, который вы не показали - может быть лучше просто объявить буфер с фиксированный размер больше, чем самое длинное из ваших слов.

Вы можете получить длину строкового литерала с помощью функции strlen():

int length = strlen(generatedWord1);

Определение буфера char:

char user_input[length+1] = "";

Заполнение символами подчеркивания

for(int i=0;i<length;i++){
    user_input[i] = '_';
}
user_input[length] = 0; // завершающий нулевой символ

Я все еще не могу получить желаемый результат. Также он продолжает выдавать мне ошибку недопустимого преобразования из 'const char*' в 'char'.

Следующая часть неверна:

for (i=0; i < length; i++) {
    user_input[i] = "";
    user_input[length] = 0;
}   

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

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

Предупреждение, которое вы получаете от компилятора, также содержится в этой строке. Вы использовали двойные кавычки. Они отмечают строковый литерал. Но здесь мы назначаем один символ, поэтому вам нужно использовать одинарные кавычки, которые отмечают отдельные символы.

Сообщение недопустимое преобразование из const char* в char означает, что вы использовали строковый литерал (который является указателем на константный символ) и присвоили его односимвольной переменной (один элемент массив char).

,

Привет @chrisl, после того, как я опробовал предоставленный вами код, я все еще не могу получить желаемый результат. Также он продолжает выдавать мне ошибку `недопустимое преобразование из 'const char*' в 'char'`., @Isaac Agatep

Вы можете добавить новый код в конец вопроса. Тогда я посмотрю на это., @chrisl

@IsaacAgatep: 1. Код Крисла у меня работает. Если это не работает для вас, покажите нам, как вы интегрировали его в свою программу. 2. Сообщение «_недействительное преобразование_» является предупреждением, а не ошибкой. Вы можете исправить это, используя тип const char * (что означает: «указатель на неизменяемые символы») для всех указателей, предназначенных для указания на строковые литералы. В этой программе как words, так и generatedWord1 нуждаются в квалификаторе const., @Edgar Bonet

Здравствуйте @Edgar Bonet, я пробовал оба ваших предложения, но безрезультатно. Я добавил весь свой набросок внизу вопроса на тот случай, если я пропустил что-то важное, что может быть причиной моих ошибок., @Isaac Agatep

@IsaacAgatep Я добавил абзац в свой ответ, чтобы решить эту проблему., @chrisl

@chrisl большое спасибо за вашу помощь и объяснения. Я не могу с уверенностью сказать, что понимаю это, но теперь я найду время, чтобы переварить. Приму ваш ответ!, @Isaac Agatep

@IsaacAgatep Это может помочь сделать учебник по указателям, чтобы вы поняли, что означает * в этом коде., @chrisl