Игра на месте разницы - PullRequest
       7

Игра на месте разницы

1 голос
/ 09 февраля 2020

У меня есть три массива, все из которых в основном одинаковы для начала. Все они начинаются с 50 записей, и все они являются целочисленными массивами. Одна из них, однако, сразу же заполняется большими значениями, а две другие начинаются с обычного 0,0,0, ... Чем этот массив выделяется среди остальных? Следуя предложению предоставить минимальный пример, я разместил один ниже. Вероятно, это может быть уменьшено и дальше, но я оставил все операторы печати только для того, чтобы объяснить, что это гейзенбаг. Действительно, если я удаляю больше строк, проблема может просто не появиться, и я хочу убедиться, что она появляется, чтобы ее можно было отменить.

  int main() {
   int assignments;
   int i; /*for loop index for both loops*/
   int days_late[50], scores[50], weights[50];
   scanf(" %d",&assignments);
   /*assigns assignment data from input to days_late, scores, weights*/
   for(i=0; i<assignments; i++){
     int index;
     printf(" Index scanned: %d",scanf(" %d",&index));
     printf(" Index is: %d",index);
     printf("\nScore just added is %d",scores[index]);
     printf("\nWeight just added is %d",weights[index]);
     printf("\nLateness just added is %d",days_late[index]);
     printf("\nIndex is %d",index);
     printf(" Variables scanned: %d",scanf(" %d%d%d",&scores[index],&weights[index],&days_late[index]));
     printf("\nScore just added is %d",scores[index]);
     printf("\nWeight just added is %d",weights[index]);
     printf("\nLateness just added is %d",days_late[index]);
   }
/*anything past this point is not neccessary, the error has already occurred*/
}

Вывод:

Index scanned: 1 Index is: 2
Score just added is -1793035504
Weight just added is 0
Lateness just added is 0
Index is 2 Variables scanned: 0
Score just added is -1793035504
Weight just added is 0
Lateness just added is 0 Index scanned: 0 Index is: 2
Score just added is -1793035504
Weight just added is 0
Lateness just added is 0
Index is 2 Variables scanned: 0
Score just added is -1793035504
Weight just added is 0
Lateness just added is 0

Серьезно, в чем разница между оценками и весом / задержкой? Кажется, только одна из них испорчена с самого начала.

Редактировать: я вложил scanf и printf, чтобы проверить, сколько переменных было успешно отсканировано, и возвращенные числа были такими, как я ожидал. Таким образом, никакой новой информации.

Это файл, из которого читается ввод:

10 0 Y
2
2, 80, 40, 0
1, 100, 60, 0

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

2, 80, 40, 0
1, 100, 60, 0

Ответы [ 2 ]

6 голосов
/ 09 февраля 2020

Проблема в том, что вы логически пытаетесь поставить "телегу перед лошадью" . Ход программы последовательный. Вам нужно прочитать и сохранить значения, которые вы ищете, прежде чем пытаться вывести сохраненные значения. В вашем коде вы пытаетесь вывести неинициализированные (например, неопределенные ) значения до того, как получите ввод для заполнения значений (или инициализируете значения во время объявления). Как отмечено выше, это приводит к неопределенному поведению :

C11 Standard - 6.7.9 Инициализация (p10) "Если объект, который имеет automati c продолжительность хранения не инициализирована явно, ее значение не определено. " и C11 Standard - J.2 Неопределенное поведение " Используется значение объекта с автоматами c продолжительность хранения пока оно не определено (6.2.4, 6.7.9, 6.8). "

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

Глядя на ваш код, кажется, что вы хотите запросить у пользователя число assignments для ввода, а затем l oop, принимая данные для элементов массива для score, weight и days_late и затем отображать то, что было введено для подтвердите ввод.

При усложнении проблемы вы пытаетесь заставить пользователя ввести index в массивах, в которых будут храниться значения (хорошо, но не нужно, если вы зацикливаетесь на вводе). Кроме того, значение index должно быть в пределах диапазона элементов в каждом из ваших массивов, например, 0 <= index < 50. Вы должны были бы проверить, что index попадает в диапазон перед его использованием - или вы бы снова вызвали Undefined Behavior , пытаясь записать и прочитать значения за пределами границ вашего массива.

Чтобы устранить всю проблему index, поскольку вы зацикливаетесь, просто прочитайте значения для присваивания, соответствующие переменной l oop. (например, вместо scores[index] просто используйте scores[i] в вашем l oop). Таким образом, l oop контролирует запрашиваемый и заполняемый индекс.

Собирая это вместе и проверяя каждый вход (и просто выйдите, если введена недопустимая запись), вы можете сделать что-то похожее на:

#include <stdio.h>

int main (void) {

    int assignments,
        i,                      /* for loop index for both loops */
        days_late[50] = {0},    /* initialize arrays all zero */
        scores[50] = {0}, 
        weights[50] = {0};

    fputs ("\nEnter No. assignments: ", stdout);    /* prompt for no. assignments */
    /* VALIDATE EVERY INPUT - both the conversion and that the value is within range */
    if (scanf("%d", &assignments) != 1 || assignments < 0 || assignments > 49) {
        fputs ("error: invalid integer input or input out of range.\n", stderr);
        return 1;
    }

    /* loop assignments times */
    for (i = 0; i < assignments; i++) {
        /* display assignment no. prompt for score, weight, days_late */
        printf ("\nassignment[%2d]\nenter score, weight, days_late: ", i + 1);
        if (scanf ("%d%d%d",    /* read and VALIDATE each value */
                    &scores[i], &weights[i], &days_late[i]) != 3) {
            fputs ("error: invalid integer input - scores, weights, days_late.\n", 
                    stderr);
            return 1;
        }
        /* output values read */
        printf ("\nScore just added is %d\n"
                "Weight just added is %d\n"
                "Lateness just added is %d\n",
                scores[i], weights[i], days_late[i]);
    }
    return 0;
}

Обратите внимание, вы можете обрабатывать проверку ошибок более изящно, так что пользователю будет предложено повторять запрос до действительной записи сделано (или EOF сгенерировано), но оно остается вам после разрешения входной логики c. См. Ответ на функция isalpha в C не возвращает правильное значение - для примера помечает все входные данные как символы AZ * .

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

$ ./bin/scoreswtsdays_late

Enter No. assignments: 2

assignment[ 1]
enter score, weight, days_late: 88 1 0

Score just added is 88
Weight just added is 1
Lateness just added is 0

assignment[ 2]
enter score, weight, days_late: 91 1 2

Score just added is 91
Weight just added is 1
Lateness just added is 2

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


Редактировать после публикации формата входного файла

Пока нам все еще неясно, значение первой строки, учитывая ваше оставшееся описание, чтение assignments из строки 2, а затем зацикливание assignments раз и чтение index, scores, weights, days_late довольно просто.

Поскольку вы читаете строку -время , вы захотите использовать линейно-ориентированную функцию ввода, такую ​​как fgets() (или POSIX getline()). Обратите внимание, что строчно-ориентированные функции читают и включают '\n' в конце каждой строки в буфере, который они заполняют (хотя здесь синтаксический анализ с sscanf, никаких специальных приспособлений не требуется)

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

Начиная с строки-3, просто прочитайте строку и затем проанализируйте значения из строки используя sscanf, проверяем ожидаемое количество конверсий для каждой строки. Значения легко анализируются из строки с форматной строкой "%d, %d, %d, %d"

Соединяя части, вы можете сделать:

#include <stdio.h>

#define MAXC 1024       /* if you need a constant, #define one (or more) */

int main (void) {

    char buf[MAXC];             /* character array used as buffer for input */
    int assignments,
        i = 0,                  /* loop counter */
        days_late[50] = {0},    /* initialize arrays all zero */
        scores[50] = {0}, 
        weights[50] = {0};

    if (!fgets (buf, MAXC, stdin)) {    /* read/validate line 1 */
        fputs ("error: insufficient input - line 1\n", stderr);
        return 1;
    }
    /* parsing the 3 values left to you until description given */
    printf ("line 1: %s", buf);       /* simply output line 1 */

    if (!fgets (buf, MAXC, stdin)) {    /* read/validate line 2 */
        fputs ("error: insufficient input - line 1\n", stderr);
        return 1;
    }
    /* parse assignments from buf, validate in range */
    if (sscanf (buf, "%d", &assignments) != 1 || assignments < 0 || assignments > 49) {
        fputs ("error: invalid assignments values line - 2\n", stderr);
        return 1;
    }

    while (i < assignments && fgets (buf, MAXC, stdin)) {
        int index, score, weight, dayslate; /* temporary value to read into */
        /* parse values from line, VALIDATE 4 conversion took place */
        if (sscanf (buf, "%d, %d, %d, %d", &index, &score, &weight, &dayslate) != 4 ||
                    index < 0 || index > 49) {
            fputs ("error: invalid line format, lines 3+, or index out of range\n", 
                    stderr);
            return 1;
        }
        scores[index] = score;          /* assign values to array[index] */
        weights[index] = weight;
        days_late[index] = dayslate;

        /* output values read */
        printf ("\nassignment[%2d]:\n"
                "  Score just added is   : %d\n"
                "  Weight just added is  : %d\n"
                "  Lateness just added is: %d\n",
                index, scores[index], weights[index], days_late[index]);
        i++;    /* increment counter */
    }
    return 0;
}

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

Если ваш входной файл находится в dat/scoreswtsdays.txt, запуск программы при перенаправлении файла данных в качестве ввода приведет к следующему:

$ ./bin/scoreswtsdays_late_file < dat/scoreswtsdays.txt
line 1: 10 0 Y

assignment[ 2]:
  Score just added is   : 80
  Weight just added is  : 40
  Lateness just added is: 0

assignment[ 1]:
  Score just added is   : 100
  Weight just added is  : 60
  Lateness just added is: 0

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

0 голосов
/ 09 февраля 2020

Изменение оператора scanf на

printf(" Variables scanned: %d",scanf("%*c%d%*c%d%*c%d",&scores[index],&weights[index],&days_late[index]));

устранило проблему. Ответ Дэвида также проницателен, но только объяснил большое значение для первого результата оценки. Я все еще рекомендую людям поддержать его ответ, потому что он содержит полезные советы по другим вопросам.

...