сталкиваюсь с проблемой написания собственного и my_itoa и моего atoi, которые должны изменить целое число на ascii и наоборот в C - PullRequest
0 голосов
/ 31 октября 2018

Я пропустил публикацию здесь, вы всегда многому меня учите!

Итак, у меня есть задание написать две собственные функции для перехода с целого числа на ASCII и обратно с ASCII на целое для встроенной системы, и они имеют очень специфические особенности:

вот предоставленные определения функций, на которых я должен основываться. он помещается в файл data.h:

#include <stdint.h>

uint8_t my_itoa(int32_t data, uint8_t * ptr, uint32_t base);

int32_t my_atoi(uint8_t * ptr, uint8_t digits, uint32_t base);

эти функции должны использоваться для базовых операций с данными, вот как эти функции будут использоваться в другом файле course1.c, который включает data.c:

digits = my_itoa( num, ptr, BASE_16);   
value = my_atoi( ptr, digits, BASE_16);  

и

digits = my_itoa( num, ptr, BASE_10);
value = my_atoi( ptr, digits, BASE_10);

Есть определенные функции, которые должны быть в обеих функциях:

  1. они должны поддерживать базу 2 вплоть до базы 16.
  2. Строковые функции или библиотеки не должны использоваться.
  3. Все операции должны выполняться с использованием арифметики указателей, а не индексации массивов.
  4. функция должна обрабатывать подписанные данные.

для my_itoa:

  1. Integer-to-ASCII должен преобразовывать данные из стандартного целочисленного типа в строку ASCII.
  2. Число, которое вы хотите преобразовать, передается как 32-разрядное целое число со знаком.
  3. Скопировать преобразованную символьную строку в указатель uint8_t *, переданный в качестве параметра (ptr)
  4. 32-разрядное число со знаком будет иметь максимальный размер строки (Подсказка: подумайте основание 2).
  5. Вы должны поместить нулевой терминатор в конец преобразованной c-строки
  6. Функция должна возвращать длину преобразованных данных (включая отрицательный знак). Пример my_itoa (ptr, 1234, 10) должен возвращать длину строки ASCII 5 (включая нулевой терминатор).

для my_atoi:

  1. ASCII-to-Integer необходимо преобразовать данные обратно из строки, представленной в ASCII, в целочисленный тип.
  2. Символьная строка для преобразования передается как указатель uint8_t * (ptr).
  3. Количество цифр в вашем наборе символов передается как целое число uint8_t (цифры).
  4. Должно быть возвращено преобразованное 32-разрядное целое число со знаком.

после моих исследований в этой теме: Написание собственной функции atoi

Мне удалось написать этот код, мои данные.c:

#include <stdlib.h>
#include <string.h>


int main(){

        return 0;
}


uint8_t my_itoa(int32_t data, uint8_t * ptr, uint32_t base)
{
        return *ptr;
};


int32_t my_atoi(uint8_t * ptr, uint8_t digits, uint32_t base)
{
        const char* str= ptr;
        uint8_t len = strlen(str);
        str = (uint8_t*) malloc(len * sizeof(uint8_t));

        while (*str != '\0')
        {
                uint8_t a;
                a = *str -'0';
                *ptr = a;
                str++;
                ptr++;
        }
        str = str - len;
        ptr = ptr -len;

        return *ptr;
};

как я понимаю, эта часть удаляет нулевой символ:

a = *str -'0';

у этого кода есть главная проблема: когда я компилирую его таким образом, я получаю в my_atoi указатель различий в sginedness и присваивания указателя разного в signed:

src/data.c: In function ‘my_atoi’:
src/data.c:20:19: error: pointer targets in initialization differ in 
signedness [-Werror=pointer-sign]
  const char* str= ptr;
                   ^~~
src/data.c:22:6: error: pointer targets in assignment differ in 
signedness [-Werror=pointer-sign]
  str = (uint8_t*) malloc(len * sizeof(uint8_t));
      ^

и когда я редактирую это так:

uint8_t len = strlen(str);

Я получаю ошибки, указывающие на то, что указатель target при передаче аргумента 1 в strlen отличается sigdness, а в определении string.h strlen ожидается постоянный символ *:

src/data.c: In function ‘my_atoi’:
src/data.c:21:19: error: pointer targets in passing argument 1 of 
‘strlen’ differ in signedness [-Werror=pointer-sign]
  int len = strlen(str);
                   ^~~
In file included from src/data.c:3:0:
/usr/include/string.h:384:15: note: expected ‘const char *’ but 
argument is of type ‘unsigned char *’
extern size_t strlen (const char *__s)
              ^~~~~~
src/data.c:22:6: error: pointer targets in assignment differ in 
signedness [-Werror=pointer-sign]
  str = (char*) malloc(len * sizeof(char));
      ^

а также тот факт, что мне нужно полностью избавиться от strlen и string.h. как здесь: Преобразование ASCII в Hex и наоборот - странная проблема , так что это было не очень полезно. На самом деле я не понимаю код внутри него.

Другая проблема связана с определением входной переменной для функции (3-й вход), которая должна быть BASE_10, BASE_16 или BASE_2 и т. Д., Как переменная:

uint32_t base

, который является int, сохраните это значение "BASE_10", чтобы сравнить его в условном условии if? и каковы основы преобразования в разные базы и как с ними обращаться?

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


РЕДАКТИРОВАТЬ, отредактировав этот код следующим образом:

uint8_t* str= ptr;
uint8_t len = strlen((const char *)str);

подписался на эту тему: приведение без знака char * (uint8_t *) к const char *

У меня сейчас нет ошибок, но все равно нужно полностью избавиться от string.h

1 Ответ

0 голосов
/ 01 ноября 2018

Что?

  str = (uint8_t*) malloc(len * sizeof(uint8_t));
  while (*str != '\0')

Этот my_atoi() код не имеет большого смысла. Код выделяет память, чье содержимое неизвестно - тогда сразу пытается их проверить?

Выделение памяти не требуется, а затем strlen() не нужно.

Символ в десятичном виде

«Я так понимаю, эта часть удаляет нулевой символ: a = *str -'0';» -> Не совсем. Когда *str является символом цифры, *str -'0' преобразует закодированное значение символа (обычно ASCII) в его числовое значение (например, от 0 до 9).

*str -'0' недостаточно для шестнадцатеричных цифр, таких как 'a' и 'F'.

Альтернативные

Вместо этого итерируйте по ptr и масштабируйте текущую сумму.

Приведенное ниже не соответствует двум целям кодирования, которые я оставляю для OP как подзадачи для обработки.

** Строковые функции или библиотеки не должны использоваться.
** функция должна обрабатывать подписанные данные.

.

#include <ctype.h>

// Convert 1 digit
static int value(int ch) {
  if (isdigit(ch)) {
    return ch - '0';
  }
  if (isxdigit(ch)) {
    ch = tolower(ch);
    const char *xdigits = "abcdef";
    return strchr(xdigits, ch) - xdigits  + 10;
  }
  return INT_MAX; // non-digit
}

int32_t my_atoi(uint8_t * ptr, uint8_t digits, uint32_t base) {
  int32_t sum = 0;
  while (*ptr) {
    sum *= base;
    sum += value(*ptr++);
  }
  return sum;
}

Более качественный код будет обнаруживать нечисловой ввод, переполнение, отсутствие преобразования и т. Д. Другие соображения, которые не показаны, включают обработку знака '-', проверку базы в диапазоне.

int32_t my_atoi(uint8_t * ptr, uint8_t digits, uint32_t base) {
  int32_t sum = 0;
  while (isspace(*ptr)) ptr++;  // skip leading white space
  if (*ptr == '+')  ptr++;      // Allow optional leading `+`
  bool digit_found = false;

  while (*ptr) {
    unsigned digit = value(*ptr++);
    if (digit >= base) {
      return INT_MIN; // TBD signal unexpected digit
    }
    if (sum >= INT_MAX/base && (sum > INT_MAX/base || digit > INT_MAX%base)) {
      // Overflow
      return INT_MIN; // TBD signal OF
    }
    sum *= base;
    sum += digit;
    digit_found = true;
  }

  if (*str) {
    sum = INT_MIN; // TBD signal unexpected junk at the end
  }
  if (!digit_found) {
    sum = INT_MIN; // TBD signal no digits
  }
  return sum;
}

my_itoa()

Чтобы получить справку по my_itoa(), просмотрите Как правильно реализовать хорошую функцию «itoa ()»? . Там есть хороший ответ - где-то.

...