为什么这段随机化歌曲名称列表的代码会产生分段错误?
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()
返回的指针。
我正在尝试创建一个程序,从用户那里接收 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 mostn
bytes ofsrc
are copied.Warning: If there is no null byte among the first n bytes of
src
, the string placed indest
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()
返回的指针。