Как можно преобразовать из строкового целого числа в C?

Как можно преобразовать целые числа из строки в C?

Какой самый простой способ? Мне нужна программная функция, например:

fraction create_fraction_from_string(char *str)

Где я буду в основной функции вызова файла, например:

fraction create_fraction_from_string("-12/4") 

И результатом должно быть два целых числа:

int a = -12;
int b = 4;

Я думаю, что я разбиваю строку и после этого конвертирую эти две строки... Я новичок в программировании на C...

Обновлено:

Дроби это:

typedef struct { int a; int b; } fraction;

И ввод всегда будет в «x/y» или «-x/y»

И в результате должно получиться:

fraction res = { .a = -12, .b = 4 };

Вы уже знаете, как преобразовать "-12" в -12? Как прочитать «/» в char? Если сначала не узнать это. Если да, то с какой проблемой вы сталкиваетесь в связи с вашей текущей целью?

Yunnosch 20.11.2022 21:35

Что такое fraction? Это просто double? Или это (например) typedef struct { int a; int b; } fraction;? То есть из "-12/4" вы хотите, чтобы результат был: double res = -3.0; или вы хотите: fraction res = { .a = -12, .b = 4 };? Является ли ввод всегда в форме "x/y" или вы хотите, чтобы полный анализ уравнения (например) "-12/4*37.6+23"?

Craig Estey 20.11.2022 22:10

Отвечает ли это на ваш вопрос? Как преобразовать строку в целое число в C?

smabrar 21.11.2022 07:04

@SMSamnoonAbrar Кажется, это не то, что пользователь хочет знать, потому что он действительно хочет преобразовать строку в два целых числа.

Martin Rosenau 21.11.2022 07:58

Вы можете использовать функцию sscanf: sscanf(str, "%d/%d", &res.a, &res.b);

Martin Rosenau 21.11.2022 07:59

Стандартный подход: (1) прочитать всю строку с помощью fgets(), (2) проанализировать то, что вам нужно, из буфера с помощью sscanf(), как объясняет @MartinRosenau. (3) НЕ ЗАБУДЬТЕ проверить возврат ОБА fgets() и sscanf() и соответствующим образом обработайте любую ошибку.

David C. Rankin 21.11.2022 08:45
Как настроить Tailwind CSS с React.js и Next.js?
Как настроить Tailwind CSS с React.js и Next.js?
Tailwind CSS - единственный фреймворк, который, как я убедился, масштабируется в больших командах. Он легко настраивается, адаптируется к любому...
LeetCode запись решения 2536. Увеличение подматриц на единицу
LeetCode запись решения 2536. Увеличение подматриц на единицу
Увеличение подматриц на единицу - LeetCode
Переключение светлых/темных тем
Переключение светлых/темных тем
В Microsoft Training - Guided Project - Build a simple website with web pages, CSS files and JavaScript files, мы объясняем, как CSS можно...
Отношения "многие ко многим" в Laravel с методами присоединения и отсоединения
Отношения "многие ко многим" в Laravel с методами присоединения и отсоединения
Отношения "многие ко многим" в Laravel могут быть немного сложными, но с помощью Eloquent ORM и его моделей мы можем сделать это с легкостью. В этой...
В PHP
В PHP
В большой кодовой базе с множеством различных компонентов классы, функции и константы могут иметь одинаковые имена. Это может привести к путанице и...
Карта дорог Беладжар PHP Laravel
Карта дорог Беладжар PHP Laravel
Laravel - это PHP-фреймворк, разработанный для облегчения разработки веб-приложений. Laravel предоставляет различные функции, упрощающие разработку...
1
6
81
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Извлекая мудрость из комментариев, ваш основной подход к чтению любого ввода, где вам нужно проанализировать значения из того, что введено, заключается в следующем:

  1. прочитайте всю строку ввода в буфер достаточного размера, используя fgets(), не экономьте на размере буфера. Подтвердите возврат, чтобы убедиться, что у вас есть действительный ввод, и пользователь не отменил ввод, создав руководство EOF, нажав Ctrl + d (или Ctrl + z в Windows),
  2. проанализируйте значения, необходимые для ввода, используя sscanf(). Проверьте результат, чтобы убедиться, что каждое запрошенное преобразование выполнено успешно. В противном случае обработайте ошибку.

Что касается вашей функции create_fraction_from_string(), вам нужно изменить тип возвращаемого значения, чтобы возвращаемое значение могло указывать на то, были ли преобразования из ввода успешными или неудачными. Вы можете использовать bool для индикации true/false или просто использовать int с 0/1 для той же цели. Вы можете передать адрес fraction и обновить значения по адресу указателя внутри функции, и эти значения будут доступны обратно в вызывающем объекте.

Затем в вашем вызывающем объекте (main() здесь) подтвердите возврат от create_fraction_from_string(), прежде чем пытаться вывести значения. Вы можете избежать UB (неопределенного поведения), если попытаетесь вывести свою дробь, полностью инициализировав структуру во время объявления. Независимо от того, используете ли вы named-initialized, как показано ниже, или просто задаете значение для каждого члена, результат будет одинаковым.

В целом, вы можете сделать что-то похожее на:

#include <stdio.h>

#define FRACFMT "%d/%d"   /* if you need a constant, #define one (or more) */
#define FRACCNV      2

typedef struct { 
  int a, b; 
} fraction;

/* fill frac from str using sscanf (str, fmt, ...), validate nconv
 * conversions. Returns 1 on success, O otherwise.
 */
int create_fraction_from_string (fraction *frac, const char *str,
                                 const char *fmt, const int nconv)
{
  /* parse fmt from string into frac->a, frac->b, validate nconv */
  if (sscanf (str, fmt, &frac->a, &frac->b) != nconv) {
    return 0;   /* return failure */
  }
  
  return 1;     /* return success */
}

int main (void) {
                                  /* BUFSIZ 4096 on Linux, 512 on Windows */
  char line[BUFSIZ];              /* buffer to hold line of input */
  fraction frac = { .a = 0 };     /* fraction to hold result */
  
  fputs ("enter fraction (\"int/int\"): ", stdout);   /* prompt */
  
  if (!fgets (line, BUFSIZ, stdin)) {   /* read into buffer, validate */
    puts ("(user canceled input)");     /* handle manual EOF */
    return 0;
  }
  
  /* call create_fraction_from_string(), validate return */
  if (!create_fraction_from_string (&frac, line, FRACFMT, FRACCNV)) {
    fputs ("error: invalid input, must be \"int / int\".\n", stderr);
    return 1;
  }  
  
  /* output result */
  printf ("\nfrac.a : %d\nfrac.b : %d\n", frac.a, frac.b);
}

(примечание: вы, очевидно, должны проверить, что знаменатель не 0 в create_fraction_from_string() - это осталось за вами)

Пример использования/вывода

$ ./bin/readfraction
enter fraction ("int/int"): -12/4

frac.a : -12
frac.b : 4

Просмотрите вещи и дайте мне знать, если у вас есть вопросы.

В чем смысл nconv? Разве это не всегда должно быть 2?

klutt 21.11.2022 09:26

Поскольку строка формата была определена как макрос и передана как параметр для обобщения функции синтаксического анализа, например. в форме create_X_from_string() количество ожидаемых конверсий было передано, чтобы позволить проверке в функции сгенерировать либо успешный, либо неудачный возврат из функции. (Также позволяет избежать проблемы с MagicNumbers :)

David C. Rankin 21.11.2022 09:27

Да, это был мой второй вопрос. Какой смысл отправлять строку формата? Такое ощущение, что единственная реальная работа, которую содержит create_fraction_from_string, — это сообщение об ошибке.

klutt 21.11.2022 09:30

Да, это был мыслительный процесс. Мы могли бы либо жестко закодировать ее, либо написать функцию в общем виде, с помощью которого они могли бы моделировать другие функции create_X_from_string(). Я просто пошел с общим подходом.

David C. Rankin 21.11.2022 09:31

Если вам нужна общая функция, то сообщение об ошибке не должно быть конкретным, верно?

klutt 21.11.2022 09:34

Ну... В данном случае это была функция create_fraction_from_string, но вы правы - по двум причинам (1) ошибка должна быть выведена из вызывающего объекта, чтобы разделить интерфейс и реализацию, и да (2) это можно было бы передать как параметр, но я увидел в этом сокращающиеся преимущества с точки зрения обучения. Чтобы обработать ошибку в общем виде, функция может вернуться, например. -2, -1, 0 для 3 разных случаев ошибок — вы можете вывести правильную ошибку, выполнив поиск в вызывающем объекте. (но когда мы доходим до этого уровня - мы начинаем терять внимание ОП :)

David C. Rankin 21.11.2022 09:37

Да, я понимаю, что это была какая-то педагогическая причина. Тем не менее, я думаю, что это просто сделало вещи странными и трудными для понимания. Извините, если я звучу резко. Никаких обид. Если функция имеет это жестко закодированное сообщение об ошибке, это просто неправильно. И если вы также передадите сообщение об ошибке в качестве другого параметра, функция, по сути, будет просто довольно бесполезной оболочкой для sscanf, которая практически не добавляет никакой ценности.

klutt 21.11.2022 09:41

Если вы хотите сохранить код как есть, я могу добавить еще один ответ с более простым подходом.

klutt 21.11.2022 09:42

Что ж, поскольку существует только одна возможная ошибка (сбой сопоставления), в этом случае мы можем передать ее обратно вызывающей стороне. (где я бы предпочел, чтобы это было в любом случае) Рад вашим мыслям и обсуждениям - я всегда считал, что 4 глаза всегда лучше, чем два, и это приводит к лучшим примерам или коду.

David C. Rankin 21.11.2022 09:43

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

int create_fraction_from_string (fraction *frac, const char *str)
{
    const char *fmt = "%d/%d";

    return (sscanf (str, fmt, &frac->a, &frac->b) == 2);
}

Это вернет 1 в случае успеха и 0 в случае неудачи, поэтому вам нужно проверить, сработало ли преобразование, прежде чем использовать frac.

Мне нравится равенство в качестве возврата, но разве это не пришло из продвинутого класса? :)

David C. Rankin 21.11.2022 09:50

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

klutt 21.11.2022 09:56

Я просто немного поддразнил. Оба эквивалентны, один выписан, другой сделан сразу с равенством.

David C. Rankin 21.11.2022 10:21

@DavidC.Rankin Я понял поддразнивание, но это все еще был актуальный вопрос, который, как мне казалось, заслуживал серьезного ответа. :)

klutt 21.11.2022 10:22

Другие вопросы по теме