Как можно преобразовать из строкового целого числа в 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
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
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

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