I am trying to pass some strings trough espeak and

2019-08-28 21:29发布

问题:

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!

回答1:

The two main issues are:

  1. you use strlen on an uninitialized array of chars;
  2. the 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.

Addendum

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;
}