Является ли заполнение целочисленного массива таким же, как заполнение с плавающей точкой? - PullRequest
0 голосов
/ 04 мая 2018

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

самый простой способ заполнить целочисленный массив - использовать цикл for. Но будет ли это иначе для массива типа float?

будет ли это выглядеть примерно так? Или это неверно?

int size, i;
float items[size];
printf("How many items are you checking out today?");
scanf("%d", &size);
for(i=0;i<size;i++){
  printf("Enter the price of an item\n");
  scanf("%f", items[i]);
}

Я новичок в этом сайте, поэтому заранее спасибо

Ответы [ 3 ]

0 голосов

Я бы порекомендовал всегда инициализировать переменные, поскольку вы объявляете их, чтобы случайно не «мусорные» значения. Кроме того, я действительно не рекомендую предварительно объявлять ваши счетчики циклов. Вы видите это во многих старых кодах (раньше это требовалось из-за ограничений компилятора), но теперь я просто думаю, что это шум кода. Это будет выглядеть так:

for (int i = 0; i < size; i++) {
    // stuff
}

Кроме того, у вашего кода большая проблема. Вы используете так называемый массив переменного размера, и они не очень хорошая идея . Как правило, вы хотите объявить размер массива во время компиляции или динамически выделить пространство для массива, используя malloc.

Однако, возвращаясь к инициализации, вы должны установить каждый элемент в массиве, выделенном стеком, при объявлении:

#define SIZE 4

int main(void)
{
    float items[SIZE] = { 0 };
}

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

Чтобы ответить на ваш вопрос о заполнении массива, да, нет разницы в том, как вы на самом деле будете это делать. Цикл for работает просто отлично в обоих случаях. Просто не забудьте проверить возвращаемое значение scanf.

0 голосов
/ 04 мая 2018

Как было правильно указано, вы не можете объявить float items[size];, пока size не будет правильно инициализировано положительным целочисленным значением. Ваша попытка объявить items до size содержит значение вызывает неопределенное поведение из-за вашей попытки получить доступ к неинициализированному значению. (допустимая операция вашего кода на этом этапе закончена, и он может делать все, что угодно, начиная от правильной работы до StackOverflow или SegFaulting)

Каждый раз, когда вы принимаете пользовательский ввод, вы должны учитывать каждый символ, который остается во входном буфере (stdin здесь). Это особенно верно при приеме ввода с scanf (или семейством) из-за способа, которым scanf обрабатывает input или , соответствующие сбоям. В любом из этих случаев дальнейшие символы не читаются , а любые оскорбительные символы остаются непрочитанными во входном буфере - просто ожидая, что вас снова укусят при следующей попытке чтения (обычно это приводит к бесконечному циклу, если вы принимая входные данные в цикле)

(это одна из основных причин, по которой линейно-ориентированная функция , такая как fgets, рекомендуется для ввода данных пользователем)

scanf можно использовать, если используется правильно. Это означает, что вы несете ответственность за проверку возврата из scanf каждый раз . Вы должны справиться с тремя условиями

  1. (return == EOF) пользователь отменяет ввод, генерируя руководство EOF, нажимая Ctrl + d (или в windows Ctrl + z , но см. CTRL + Z не генерирует EOF в Windows 10 );
  2. (return == expected No. of conversions) указывает на успешное чтение - тогда вам нужно проверить, соответствует ли входные данные каким-либо дополнительным критериям (например, положительное целое число, положительная с плавающей точкой и т. Д.); и
  3. в противном случае вы должны обработать ошибку match или input , и вы должны учитывать каждый символ, который может остаться в вашем входном буфере. (обычно вы будете сканировать вперед во входном буфере до тех пор, пока не будет найден '\n' или EOF, отбрасывающий все оставшиеся посторонние символы)

Если вы делаете свою работу, вы можете успешно использовать scanf по мере необходимости.

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

Собрав вместе требования scanf, вы можете безопасно сделать что-то вроде следующего:

#include <stdio.h>

/* function to empty extraneous characters from stdin
 * (like the '\n' generated by pressing [Enter])
 */
void empty_stdin()
{
    int c = getchar();

    while (c != '\n' && c != EOF)
        c = getchar();
}

int main (void) {

    int size = 0, i;
    float total = 0.0;

    for (;;) {  /* loop continually until valid size entered */
        int rtn;
        printf ("How many items are you checking out today?: ");
        rtn = scanf ("%d", &size);
        if (rtn == EOF) {       /* handle EOF */
            fprintf (stderr, "(user canceled input)\n");
            return 1;
        }
        else if (rtn == 1 && size > 0) {    /* valid int received */
            empty_stdin();
            break;
        }   /* otherwise, handle error */
        fprintf (stderr, "error: invalid input.\n\n");
        empty_stdin (); /* remove any chars from stdin up to '\n' */
    }
    float items[size];  /* declare VLA of size floats */

    for (i = 0; i < size; i++) {
        items[i] = 0.0; /* initialize each (or memset VLA) */
        for (;;) {      /* loop continually until valid item price entered */
            int rtn;
            printf ("  price of item[%2d]: ", i + 1); /* prompt for price */
            rtn = scanf ("%f", &items[i]);
            if (rtn == EOF) {       /* handle EOF */
                fprintf (stderr, "(user canceled input)\n");
                return 1;
            }
            else if (rtn == 1 && items[i] > 0) { /* valid price received */
                empty_stdin();
                break;
            }   /* otherwise, handle error */
            fprintf (stderr, "error: invalid input.\n\n");
            empty_stdin (); /* remove any chars from stdin up to '\n' */
        }
        total += items[i];
    }
    printf ("\ntotal (%d items): $%.2f\n", size, total);
}

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

(показано с преднамеренными ошибками в записи)

$ ./bin/checkout
How many items are you checking out today?: what?
error: invalid input.

How many items are you checking out today?: 4
  price of item[ 1]: free?
error: invalid input.

  price of item[ 1]: 1.25
  price of item[ 2]: 3.50
  price of item[ 3]: discount?
error: invalid input.

  price of item[ 3]: 2.25
  price of item[ 4]: 3

total (4 items): $10.00

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

0 голосов
/ 04 мая 2018

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

#define MAX_SIZE (10)

int size=0, i=0; //It is always better to initialize the variables.
float items[MAX_SIZE] = {0.0f}; //Automatically the entire array will be initialized to zero.
printf("How many items are you checking out today?");
scanf("%d", &size);
if(size > MAX_SIZE)
    size = MAX_SIZE;

for(i=0;i<size;i++){
  printf("Enter the price of an item\n");
  scanf("%f", &items[i]); //You need to pass address of variable to scanf
}

Существуют и другие способы реализации вашего кода для обработки размера массива. Это один из способов.

...