C не может получить номер поиска в массиве внутри цикла, пока работает цикл и ошибка «двойного освобождения или повреждения» - PullRequest
0 голосов
/ 28 февраля 2019

Я новичок в программировании на C, и я прошу прощения за этот вопрос, который может быть очень простым, но я не могу решить эту проблему после поиска весь день.Я пытаюсь написать программу, которая генерирует случайное число, проверяя, что это еще не присутствует в списке, содержащемся в файле number.txt.В конце программа должна спросить, хотите ли вы извлечь другой номер и, если да, перезапустить его.Я пробовал разные циклы for и while, но ни один из них не работал: числа в списке часто извлекаются, что не так?

Более того, иногда, после различных итераций, программа останавливается с ошибкой «double free или поврежден (! prev) ", чем это вызвано?

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define rangeMAX 27 //Upper limit of range.
#define rangeMIN 1  //Lower limit of range.


int main()
{
  int get, i, n;
  int num[5];
  char r;
  FILE *filer;
    filer = fopen("numbers.txt", "r");
    printf("When you are ready press any key to continue\n");
    getchar();
    if (filer == NULL)
    {
        printf("ERROR Creating File!");
        exit(1);
    }
    do {
        num[5] = 0;
        n = 0;
        i = 0;
        free(filer);
        get = 0;
        r = 0;
            srand(time(0)); // this will ensure that every time, program will generate different set of numbers. If you remove this, same set of numbers will generated every time you run the program.
            get = ((rand() % (rangeMAX-rangeMIN+1)) + rangeMIN); // generate random number.
        for (n = 0; n < 5; n++){
        fscanf(filer, "%d\n", &num[n]);
        }
            for (n = 0; n < 5; n++){
                if (get == num[n]){
                printf("false\n");
                printf("%d\n", n);
                break;
                }
            }
                i=get;
                printf("%d\n",i);
    printf ("Do you want another number? Y/N ");
    scanf (" %c", &r);
    } while (r == 'y' || r == 'Y');
    return(0);

}

Ответы [ 3 ]

0 голосов
/ 01 марта 2019

Хорошо, я изучил ваш код и более или менее понял, что делает ваша программа и как назначаются переменные, но теперь это моя проблема: я установил размерность массива на пять, потому что хочу прочитать только последний (или первое, пока что) пять чисел в number.txt (которое должно быть самым последним извлеченным, потому что на следующем шаге я хотел бы добавить каждое извлеченное число в этот файл), поэтому мне удалось изменить ваш код, чтобы сделать это(только что изменил первый цикл while), и это прекрасно работает.Я не могу решить, почему ваш цикл for (;;) отлично работает, а мой код не указан, поэтому в моем коде

for (n = 0; n < sizeof(num[5]); n++){
        if (get == num[n]){
        printf("false\n");
        printf("%d\n", n);
        break;
        }
else{
        printf("true");
        break
    }
}

(добавлено еще) работает только для первого числа в массиве, ноЕсли извлекается число, которое является вторым, третьим ... в массиве (которые загружаются в массив, потому что я могу его напечатать), программа не видит его.

@ stensal В моемВ файле numbers.txt каждый номер находится в новой строке.

0 голосов
/ 21 марта 2019

Хорошо, моя программа выросла и теперь имеет много новых функций:

  1. вы можете выбрать файл, из которого загружен список имен
  2. вы можете выбрать файл, содержащийчисла, которые еще были извлечены на предыдущих сессиях
  3. Вы можете добавить номера студентов, которые не присутствовали на последнем уроке или у которых есть правовое подтверждение того, что они не изучали урок (мне нужна эта программа, чтобы позвонить студентамin classe)
  4. Если число еще извлечено, программа пытается выполнить вторую, а затем третью экстракцию

, и это код (комментарии на итальянском языке)

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#define rangeMAX 27 //Upper limit of range.
#define rangeMIN 1  //Lower limit of range.

int main()
{
  srand(time(0)); // this will ensure that every time, program will generate different set of numbers. If you remove this, same set of numbers will generated every time you run the program.

 char elenco[20], filelenco[30];
    printf("inserire il nome del file elenco: ");
    fgets(elenco, 20, stdin);
    elenco[strlen(elenco)-1]='\0';
    sprintf(filelenco, "%s.txt", elenco);

//lettura dell'elenco dei nomi
char nomi[27][20];
FILE * nomif = fopen(filelenco, "r");

  if (nomif == NULL)
  {
    printf("ERROR impossibile leggere %s",filelenco);
    exit(1);
  }

    size_t g = 0;

        for (g = 0; g <=27; g++) {
                fscanf(nomif, "%s", nomi[g]);
                }


//prompt per la scelta del file in cui leggere i numeri di quelli già chiamati
    char fname[20], filename[30];
    printf("inserire il nome del file: ");
    fgets(fname, 20, stdin);
    fname[strlen(fname)-1]='\0';
    sprintf(filename, "%s.txt", fname);
   FILE * filer = fopen(filename, "r");

  if (filer == NULL)
  {
    printf("ERROR impossibile leggere %s\n", fname);
    exit(1);
  }

//creazione dell'array contenente i numeri di quelli già chiamati
  int * nums = NULL;
  int num;
  size_t sz = 0, nnums = 0;
  char yn[16];
  int c;

  while (fscanf(filer, "%d", &num) == 1) {
    if (nnums == sz) {
      sz += 100;
      nums = realloc(nums, sz * sizeof(int));
    }
    nums[nnums++] = num;
  }
  fclose(filer);

//creazione del file contenente gli assenti della volta precedente e i giustificati
char data[30], nome[20];
char ass[20];
struct tm ora;
time_t now;
now = time(NULL);//epoch time
ora = *(localtime(&now)); //conversione nell'ora locale
strftime(data,30,"%Y%m%d",&ora); //formattazione della data secondo lo standard  YYYYMMDD
sprintf(nome, "%s_giustificati_%s.txt", data, fname); //creazione della stringa da usare come nome file
//printf("%s\n", nome);

FILE * assenti;

    assenti = fopen(nome,  "w+"); //creazione vera e propria del file, con il nome formato al comando precedente
    printf("Inserite i numeri degli assenti/giustificati\n");
    scanf("%[^\n]", ass);
    fprintf(assenti, "0 %s", ass);
    fclose(assenti);

//creazione dell'array degi assenit/giustificati tramite lettura del file appena creato
  assenti = fopen(nome, "r");
  int * nums1 = NULL;
  int num1;
  size_t sz1 = 0, nnums1 = 0;
  int d;

  while (fscanf(assenti, "%d", &num1) == 1) {
    if (nnums1 == sz1) {
      sz1 += 100;
      nums1 = realloc(nums1, sz1 * sizeof(int));
    }
    nums1[nnums1++] = num1;
  }
  fclose(assenti);

//attesa dell'input
  while ((getchar()) != '\n'); 

  printf("Se siete pronti premete un tasto per continuare\n");
  getchar();

//scelta della più grande tra le due variabili nnums (numero di elementi dell'array dei già chiamati) e nnums1 (numero di elementi dell'array degli assenti/giustificati) - serve per le iterazioni del ciclo for all'interno del do...while
    size_t max = ((nnums >= nnums1) ? nnums : nnums1);
//    printf("max %d\n", max);

//somma delle due variabili nnums (numero di elementi dell'array dei già chiamati) e nnums1 (numero di elementi dell'array degli assenti/giustificati)
//  size_t total = nnums + nnums1;
//  printf("total %d\n", total);

  do {
    int get = ((rand() % (rangeMAX-rangeMIN+1)) + rangeMIN); // generate random number.
    size_t i = 0;

//ciclo for che verifica che il numero non sia presente nel file dei già chiamati e in quello degli assenti e giustificati. Solo dietro queste due condizioni estrae il numero
    for (;;) {

    if (i == max) {
        printf("E' stato estratto il %d,\n ovvero\n", get);
    sleep(2);
    printf("%s\n", nomi[get-1]);
    filer = fopen(filename, "a");
    fprintf (filer, "%d\n", get);
    fclose(filer);
        break;
      }

//se il numero è gia presente nell'array dei già chiamati crea un interrupt e fa ripartire il do
      if (get == nums[i]) {
//      printf("%d is the number rank %d in the file\n", get, i + 1);
    printf("prima estrazione: Il %d e' gia' stato chiamato\n", get);
    get = ((rand() % (rangeMAX-rangeMIN+1)) + rangeMIN);
    size_t z = 0;
    for (;;) {
        if (z == max) {
            printf("E' stato estratto il %d,\n ovvero\n", get);
                sleep(2);
                printf("%s\n", nomi[get-1]);
                filer = fopen(filename, "a");
                fprintf (filer, "%d\n", get);
                fclose(filer);
                break;}

        if (get == nums[z]){
            printf("seconda estrazione: Il %d e' gia' stato chiamato\n", get);
                get = ((rand() % (rangeMAX-rangeMIN+1)) + rangeMIN);
                    size_t w = 0;
                    for (;;) {
                            if (w == max) {
                                    printf("E' stato estratto il %d,\n ovvero\n", get);
                                    sleep(2);
                                    printf("%s\n", nomi[get-1]);
                                    filer = fopen(filename, "a");
                                    fprintf (filer, "%d\n", get);
                                    fclose(filer);
                                    break;}

                            if (get == nums[w]){
                        printf("e' stato di nuovo estratto il %d\n", get);
                        break;}

                    w += 1;}
            break;}

        z += 1;}

        break;
    }

//se il numero è presente nell'array degli assenti/giustificati crea un messaggio a video e fa ripartire il do
    if (get == nums1[i]) {
    printf("Il %d, ovvero %s, era assente o e' giustificato\n", get, nomi[get-1]);
    break;
      }

      i += 1;
    }

//scelta se continuare ad estrarre o meno
    printf ("Volete estrarre un altro numero? Y/N ");
    if (scanf ("%15s", yn) != 1)
      break;
  } while (*yn == 'y' || *yn == 'Y');


  return(0);
}
0 голосов
/ 28 февраля 2019

В вашем коде есть несколько проблем

1) printf("ERROR Creating File!"); - плохое сообщение, вы не пытаетесь создать файл, вы открываете его для чтения внутри

2) num[5] = 0; имеет неопределенное поведение, потому что вы пишете из num , размер которого равен 5 (int num[5];)

3) free(filer); filer является FILE *, поведение не определено, что вы хотели сделать?Это очень вероятно причина вашего:

Более того, иногда, после различных итераций, программа останавливается с ошибкой "double free or коррупция (! Prev)", что вызывает ее?

4) get = 0; бесполезен, вы не используете get , прежде чем назначить его снова с результатом rand ()

5) r = 0; также бесполезен, потому что вы не используете r , прежде чем делать scanf (" %c", &r);

6) srand(time(0));, что должно быть сделано только один раз в начале программы,не несколько раз, потому что если вы сделаете два раза за одну секунду, rand() вернет одно и то же значение.

7) вы делаете

    for (n = 0; n < 5; n++){
    fscanf(filer, "%d\n", &num[n]);
    }

для каждого do .. while, но вы никогда не возвращаетесь к началу файла, поэтому каждый раз, когда вы прогрессируете и не проверяете конецфайл.Когда вы достигаете конца файла, fscanf(filer, "%d\n", &num[n]); ничего не делает и num не изменяется.

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

8) Вы просите rand () вернуть значение в диапазоне от 1 до 27, так что возможностей мало, поэтому, вероятно, у вас есть:

чисел всписок часто извлекается.


Здесь предложение с учетом замечаний (кроме последнего о диапазоне значений), numbers.txt не ограничивается5 номеров.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define rangeMAX 27 //Upper limit of range.
#define rangeMIN 1  //Lower limit of range.

int main()
{
  srand(time(0)); // this will ensure that every time, program will generate different set of numbers. If you remove this, same set of numbers will generated every time you run the program.

  FILE * filer = fopen("numbers.txt", "r");

  if (filer == NULL)
  {
    printf("ERROR cannot read numbers.txt");
    exit(1);
  }

  int * nums = NULL;
  int num;
  size_t sz = 0, nnums = 0;

  while (fscanf(filer, "%d", &num) == 1) {
    if (nnums == sz) {
      sz += 100;
      nums = realloc(nums, sz * sizeof(int));
    }
    nums[nnums++] = num;
  }
  fclose(filer);

  printf("When you are ready press any key to continue\n");
  getchar();

  char yn[16];

  do {
    int get = ((rand() % (rangeMAX-rangeMIN+1)) + rangeMIN); // generate random number.
    size_t i = 0;

    for (;;) {
      if (i == nnums) {
        printf("%d is not in the file\n", get);
        break;
      }
      if (get == nums[i]) {
        printf("%d is the number rank %d in the file\n", get, i + 1);
        break;
      }
      i += 1;
    }

    printf ("Do you want another number? Y/N ");
    if (scanf ("%15s", yn) != 1)
      break;
  } while (*yn == 'y' || *yn == 'Y');

  return(0);
}

Компиляция и исполнение:

pi@raspberrypi:/tmp $ gcc -pedantic -Wall -g r.c
pi@raspberrypi:/tmp $ cat numbers.txt 
1 3 7 9 10 20 23
pi@raspberrypi:/tmp $ ./a.out
When you are ready press any key to continue

12 is not in the file
Do you want another number? Y/N Y
12 is not in the file
Do you want another number? Y/N Y
4 is not in the file
Do you want another number? Y/N Y
3 is the number rank 2 in the file
Do you want another number? Y/N Y
12 is not in the file
Do you want another number? Y/N Y
15 is not in the file
Do you want another number? Y/N Y
16 is not in the file
Do you want another number? Y/N Y
8 is not in the file
Do you want another number? Y/N N
...