-1

i would like to print all the content from the files in the same folder. The attached photo shows how i named my files. i would first random generate a sequence according to fisher yates shuffle and then print the files according to the sequence.

how i name my files

however, in my program, i keep getting buffer overflow detected and could only print the content of the first file. i have tested and the overflow occurs after the while loop and before the rewind(pic) statement. it works when i print one single file, so it shouldn't be the problem with the arrays 'folder1' and 'folder2'. i think the main problem is with the 'loadPhoto' function, but i still provided other parts of the code (necessary ones) for your reference.

also i added this to test which part is wrong,

printf("first test"); 
rewind(pic);
printf("\n");
printf("second test");

however, the weird thing is when printf("\n"); is added in the third row, 'first test' can be printed. however, when printf("\n"); is deleted, 'first test' cannot be printed.

int i, j;
FILE *pic;
FILE *correctAns;
char ch;
char category[10] = "";
int secondTries = 3, correct;

char askCategory() {
  printf("\nAnimals     Weather\n");
  printf("Clothes      Food\n");
  printf(" Fruit       Jobs\n");
  printf("\nWhich category of vocabulary would you like to learn? ");
  scanf("%s", category);
}

void fisherYatesShuffle(int arr[]){
  int random, temp;
  srand(time(NULL));
  for (i=14; i>0; i--){
    random = rand()%(i+1);
    temp = arr[i];
    arr[i] = arr[random];
    arr[random] = temp;
  }
}

void loadPhoto(){
  char photo[3];
  int sequence[15];
  for (i=0; i<15; i++)
    sequence[i] = i;
  fisherYatesShuffle(sequence);

  char folder1[20] = "ascii_art/";
  char folder2[10] = "";
  strcat(strcpy(folder2, category), "/");
  for(i=0; i<15;i++){
    sprintf(photo, "%d", sequence[i]);
    pic = fopen(strcat(strcat(folder1, folder2), photo), "r");
    if (pic == NULL)
      printf("Error. Cannot open the file.");
    printf("\n");
    while ((ch = fgetc(pic)) != EOF){
      printf("%c", ch);
    }
    printf("first test"); 
    rewind(pic);
    printf("\n");
    printf("second test");
    rewind(pic);
    printf("\n");
  }
 }

void Level1() {
  askCategory();
  // printf("%s", category);
  loadPhoto();
}

int main(void) {
  int form = 0, level;
  do {
    printf("Enter your level of study (1-6): ");
    scanf("%d", &form);
    if (form == 1 || form == 2 || form == 3)
      Level1();
    else if (form == 4 || form == 5 || form == 6)
      Level2();
    else
      printf("Invalid input. Please input again.\n");
  } while (form < 1 || form > 6);

  return 0;
}

here is my code. i have tried using the rewind function but it doesnt solve the problem. thank you very much for your help!!!

soph
  • 17
  • 4
  • 2
    Where do you declare `i`, `pic` and `ch`? `rand() % 14 + 0` gets you values from 0 to 13, not 14. Use `srand(time(NUL))` only once at the start of your program. Close your files when you dont need them anymore. – Joel Aug 24 '23 at 12:04
  • 1
    Your array sizes seem to be very small, start looking there if one of them overflows. You can just multiplay all array sizes by 3, if the problem goes away the probability is high that you have a buffer overflow. Then dig deeper. – Jabberwocky Aug 24 '23 at 12:11
  • Please supply a _complete_ (but still minimal) code sample. Where is the definition of `category`? Did you initialize it? How long is the string used to initialize it? – Ruud Helderman Aug 24 '23 at 12:34
  • @RuudHelderman hello, i have gave more details on the program and description. could you please help take a look and see what's wrong with it, please? thanks a lot for your help! – soph Aug 24 '23 at 16:14
  • Stack Overflow is not a collaborative coding platform. Please do not update your question with bugfixes proposed in answers. It turns the question into a moving target. At the moment, your code contains an obvious buffer overflow that wasn't there in the original question: doing `strcat` on `folder1` in a loop without re-initializing `folder1` on every loop iteration. – Ruud Helderman Aug 24 '23 at 18:43
  • By the way, `ch` [must be int, not char](https://stackoverflow.com/questions/35356322/difference-between-int-and-char-in-getchar-fgetc-and-putchar-fputc). – Ruud Helderman Aug 24 '23 at 18:48
  • @RuudHelderman the buffer overflow has always been there, before and after i edited – soph Aug 25 '23 at 00:08
  • @soph I wasn't insinuating there was no buffer overflow before the edit. I was trying to make you aware _the edit itself_ is harmful, for reasons explained [here](https://meta.stackexchange.com/q/96560). – Ruud Helderman Aug 28 '23 at 11:24

1 Answers1

1
      srand(time(NULL));

Do not call srand inside this loop or this function. srand starts a sequence of random numbers, so you use it only once to start a sequence, then you use rand to get numbers from that sequence. Commonly srand is called once near the start of the main routine. (Some programs might call it again if they need to repeat the same sequence for a reason or want to perform separate controlled experiments that can be reproduced by using the same seed to srand.)

Calling srand repeatedly restarts a sequence repeatedly. And time typically returns a time in seconds (the C standard does not specify the units), so it changes only once per second. But your program runs quickly and does many things per second, so you are repeatedly restarting the same sequence and getting the same numbers from rand, until the next second arrives.

      random = rand() % 14 + 0;

% 14 limits the result to 14 different values, the integers from 0 to 13, inclusive. To get 0 to 14, you need rand() % 15. (Also, there may be issues with using % to obtain values from some poor-quality random number generators and when high-quality distributions are needed. You can neglect these for now but should be aware not to use a simple % operation with rand in good-quality programs.)

      if(chosen[random] == 1)

This is an inefficient way to do selection without replacement. A common method is the Fisher-Yates shuffle: Put the entire population of numbers into an array and set a variable to count how many unused numbers are in the array. Pick an element randomly from the unused numbers. Copy that element, then move the last element into its place and reduce the count of remaining unused numbers.

      if(chosen[random] == 1){
        srand(time(NULL));
        random = rand() % 14 + 0;
      }
    }while(chosen[random] == 1);

You have a redundant test inside a loop that does the same test. If you are not going to change to the Fisher-Yates shuffle, rewrite this loop to remove the interior test. Just loop until a non-repeated value is found.

    char folder1[20] = "ascii_art/";
    char folder2[10] = "";
    strcat(strcpy(folder2, category), "/");
    pic = fopen(strcat(strcat(folder1, folder2), photo), "r");

You have not given us enough information to know whether 20 characters suffice for folder or whether 10 characters suffice for folder2. Shown the definition of category. This is a like source of buffer overflows.

You did not test whether pic is null, indicating the fopen failed.

    while (ch != EOF) {
      ch = fgetc(pic);
      printf(" %c", ch);
    }

You did not initialize ch before this code, so using it in ch != EOF is wrong. The proper place to test ch is after assigning a value to it with fgetc(pic) and before printing it with printf(" %c", ch);. One way to rewrite the loop is:

while (1)
{
    ch = fgetc(pic);
    if (ch == EOF)
        break;
    printf(" %c", ch);
}
    strcpy(photo, "");

This is unnecessary.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • thanks for your suggestions. i have made modifications according to your suggestions but it still shows 'buffer overflow detected'. i have edited and provided more details of the program above. Could you kindly take a look at it and see if you can spot any mistakes, please? thank you very much for your help!! – soph Aug 24 '23 at 16:20