проблема в возвращении адреса массива из функции в C - PullRequest
0 голосов
/ 26 апреля 2020

Приходит ошибка "конфликтующие типы", так что я могу сделать, и предпочитаю хорошую альтернативу для этого. Основная проблема заключается в возврате массива из функции

#include<stdio.h>
int* freqofchar(char);
int main()
{

    char str[100];
    printf("Enter a sentence below :\n");
    gets(str);
    int* p = freqofchar(str);
    for(int i=0;i<128;i++){
        if(*p>0){
            printf("%c occurred %d times\n",(char) i , *p++);
        }
    }
    return 0;
}
int* freqofchar(char str[]){
    int freq[128] = {0};
    for(int i = 0;str[i] != '\0';i++){
        freq[ str[i] ]++;
    }
    return freq;
}

Ответы [ 4 ]

1 голос
/ 26 апреля 2020

Ошибка, которую вы видите из-за несоответствия функции прототип и ее фактического определения .

Однако у вас есть и другие проблемы:

Функция
  • gets была удалена из стандарта C (с тех пор) по уважительной причине и ни в коем случае не должна использоваться. Вместо этого вы можете использовать fgets для чтения ввода. Но вам нужно удалить символ новой строки, если fgets читает его.

  • Вы возвращаете указатель на локальную переменную, время жизни которой недопустимо после возврата из функции freqofchar , который является неопределенным поведением. Вместо этого вы можете передать другой аргумент. Как правило, вы можете рассмотреть динамическое распределение c (например, через malloc), но в этом случае - вам нужен только небольшой массив - массив, локальный по отношению к основной функции, который имеет automati c продолжительность хранения и, следовательно, его время жизни действительно в течение main(), и его можно безопасно передавать в функцию freqofchar, не считая его недействительным или отменяющим, так как время жизни объекта (freq являющееся объектом, указанным здесь) все еще действует, когда он используется в freqofchar() - здесь лучше подходит.

Вот как выглядит фиксированное решение:

#include<stdio.h>
#include<string.h>

void freqofchar(char*, int*);

int main()
{
    char str[100] = {0};
    int freq[256] = {0};

    printf("Enter a sentence below :\n");
    fgets(str, sizeof str, stdin);

    /* Remove the newline if present. */
    char *p = strchr(str, '\n');
    if (p) *p = '\0';

    freqofchar(str, freq);

    for(size_t i = 0;i < sizeof freq; i++) {
        if(freq[i]) {
            printf("%c occurred %d times\n", i, freq[i]);
        }
    }
    return 0;
}

void freqofchar(char str[], int freq[])
{
    for(int i = 0;str[i] != '\0';i++) {
        freq[ str[i] ]++;
    }
}
1 голос
/ 26 апреля 2020

У вас есть 2 проблемы:

1) конфликтующие типы:

int* freqofchar(char)

в объявлении, но

int* freqofchar(char str[])

в определении.

2) Вы возвращаете freq, размещенный в стеке, из freqofchar

0 голосов
/ 26 апреля 2020

Параметр функции объявляется в объявлении функции как имеющий тип char

int* freqofchar(char);
                ^^^^^

Но в объявлении функции это же определение

int* freqofchar(char str[]){
                ^^^^^^^^^ 

. Параметр объявлен как имеющий тип char [] (который корректируется компилятором на тип char *).

Эта опечатка является причиной сообщения компилятора.

Но в любом если функция должна быть объявлена ​​как минимум как

unsigned int * freqofchar( const char [] );

То есть нет смысла определять частоты как имеющие целочисленный тип со знаком, а параметр должен иметь квалификатор const, поскольку переданная строка не изменяется в функции.

Программа имеет неопределенное поведение, поскольку функция возвращает указатель на локальный массив с автоматическим c сроком хранения, который не будет активен после выхода из функции.

int* freqofchar(char str[]){
    int freq[128] = {0};
    //...
    return freq;
}

Вы должны либо выделить массив динамически, либо объявить его с помощью спецификатора хранилища static. В последнем случае вам нужно каждый раз при вызове функции сбрасывать элементы массива на нули.

Функция gets является небезопасной функцией и больше не поддерживается стандартом C. Вместо этого используйте стандартную C функцию fgets.

Вот демонстрационная программа.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

unsigned int* freqofchar( const char *);

int main( void )
{
    enum { N = 100 };
    char str[N];
    str[0] = '\0';

    printf( "Enter a sentence below : " );

    fgets( str, N, stdin );

    // remove the appended new line character '\n'
    str[ strcspn( str, "\n" ) ] = '\0';

    unsigned int *p = freqofchar( str );

    for ( size_t i = 0; i < 128; i++ )
    {
        if ( p[i] )
        {
            printf( "'%c' occurred %u times\n", ( char )i , p[i] );
        }
    }

    free( p );

    return 0;
}

unsigned int * freqofchar( const char str[] )
{
    enum { N = 128 };

    unsigned int *freq = calloc( N, sizeof( unsigned int ) );

    while ( *str ) ++freq[ ( size_t )*str++ ];

    return freq;
}

Ее вывод может выглядеть как

Enter a sentence below : Hello World!
' ' occurred 1 times
'!' occurred 1 times
'H' occurred 1 times
'W' occurred 1 times
'd' occurred 1 times
'e' occurred 1 times
'l' occurred 3 times
'o' occurred 2 times
'r' occurred 1 times

Если определить функция со спецификатором хранения stati c, тогда ее определение может выглядеть следующим образом.

#include <stdio.h>
#include <string.h>

unsigned int* freqofchar( const char *);

int main( void )
{
    enum { N = 100 };
    char str[N];
    str[0] = '\0';

    printf( "Enter a sentence below : " );

    fgets( str, N, stdin );

    // remove the appended new line character '\n'
    str[ strcspn( str, "\n" ) ] = '\0';

    unsigned int *p = freqofchar( str );

    for ( size_t i = 0; i < 128; i++ )
    {
        if ( p[i] )
        {
            printf( "'%c' occurred %u times\n", ( char )i , p[i] );
        }
    }

    return 0;
}

unsigned int * freqofchar( const char str[] )
{
    enum { N = 128 };

    static unsigned int freq[N];

    memset( freq, 0, N * sizeof( unsigned int ) );

    while ( *str ) ++freq[ ( size_t )*str++ ];

    return freq;
}
0 голосов
/ 26 апреля 2020
  1. Вы делаете одну из самых распространенных ошибок в C программировании. Вы возвращаете указатель на объект, который не существует после возврата функции.

возможные решения

a. используйте динамически выделенную память

int* freqofchar(char *str)
{
    int *freq = malloc(128 * sizeof(*freq)); // or if you want to zero it calloc

    /* ... */    
    return freq;
}

, но вам нужно освободить выделенную память, когда она не нужна.

б. используйте массив stati c или глобальный массив

int* freqofchar(char *str)
{
    static freq[128];

    /* ... */    
    return freq;
}

или

static freq[128];

int* freqofchar(char *str)
{

    /* ... */    
    return freq;
}

Недостатки этого решения: функция не реентерабельна, массив freq не может быть передан в asyn c Задача и функции, как это может быть изменено, если функция вызывается снова. Инициализация происходит только один раз перед первым вызовом функции.

c. Оберните его в объединение или структуру и верните весь объект

struct freqstruct {
    int freq[128];
};

struct freqstruct freqofchar(char *str)
{
    struct freqstruct freq = {0};

    /* ... */    
    return freq;
}

Недостаток - весь массив, помещенный в struct, копируется. Это не очень память и производительность.

Ваше определение не соответствует объявлению функции. Это показывает, что вы приложили недостаточно усилий.
int* freqofchar(char *str)

int* freqofchar(char *str)
{
     /* ... */
}

или - но мне лично не нравится эта запись, поскольку она заставляет начинающих думать, что массив передается не по указателю.

int* freqofchar(char str[])

int* freqofchar(char str[])
{
     /* ... */
}
Эта функция не является постоянной - параметр str должен быть const char *str или const char str[]
...