C无法获取数组内部的搜索号,而循环工作和“双重自由或损坏”错误

问题描述 投票:0回答:3

我是C编程的菜鸟,我很抱歉这个问题很容易,但我整个下午搜索后都无法解决这个问题。我正在尝试编写一个生成随机数的程序,检查文件number.txt中包含的列表中是否存在这个数字。最后,程序必须询问您是否要提取另一个数字,如果是,则重新运行它。我尝试了各种for和while循环,但这些都没有奏效:列表中的数字经常被提取,​​出了什么问题?

此外,有时,在各种迭代之后,程序会因错误“双重免费或损坏(!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);

}
c for-loop random while-loop corruption
3个回答
2
投票

您的代码中存在几个问题

1)printf("ERROR Creating File!");是一个不好的消息,你不要尝试创建文件,你打开它来读取里面

2)num[5] = 0;有一个未定义的行为,因为你写出了大小为5的num(int num[5];

3)free(filer);文件管理器是一个FILE *,行为是未定义的,你想做什么?这很可能是你的原因:

此外,有时,在各种迭代之后,程序会因错误“双重免费或损坏(!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

0
投票

好吧,我研究了你的代码,我或多或少地了解你的程序做了什么以及如何分配变量,但现在这是我的问题:我将数组的维度设置为5,因为我只想读取最后一个(或者第一个) ,现在)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
投票

好的,我的程序增长了,现在有很多新功能:

  1. 您可以选择加载名称列表的文件
  2. 您可以选择包含之前会话中尚未提取的数字的文件
  3. 你可以添加在上一课没有出现的学生的数量,或者没有学过课程的学生的数量(我需要这个课程给学生打电话)
  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);
}
© www.soinside.com 2019 - 2024. All rights reserved.