2015-01-29 3 views
-1

Этот код не работает - проблемы с передачей данных из подпрограммы в основной и выделения памяти.Функция main получила неправильные значения из подпрограммы

Вычисления правильны внутри подпрограммы, но значения, принимаемые основным, неверны - переменные в главном имеют случайные значения, например sRates.

#include <stdio.h> 
#include <malloc.h> 
#include "sndfile.h" 

int main(int argc, char *argv[]) 
{ 
    int sRates , sRatem , ret; 
    long nSamples=0, nSamplem; 
    float *datas, *datam; 


    printf("Read Test\n"); 
    if (argc != 3) { 
     fprintf(stderr, "Expecting two wav file as argument\n"); 
     return 1; 
    } 


    ret = readWav(argv[1], nSamples, sRates, &datas); 
    if (ret != 0) { 
    printf("Error\n"); 
    } 
    // Output Info 
    printf("Read %ld frames from %s, Sample rate: %d, Length: %fs\n", 
     nSamples, argv[1], sRates, (float)nSamples/sRates); 
    printf("Read %ld frames from %s, Sample rate: %d, Length: %fs\n", 
     nSamples, argv[1], sRates, (float)nSamples/sRates); 

// free(datas); 

    return 0; 
} 

int readWav(char *fname, long *numFrames, int *sRate, float **buffer ) 
{ 

    // Open sound file 
    SF_INFO sndInfo; 
    SNDFILE *sndFile = sf_open(fname, SFM_READ, &sndInfo); 
    if (sndFile == NULL) { 
     fprintf(stderr, "Error reading source file '%s': %s\n", fname, sf_strerror(sndFile)); 
     return 1; 
    } 


    printf("1Format of the audio file = %i\n", sndInfo.format); 
    printf("2Number of channels = %i\n", sndInfo.channels); 
    printf("3Sample Rate = %d\n", sndInfo.samplerate); 
    printf("4 Sample count = %ld\n", (long)sndInfo.frames); 
    sRate= sndInfo.samplerate; 

    // Allocate memory 
    buffer = (float *)malloc(sndInfo.frames * sndInfo.channels * sizeof(float)); 
    if (buffer == NULL) { 
     fprintf(stderr, "Could not allocate memory for file\n"); 
     sf_close(sndFile); 
     return 1; 
    } 

     // Load data 
    numFrames = sf_readf_float(sndFile, buffer, sndInfo.frames); 

    // Check correct number of samples loaded 
    if (numFrames != sndInfo.frames) { 
     fprintf(stderr, "Did not read enough frames for source\n"); 
     sf_close(sndFile); 
     free(buffer); 
//  return 1; 
    } 
    else { 
     printf("Successfully read file\n"); 
     numFrames = sndInfo.frames; 
    } 
    // Output Info 
    printf("Read %ld frames from %s, Sample rate: %d, Length: %fs\n", 
//  numFrames, fname, sndInfo.samplerate, (float)numFrames/sndInfo.samplerate); 
     numFrames, fname, sRate, (float)numFrames/sndInfo.samplerate); 


    sf_close(sndFile); 
// return(buffer); 
    return(0); 

} 
+0

'sRates' является локальным для основных. Передайте указатель на него. –

+1

Вы не объявили 'readWav' перед' main'. Если это вообще компилируется, оно должно выдать предупреждение. И на это предупреждение следует обратить внимание. – 5gon12eder

+0

Если ваша функция принимает аргумент 'float *', и вы объявили 'datas' как' float * datas', как вы думаете, '& datas' будут?и, с другой стороны, вы пытаетесь инициализировать 'sRate' в' readWav() 'функцию, но вы передали ее значение вместо своего адреса, там, где вам нужен оператор' & '. –

ответ

1

У вас есть несколько ошибок в коде

  1. Вы не декларировать readWav() и вы называете его от main(), это работает по совпадению, а именно потому, что он возвращает int.

  2. Вы передаете адрес datas к readWav(), обратите внимание, что &datas имеет тип float ** и readWav() ожидает float *.

    Если у вас были предупреждения о компиляторе, вы бы это заметили.

  3. Вы передаете значение nSamples и sRate к readWav() и вы ожидали nSamples и sRate в главном, чтобы инициализировать, вам нужно передать их адреса вместо.

  4. Вы проверяете возвращаемое значение readWav(), и все же вы по-прежнему пытаетесь ввести указатель datas.

Это исправленная версия кода

#include <stdio.h> 
#include "sndfile.h" 

int readWav(const char *const fname, long *numFrames, int *sRate, float **buffer); 

int main(int argc, char *argv[]) 
{ 
    int sRates, sRatem, ret; 
    long nSamples = 0, nSamplem; 
    float *datas, *datam; 


    printf("Read Test\n"); 
    if (argc != 3) { 
     fprintf(stderr, "Expecting two wav file as argument\n"); 
     return 1; 
    } 


    ret = readWav(argv[1], &nSamples, &sRates, &datas); 
    if (ret != 0) { 
     printf("Error\n"); 
     return 1; 
    } 
    // Output Info 
    printf("Read %ld frames from %s, Sample rate: %d, Length: %fs\n", 
     nSamples, argv[1], sRates, (float)nSamples/sRates); 
    printf("Read %ld frames from %s, Sample rate: %d, Length: %fs\n", 
     nSamples, argv[1], sRates, (float)nSamples/sRates); 
    free(datas); 

    return 0; 
} 

int readWav(const char *const fname, long *numFrames, int *sRate, float **buffer) 
{ 
    // Open sound file 
    SF_INFO sndInfo; 

    if ((sRate == NULL) || (numFrames == NULL) || (buffer == NULL)) { 
     fprintf(stderr, "Invalid arguments passed to readWav()\n"); 
     return 1; 
    } 

    SNDFILE *sndFile = sf_open(fname, SFM_READ, &sndInfo); 
    if (sndFile == NULL) { 
     fprintf(stderr, "Error reading source file '%s': %s\n", fname, sf_strerror(sndFile)); 
     return 1; 
    } 

    printf("1Format of the audio file = %i\n", sndInfo.format); 
    printf("2Number of channels = %i\n", sndInfo.channels); 
    printf("3Sample Rate = %d\n", sndInfo.samplerate); 
    printf("4 Sample count = %ld\n", (long)sndInfo.frames); 

    // Allocate memory 
    *buffer = malloc(sndInfo.frames * sndInfo.channels * sizeof(float)); 
    if (*buffer == NULL) { 
     fprintf(stderr, "Could not allocate memory for file\n"); 
     sf_close(sndFile); 

     return 1; 
    } 

    *sRate = sndInfo.samplerate; 
    // Load data 
    *numFrames = sf_readf_float(sndFile, *buffer, sndInfo.frames); 
    // Check correct number of samples loaded 
    if (*numFrames != sndInfo.frames) { 
     fprintf(stderr, "Did not read enough frames for source\n"); 
     sf_close(sndFile); 
     free(*buffer); 
    } 
    else { 
     printf("Successfully read file\n"); 
     *numFrames = sndInfo.frames; 
    } 
    // Output Info 
    printf("Read %ld frames from %s, Sample rate: %d, Length: %fs\n", 
     *numFrames, fname, *sRate, (float)*numFrames/sndInfo.samplerate); 

    sf_close(sndFile); 
    return(0); 

} 

Совет: Вы должны попытаться написать функцию таким образом, что он имеет только одну точку выхода, я люблю использовать goto для что, несмотря на то, что религиозные программисты верят в goto, он делает ваш код более понятным и совместимым.

То, что я имею в виду, вы можете иметь ярлык, где вы возвращаете код ошибки из функции и делать все очистки, что-то вроде этого

int function() 
{ 
    /* set errorCode */ 
    if (firstFailureCondition == 1) 
     goto cleanup; 
    if (secondFailureCondition == 1) 
     goto cleanup; 
       . 
       . 
       . 
    if (nthFailureCondition == 2) 
     goto cleanup; 
cleanup: 
    /* do your cleanup */ 
    return errorCode; 
} 
+0

спасибо. free (* buffer) находится в readWav при возникновении ошибки - в противном случае возникает необходимость освободить .... если это когда и где? Почему нет необходимости освобождать буфер, если программа работает нормально. Я думаю, если она будет освобождена, то основной получил NULL? – user4504270

+0

В readWav, почему нужен ((sRate == NULL) || (numFrames == NULL) || (buffer == NULL))? – user4504270

+0

Эта строка была перемещена вниз - * sRate = sndInfo.samplerate - интересно, почему? Кроме того, я не могу вернуть «sndInfo.samplerate» - мне придется назначить его * sRate, а затем вернуться - почему? – user4504270

3

В C все аргументы передаются по значению, так что если вы хотите по-исх-подобный аргумент вы должны передать указатель. И так как вы хотите вернуть float*, вам необходимо пройти float**.

Фактически вы проходите это, но вы не используете его правильно (пожалуйста, используйте -Wall или эквивалент для вашего компилятора, чтобы включить предупреждения).

Код хотел бы более или менее, как это:

int readWav(const char *fname, long *numFrames, int *sRate, float **buffer) 
{ 
    *buffer = malloc(...); 
    //if you do not feel comfortable writing `*buffer` everywhere: 
    float *data = *buffer; 
    ///.... 
    *numFrames = sf_readf_float(...); 
    ///.... 
    *sRate = sndInfo.samplerate; 
    ///.... 
} 

int main() 
{ 
    long nSamples; 
    int sRates; 
    float *datas; 
    ret = readWav(argv[1], &nSamples, &sRates, &datas); 
    //... 
} 
+2

Основываясь на коде 'readWav', я подозреваю, что' nSamples' и 'sRates' должны быть переданы ему по ссылке. – Squirrel

+0

@Squirrel: Да, вы правы. Я не читал первые строки ... Я добавлю это к ответу. – rodrigo

+0

Какова логика вашего утверждения «float * data = * buffer;»? – user4504270

Смежные вопросы