This is my code. I want to get 5 strings from the user and espeak reads each of them when user interred it. But I get segmentation fault(core dumped)
message.
#include <string.h>
#include <malloc.h>
#include <espeak/speak_lib.h>
int test()
{
espeak_POSITION_TYPE position_type;
espeak_AUDIO_OUTPUT output;
char *path=NULL;
int Buflength = 500, Options=0;
void* user_data;
t_espeak_callback *SynthCallback;
espeak_PARAMETER Parm;
char Voice[] = {"English"};
int i=0;
char text[1000];
unsigned int Size,position=0, end_position=0, flags=espeakCHARS_AUTO, *unique_identifier;
output = AUDIO_OUTPUT_PLAYBACK;
espeak_Initialize(output, Buflength, path, Options );
espeak_SetVoiceByName(Voice);
const char *langNativeString = "en_US";
espeak_VOICE voice={0};
voice.languages = langNativeString;
voice.name = "US";
voice.variant = 2;
voice.gender = 1;
Size = strlen(text)+1;
for (i=0; i<5; i++)
{
scanf("%s ", &text);
printf("%s", text);
espeak_Synth( text, Size, position, position_type, end_position, flags,
unique_identifier, user_data );
espeak_Synchronize( );
fflush(stdout);
}
return 0;
}
int main(int argc, char* argv[] )
{
test();
return 0;
}
I tried some modification but none of them worked. I want the program works like this:
User input: hi
espeak says: hi
user input: one
espeak says: one
(for 5 inputs)
But when I try to interring more than 4 characters as input,it gives segmentation fault
error!
The two main issues are:
strlen
on an uninitialized array of chars;unique_identifier
argument of espeak_Synth
must be NULL
or point to an unsigned int (see the source code) while now it is an unsigned pointer to random memory.Move strlen
after scanf
, use NULL
instead of unique_identifier
and your code will suddenly work (kind of).
There are many other issues though: useless variables, uninitialized variables, no input sanitization and more. IMO a better approach would be to throw away the test
function and rewrite it from scratch properly.
This is how I'd rewrite the above code. It is still suboptimal (no input sanitization, no error checking) but IMO it is much cleaner.
#include <stdio.h>
#include <string.h>
#include <espeak/speak_lib.h>
static void say(const char *text)
{
static int initialized = 0;
if (! initialized) {
espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, NULL, 0);
espeak_SetVoiceByName("en");
initialized = 1;
}
espeak_Synth(text, strlen(text)+1,
0, POS_CHARACTER, 0,
espeakCHARS_UTF8, NULL, NULL);
espeak_Synchronize();
}
int main()
{
char text[1000];
int i;
for (i = 0; i < 5; ++i) {
scanf("%s", text);
say(text);
}
return 0;
}