LINUX.ORG.RU

C, простейшая задача


0

0

[корм для троллей] Лично меня уже достали тролли орущие, что дескать C++ - это говно с кучей никому не нужных костылей для быдлокодеров, а C (без плюсов) - это единственно правильный, очень простой в использовании язык, программы на котром всегда портируемы хоть куда. И вообще ниибаццо труЪ. [/корм для троллей]

Итак, задача: Напишите _функцию_, которая считывает со стандартного ввода число в переменную типа uint32_t (нужно именно 32хбитное беззнаковое целое) и возвращает его вызывающей стороне, если считываение удалось, либо сигнализирует вызывающей стороне об ошибке. Это всё =). Естественно, решение должно быть полностью совместимо с действующим стандартом на C и максимально коротким. Использование сторонних библиотек и нестандартных возможностей запрещено.

Чтобы не получилось недоразумения: мне нравится язык C++, но я не против других языков программирования и уважаю программистов которые на этих языках программируют. Просто задолбали тролли и быдлокрасноглазики... =)

P.S. Сейчас потихоньку изучаю common lisp.

Deleted

Просто интересно кто как решит. Всем решившим правильно - моё уважение =).

Deleted
()
Ответ на: комментарий от pierre

>> fread?

Нужно готовое решние - исходник функции.

Небольшое пояснение - на стандартный ввод число подаётся текстом и завершается переводом строки или EOF'ом, т.е. непример "12456\n".

Deleted
()
Ответ на: комментарий от Deleted

Да, ошибка, под конец недели не соображаю.

int read_uint32(uint32_t *rv) {
  unsigned x;
  if (scanf("%u", &x) != 1) {
    return 1;
  }
  if (x > (uint32_t) -1) {
    return 2;
  }
  *rv = (uint32_t) x;
  return 0;
}

Legioner ★★★★★
()

int foo(uint32_t *ip)
{
  char buf[sizeof(*p)*CHAR_BITS/3+3];
  if (fgets(buf, sizeof(buf), stdin))
  {
    char *cp = buf;
    for (*ip = 0; isdigit(*cp); ++cp)
    {
      *ip *= 10;
      *ip += *cp - '0';
    }
    if (*cp == '\n' || *cp == 0)
    {
      return 0;
    }
  }
  return -1;
}

dilmah ★★★★★
()
Ответ на: комментарий от Legioner

>> Если её два раза вызвать, на вводе "1 2", например, получится не совсем то.

Не только это.

Deleted
()

Я думаю, тесткейсы нужно такие сделать: - не число - меньше нуля (должна быть ошибка) - больше uint32_t (должна быть ошибка)

Думаю, функция должна получать указатель на uint32_t, а возвращать int. Причём, в случае ошибки, возможно, не портить число по адресу указателя.

Davidov ★★★★
()
Ответ на: комментарий от Deleted

int foo(uint32_t *ip)
{
  char buf[sizeof(*ip)*CHAR_BIT/3+3];
  if (fgets(buf, sizeof(buf), stdin))
  {
    char *cp = buf;
    for (*ip = 0; isdigit(*cp); ++cp)
    {
      if (*ip > UINT32_MAX/10)
      {
        break;
      }
      *ip *= 10;
      if (*ip > UINT32_MAX - (*cp - '0'))
      {
        break;
      }
      *ip += *cp - '0';
    }
    if (*cp == '\n' || *cp == 0)
    {
      return 0;
    }
  }
  return -1;
}

dilmah ★★★★★
()
Ответ на: комментарий от Davidov

> Думаю, функция должна получать указатель на uint32_t, а возвращать int.

имхо лучше возвращать тот же указатель, а в случае ошибки 0.

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

2dilmah: опять мимо, но уже немного ближе. и кстати можно сделать намного проще, без велосипедов.

Deleted
()
Ответ на: комментарий от Davidov

int foo(uint32_t *ip)
{
  char buf[sizeof(*ip)*CHAR_BIT/3+3];
  if (fgets(buf, sizeof(buf), stdin))
  {
    char *cp = buf;
    for (*ip = 0; isdigit(*cp); ++cp)
    {
      if (*ip > UINT32_MAX/10)
      {
        break;
      }
      *ip *= 10;
      if (*ip > UINT32_MAX - (*cp - '0'))
      {
        break;
      }
      *ip += *cp - '0';
    }
    if (*cp == '\n' || *cp == 0)
    {
      if (cp > buf)
      {
        return 0;
      }
    }
  }
  return -1;
}

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

>> long может быть 32-битным

Хммм... Ну и что?

Deleted
()
Ответ на: комментарий от pierre

>> В чем у него ошибка? На экзотических архитектурах не покатит?

У Legioner'а? Ну не на таких уж и экзотических...

Deleted
()
Ответ на: комментарий от Deleted

Может так?

int read_uint32(uint32_t *rv) {
  unsigned x;
  if (scanf("%u", &x) != 1) {
    return 1;
  };
  if (x > (uint32_t) -1) {
    return 2;
  };
  if (rv == NULL) {
    return 3;
  };
  *rv = (uint32_t) x;
  return 0;
}

pierre
()
Ответ на: комментарий от pierre

2pierre:

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

Deleted
()
Ответ на: комментарий от pierre

Финальный (надеюсь) вариант:

// C99 int read_uint32(uint32_t *rv) { unsigned long long x; // с запасом :-) if (scanf("%Lu", &x) != 1) { return 1; }; if (x > (uint32_t) -1) { return 2; }; if (rv == NULL) { return 3; }; *rv = (uint32_t) x; return 0; }

pierre
()
Ответ на: комментарий от pierre

Финальный (надеюсь) вариант:

// C99
int read_uint32(uint32_t *rv) {
  unsigned long long x; // с запасом :-)
  if (scanf("%Lu", &x) != 1) {
    return 1;
  };
  if (x > (uint32_t) -1) {
    return 2;
  };
  if (rv == NULL) {
    return 3;
  };
  *rv = (uint32_t) x;
  return 0;
}

pierre
()
Ответ на: комментарий от pierre

2pierre:

Правильнее ИМХО читать не unsigned long long, а uintmax_t ("%ju"). Но
поидее ваше решение правильное.

Вот решение на C++:

uint32_t readNum()
{
	uint32_t r;

	cin.exceptions(ios_base::badbit | ios_base::failbit);
	cin >> r;
	
	return r;
}

8)

Deleted
()
Ответ на: комментарий от anonymous

>> А чего там у нас с Itanium C++ ABI :?

А что с ним? Расскажите, возможно я что-то важное упустил из виду...

Deleted
()
Ответ на: комментарий от Deleted

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

капча busted намекает

anonymous
()
Ответ на: комментарий от anonymous

>> А вы озвучите, почему другие решения были неверными? :)

В последнем решении Legioner'а:

1) Никто не гарантирует, что uint32_t влезет в unsigned int. 2) Указатель может быть NULL (но это не сильно важно).

В последнем решении dilmah'а:

1) Вот тут помоему ошибко в вычислении максимального кол-ва символов: sizeof(*ip)*CHAR_BIT/3+3, так же fgets может прочитать из стандартного ввода больше/меньше чем нужно для полного считывания числа. 2) Указатель может быть NULL. 3) Число может начинаться с '+'.

Deleted
()
Ответ на: комментарий от anonymous

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

Как раз по этому в США C++ кодеры получают по $80/hr, а C - по $30/hr ;)

anonymous
()
Ответ на: комментарий от Deleted

гы, думал будет что-то более злобное, вроде "а вот вы обращаетесь по невыровненным адресам -- может повалится", или "а вот вы считаете, что char это 8 бит, а он может быть и 3 бита (стандарт это не запрещает), туда число не влезет", итп, итп

anonymous
()
Ответ на: комментарий от anonymous

>> гы, думал будет что-то более злобное, вроде "а вот вы обращаетесь по невыровненным адресам -- может повалится", или "а вот вы считаете, что char это 8 бит, а он может быть и 3 бита (стандарт это не запрещает), туда число не влезет", итп, итп

Ну если учитывать _ТАКОЕ_ то лучше просто убиться или перейти с C/C++ на Java =).

Deleted
()
Ответ на: комментарий от anonymous

>> ССЗБ.

Может подскажите хотя бы в каком направлении копать? А то как-то голословно. Я же указал на ошибки в C коде.

Deleted
()
Ответ на: комментарий от Deleted

>> Правильнее ИМХО читать не unsigned long long, а uintmax_t ("%ju").

Да, действительно, по спецификации C99 в формате printf/scanf нету "%Lu", но есть "%ju".

Deleted
()
Ответ на: комментарий от Deleted

> Хехе, не вижу =). На всех моих тестах работает нормально.

Нет, не работает. На строках типа "123xxxxx" радостно печатает выдает
123 вместо исключения.

Onanim
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.