Цель c, строка Scanf (), принимающая одно и то же значение дважды - PullRequest
1 голос
/ 09 мая 2011

Привет всем, у меня странная проблема, когда я использую scanf для ввода данных, он повторяет строки и сохраняет их как один, я не уверен, почему.

Пожалуйста, помогите

/ * Цикл метки назначения - Прокручивает метки ассемблера и вводит процент и название для него.* /

i = 0;
j = 0;
while (i < totalGradedItems)
{
    scanf("%s%d",  assLabel[i], &assPercent[i]);
    i++;
}

/ * Распечатка заявления * /

i = 0;
while (i < totalGradedItems)
{
    printf("%s", assLabel[i]);
    i++;
}

Входные данные

Prog1 20
Quiz 20
Prog2 20
Mdtm 15
Final 25

Вывод через консоль

Prog1QuizQuizProg2MdtmMdtmFinal

Ответы [ 2 ]

3 голосов
/ 09 мая 2011

Окончательный диагноз

Вы не показываете свои объявления ... но вы должны выделить только 5 символов для строк:

Когда я настраиваю enum MAX_ASSESSMENTLEN от 10 до 5 (см. код ниже) Я получаю вывод:

Prog1Quiz  20
Quiz       20
Prog2Mdtm  20
Mdtm       15
Final      25

Вы не допустили нулевой терминал.И вы не показали нам, что вызвало ошибку!И тот факт, что вы пропустили переводы строк в распечатке, скрыл проблему.

То, что происходит, - то, что 'Prog1' занимает все 5 байтов строки, которую вы читаете, и записывает ноль в 6-м байте;затем читается викторина, начиная с шестого байта.Когда printf() идет, чтобы прочитать строку для «Prog1», он останавливается на первом нулевом значении, которое является последующим после «z» в «Quiz», производя показанный результат.Повторите для «Prog2» и «Mtdm».Если после «Финала» будет запись, она тоже пострадает.Вам повезло, что вокруг достаточно нулевых байтов, чтобы предотвратить любые чудовищные переполнения.

Это базовое переполнение буфера (действительно, поскольку массив находится в стеке, это базовое переполнение стека );Вы пытаетесь втиснуть 6 символов (Prog1 плюс '\0') в 5-байтовое пространство, и оно просто не работает должным образом.


Предварительная диагностика

Сначала напечатайте новые строки послеваши данные.

Во-вторых, проверьте, что scanf () не возвращает ошибки - вероятно, это не так, но ни вы, ни мы не можем сказать точно.

В-третьих, вы уверены, чтофайл данных содержит то, что вы говорите?Вероятно, он содержит пару «Викторина» и пару строк «Mtdm».

Ваша переменная j, кстати, не используется.

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

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char assLabel[10][10];
    int  assPercent[10];

    int i = 0;
    int totalGradedItems = 5;

    while (i < totalGradedItems)
    {
        if (scanf("%9s%d",  assLabel[i], &assPercent[i]) != 2)
        {
            fprintf(stderr, "Error reading\n");
            exit(1);
        }
        i++;
    }

    /* Print Statement */

    i = 0;
    while (i < totalGradedItems)
    {
        printf("%-9s %3d\n", assLabel[i], assPercent[i]);
        i++;
    }

    return 0;
}

Для указанных входных данных, выходные результаты:

Prog1      20
Quiz       20
Prog2      20
Mdtm       15
Final      25

Я предпочитаю эту версию, хотя:

#include <stdio.h>

enum { MAX_GRADES = 10 };
enum { MAX_ASSESSMENTLEN = 10 };

int main(void)
{
    char assLabel[MAX_GRADES][MAX_ASSESSMENTLEN];
    int  assPercent[MAX_GRADES];
    int i = 0;
    int totalGradedItems;

    for (i = 0; i < MAX_GRADES; i++)
    {
        if (scanf("%9s%d", assLabel[i], &assPercent[i]) != 2)
            break;
    }
    totalGradedItems = i;

    for (i = 0; i < totalGradedItems; i++)
        printf("%-9s %3d\n", assLabel[i], assPercent[i]);

    return 0;
}

Конечно, если бы я установил строку формата scanf() 'правильно' (то есть безопасно), чтобы ограничить длину имен оценки, чтобы они соответствовали выделенному пространству, тогда циклпрекратите чтение со второй попытки:

...
char format[10];
...
snprintf(format, sizeof(format), "%%%ds%%d", MAX_ASSESSMENTLEN-1);
...
    if (scanf(format, assLabel[i], &assPercent[i]) != 2)

При MAX_ASSESSMENTLEN в 5, snprintf() генерирует строку формата "%4s%d".Скомпилированный код читает:

Prog       1

и останавливается.«1» происходит от 5-го символа «Prog1»;следующее имя оценки - «20», а затем преобразование «Викторины» в число завершается неудачно, в результате чего цикл ввода останавливается (поскольку был преобразован только один из двух ожидаемых элементов).

Несмотря на неудобство, если вы хотите, чтобы ваши строки scanf() корректировались в соответствии с размером переменных данных, в которые они читают, вы должны сделать что-то похожее на то, что я сделал здесь - отформатировать строку, используя правильные значения размера.

0 голосов
/ 09 мая 2011

Полагаю, вам нужно поставить

scanf("%s%d",  assLabel[i], &assPercent[i]);

пробел между% s и% d здесь.

И он не сохраняется как единое целое.Чтобы увидеть разницу, вам нужно поставить символ новой строки или поставить пробел после% s.

добавьте:

, когда я попробовал

#include <stdio.h>

int main (int argc, const char * argv[])
{

    char a[1][2];

    for(int i =0;i<3;i++)
    scanf("%s",a[i]);

    for(int i =0;i<3;i++)
        printf("%s",a[i]);
    return 0;
}

со входами

123456
qwerty
sdfgh

вывод:

12qwsdfghqwsdfghsdfgh

, что доказывает, что размер строкового массива должен быть больше, чем объявлено там.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...