为什么这段随机化歌曲名称列表的代码会产生分段错误?

Why does this code to randomize a list of song names generate a segmentation fault?

我正在尝试创建一个程序,从用户那里接收 12 首歌曲标题,然后以随机顺序形成一个集合列表。我使用了 gets() 函数和内存分配,以便将输入放入这样的数组中:

 argv[0] = song1, argv[1] = song2, argv[2] = song3 (etc.). 

输入实际歌曲然后通过随机化和createSetList()函数运行将其createSetList()合并时,似乎存在常见的分段错误。但是,如果放弃内存分配和硬编码,它会工作得很好。我的意思是这样的:

char *input[ SONG ] =
  { "song1", "song2", "song3", "song4",
      "song5", "song6", "song7", "song8",
        "song9", "song10", "song11", "song12", "song13" };

不过,我的目的是让用户在 运行 时间内输入歌曲名称。段错误错误的原因是什么?

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define SONG 13
#define SETSIZE 5
// prototypes

void randomize( unsigned int wDeck[ SONG ] ); 
void createSetList( unsigned int wDeck[ SONG ], char *wFace[] ); 

int main( void ){

printf("Please enter the songs you want to play!\n");
printf("I will create the set list and randomize it for you!\n");


char input[100];
char *argv[ SONG ];
char *token;

 /*memory allocation for inputting song titles into a single array*/
 /*****memory allocation code starts here********/
 gets(input);
   token = strtok(input, " ");
     int i=0;
       while( token != NULL ) {
         argv[i] = malloc(strlen(token) + 1);
           strncpy(argv[i], token, strlen(token));
             i++;
      token = strtok(NULL, " ");
    } 
       argv[i] = NULL; //argv ends with NULL
         /***memory allocation code ends here*****/

         unsigned int setList[ SONG ] = { 0 };
           srand( time( NULL ) ); // seed random-number generator
             randomize( setList ); // shuffle the list
                createSetList( setList, argv ); // create the setlist
 } //end of main





/*SHUFFLE FUNCTION*/
   void randomize( unsigned int wDeck[ SONG ] ){

     size_t column;
      size_t c;

 for ( c = 1; c <= SETSIZE; ++c ) {
     do {
       column = rand() % SONG;
         } while( wDeck[ column ] != 0 );

               wDeck[ column ] = c;}}

    /* Create Set List Function */
 void createSetList( unsigned int wDeck[ SONG ],  char *wFace[] ){

    size_t c;
     size_t column;

      for ( c = 1; c <= SETSIZE; ++c ) {

        for ( column = 0; column < SONG; ++column ) {

          if ( wDeck[ column ] == c ) {

             printf( "%s\n", wFace[ column ]); 
                }}}}

在您的代码中,

strncpy(argv[i], token, strlen(token));

用法有误。您还需要复制终止空字节。

strncpy()man page可以看出

The strncpy() function is similar, except that at most n bytes of src are copied.

Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.

如评论中所述,我的 @chqrlie 先生在 nice article by @Keith Thompson, you should not be using strncpy(). To be on safer side, you can make use of strdup() 中进行了解释,以避免开销( 和陷阱 ) malloc()+ strcpy().

伪代码

 argv[i] = strdup(token);

将以高效的方式完成工作。请记住,您仍然需要 free() strdup() 返回的指针。