0

I am trying to shuffle the string elements in a 2d array, and I'm quite confused whether I should just shuffle the columns or all of them. Here's what I've done so far.

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

  char words[4][20] = {"abc", "dec", "dsz", "dfas"};
  for (int i=0;i<4;i++){
    srand(time(NULL));
    int r = rand() % 4;
    int temp = i;
    strcpy(words[i], words[r]);
    strcpy(words[r],words[temp]);
  }
  for(int j=0;j<4;j++){
    printf("Elements: %s\n",words[j]);
  };
  return 0;
}

However, this gives me a Trace/BPT trap: 5 error. Any helps would be appreciated.

kaylum
  • 13,833
  • 2
  • 22
  • 31
Chocode
  • 147
  • 9
  • 3
    Unrelated to your problem, but you should never seed the random number generator more than once. Because you do it in the loop, each call to `rand()` will most likely return the exact same value. – Some programmer dude Mar 30 '22 at 11:33
  • 2
    When `r == i` you will be calling `strcpy()` with the same object, which is Undefined Behavior. – pmg Mar 30 '22 at 11:35
  • 3
    And you have some basic misunderstanding about swapping values. You should copy the whole string `words[i]` into a temporary array. Then after overwriting `words[i]` with `words[r]` you should copy the temporary string to `words[r]`. What you do now, `strcpy(words[r],words[temp])` is actually the same as `strcpy(words[r],words[i])`, which doesn't make sense. – Some programmer dude Mar 30 '22 at 11:36
  • Thanks for your comment. So if I copy the whole string into temp, would this work? I'm mostly confused on shuffling the column or as a whole. Thanks – Chocode Mar 30 '22 at 11:40
  • 1
    Unfortunately, making a proper random permutation is not as obvious as it might seem. As is, your code is not guaranteed to produce a permutation, as a given string could appear in the output twice or not at all. And some permutations are more likely than others. You can either try to reinvent the wheel here, or use the well-known [Fisher-Yates Shuffle algorithm](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle). That would, among other benefits, suppress the risk of swapping a string with itself, which is the likely cause of the crash. – jpmarinier Mar 30 '22 at 12:19
  • See [`srand()` — why call it only once?](https://stackoverflow.com/q/7343833/15168) – Jonathan Leffler Mar 30 '22 at 13:11
  • See also: • [Shuffle array in C](https://stackoverflow.com/q/06127503/15168) • Wikipedia on [Fisher-Yates Shuffle](http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle) • Jeff Atwood on [The Danger of Naivete](http://www.codinghorror.com/blog/2007/12/the-danger-of-naivete.html). • Ben Pfaff's [implementation](http://benpfaff.org/writings/clc/shuffle.html) • [Why does this simple shuffle algorithm produce biassed results?](https://stackoverflow.com/q/859253/15168) • [Is this C implementation of Fisher-Yates shuffle correct?](https://stackoverflow.com/q/3343797/15168) – Jonathan Leffler Mar 30 '22 at 15:08
  • @ChoiChangWoo: to swap two items, you need a third intermediate one. For example, for swapping integers `x` and `y` you need: `int tmp = x; x = y; y = tmp;`. Hence for your strings, you need: `char tmp[20]; strcpy(tmp, words[i]); strcpy(words[i], words[r]); strcpy(words[r], tmp);`. – Jonathan Leffler Mar 30 '22 at 16:42

2 Answers2

1

There are some ideas in your code, but there are some mistakes too. As some comments told, you should not initialize your random seed in your loop, but at the start of your program.

For your problem, it's probably because of strcpy function. Indeed, sometimes r will be equal to i, meaning that when you call strcpy(words[i], words[r]), both arguments actually refer to the same piece of memory, leading to your program crashing. This is because strcpy() takes restrict pointers as arguments.

In order to understand why it does give you an error, you must understand what the restrict keyword means in C : when two function parameters are made restrict, it means that they reference different pieces of memory. It's really great for compiler optimisation (to see more, you can have a look at this : Realistic usage of the C99 'restrict' keyword?.)

If you want your code to work, you must use a different char array as a buffer to hold your temp value.

It would then work like this :

srand(time(NULL));
char words[4][20] = {"abc", "dec", "dsz", "dfas"};
char buffer[20];
for (int i=0;i<4;i++){
    int r = rand() % 4;
    strcpy(buffer, words[i]);
    strcpy(words[i], words[r]);
    strcpy(words[r], buffer);
}
imperosol
  • 584
  • 4
  • 14
-1

Fisher-Yates Shuffle algorithm mentioned by jpmarinier.

srand(time(NULL));
  char words[4][20] = {"abc", "dec", "dsz", "dfas"};
  char copyWords[4][20];
  for (int i=0;i<4;i++){
      int r = rand() % 4;
      while(1){
        if (strcmp(words[r],"") != 0){
          strcpy(copyWords[i], words[r]);
          memset(words[r],0,sizeof(words[r]));
          break;
        }
        else {
          r = rand() % 4;
        }
      }
  }

Any feedback is welcome.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Chocode
  • 147
  • 9
  • It's not clear that the second array is really necessary. And destroying the first (source) array is not usual. This seems to be an approximation to what's described in [Wikipedia](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle) as "Fisher and Yates' original method". Approximation because the Fisher and Yates method changes the random number selected to 1..k where k is the number of as-yet unchosen options. This code would implement that by copying the last element of the `word` array over the selected element and reducing the random range (currently stuck at 4) to 3, 2, 1. – Jonathan Leffler Mar 30 '22 at 15:04
  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 30 '22 at 15:28