Поиск самого длинного слова в массиве 2D-символов [дубликат]

Используйте модуль. Он импортируется только один раз. Определите в нем глобальные переменные - они будут атрибутами singleton. Добавьте некоторые функции - методы «singleton».

104
задан Ashish Ahuja 12 January 2016 в 13:38
поделиться

8 ответов

Вы не можете возвращать массивы из функций из C. Вы также не можете (не должны) делать это:

char *returnArray(char array []){
 char returned [10];
 //methods to pull values from array, interpret them, and then create new array
 return &(returned[0]); //is this correct?
} 

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

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

Вариант 1:

динамически выделяет память внутри функции (вызывающий абонент, ответственный за освобождение ret)

char *foo(int count) {
    char *ret = malloc(count);
    if(!ret)
        return NULL;

    for(int i = 0; i < count; ++i) 
        ret[i] = i;

    return ret;
}

Вызывает его так:

int main() {
    char *p = foo(10);
    if(p) {
        // do stuff with p
        free(p);
    }

    return 0;
}

Вариант 2:

заполнить предварительно выделенный буфер, предоставленный вызывающим абонентом (абонент выделяет buf и переходит к функции)

void foo(char *buf, int count) {
    for(int i = 0; i < count; ++i)
        buf[i] = i;
}

И назовите его так :

int main() {
    char arr[10] = {0};
    foo(arr, 10);
    // No need to deallocate because we allocated 
    // arr with automatic storage duration.
    // If we had dynamically allocated it
    // (i.e. malloc or some variant) then we 
    // would need to call free(arr)
}
156
ответ дан sazzad 21 August 2018 в 20:03
поделиться
  • 1
    Вариант 3: (статический массив) – moooeeeep 25 July 2012 в 19:55
  • 2
    @moooeeeep: Да, я оставил это намеренно, чтобы все было просто, но да, вы можете вернуть указатель на статические данные, объявленные из функции. – Ed S. 25 July 2012 в 19:56
  • 3
    @ user1506919: Я бы предпочел вариант 2, так как ясно, кто выделяет и освобождает память, но я добавлю пример для вас. – Ed S. 25 July 2012 в 20:02
  • 4
    Вариант 4: Верните структуру, содержащую массив фиксированного размера. – Todd Lehman 21 May 2015 в 00:10
  • 5
    Вы сказали, что после возвращения функции массив становится недействительным. Но это также происходит с любой локальной переменной. Итак, почему все еще функция может возвращать примитив (int, например), а не массив? – CrazySynthax 1 October 2016 в 15:02

Вы можете использовать такой код:

char *MyFunction(some arguments...)
{
    char *pointer = malloc(size for the new array);
    if (!pointer)
        An error occurred, abort or do something about the error.
    return pointer; // Return address of memory to the caller.
}

Когда вы это сделаете, память должна быть освобождена позже, передав адрес бесплатно.

Есть другие варианты , Подпрограмма может возвращать указатель на массив (или часть массива), который является частью некоторой существующей структуры. Вызывающий может передать массив, и программа просто записывает в массив, а не выделяет пространство для нового массива.

0
ответ дан Eric Postpischil 21 August 2018 в 20:03
поделиться

Я не говорю, что это лучшее решение или предпочтительное решение данной проблемы. Однако может быть полезно помнить, что функции могут возвращать структуры. Хотя функции не могут возвращать массивы, массивы могут быть обернуты в структуры, и функция может возвращать структуру, тем самым перенося массив с ней. Это работает для массивов с фиксированной длиной.

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

    typedef
    struct 
    {
        char v[10];
    } CHAR_ARRAY;



    CHAR_ARRAY returnArray(CHAR_ARRAY array_in, int size)
    {
        CHAR_ARRAY returned;

        /*
        . . . methods to pull values from array, interpret them, and then create new array
        */

        for (int i = 0;  i < size; i++ )
            returned.v[i] = array_in.v[i] + 1;

        return returned; // Works!
    } 




    int main(int argc, char * argv[])
    {
        CHAR_ARRAY array = {1,0,0,0,0,1,1};

        char arrayCount = 7;

        CHAR_ARRAY returnedArray = returnArray(array, arrayCount); 

        for (int i = 0; i < arrayCount; i++)
            printf("%d, ", returnedArray.v[i]);  //is this correctly formatted?

        getchar();
        return 0;
    }

Я предлагаю комментарии о сильных и слабых сторонах этого метода. Я не удосужился это сделать.

4
ответ дан Indinfer 21 August 2018 в 20:03
поделиться

Обработка C массивами очень отличается от Java, и вам придется соответствующим образом скорректировать свое мышление. Массивы в C не являются первоклассными объектами (т. Е. Выражение массива не сохраняет его «массивность» в большинстве контекстов). В C выражение типа «N-элементный массив из T» будет неявно преобразовано («распад») в выражение типа «указатель на T», за исключением случаев, когда выражение массива является операндом sizeof или унарных & операторов, или если выражение массива является строковым литералом, используемым для инициализации другого массива в объявлении.

Между прочим, это означает, что вы не можете передать выражение массива функции и получить его как тип массива ; функция фактически получает тип указателя:

void foo(char *a, size_t asize)
{
  // do something with a
}

int bar(void)
{
  char str[6] = "Hello";
  foo(str, sizeof str);
}

В вызове foo выражение str преобразуется из типа char [6] в char *, поэтому первый параметр foo объявлен char *a вместо char a[6]. В sizeof str, поскольку выражение массива является операндом оператора sizeof, оно не преобразуется в тип указателя, поэтому вы получаете количество байтов в массиве (6).

Если вы заинтересованы в действительно , вы можете прочитать Dennis Ritchie's «Развитие языка C» , чтобы понять, откуда взялось это лечение.

Результатом является то, что функции не могут возвращать типы массивов, что отлично, поскольку выражения массива также не могут быть объектом назначения.

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

void returnArray(const char *srcArray, size_t srcSize, char *dstArray, char dstSize)
{
  ...
  dstArray[i] = some_value_derived_from(srcArray[i]);
  ...
}

int main(void)
{
  char src[] = "This is a test";
  char dst[sizeof src];
  ...
  returnArray(src, sizeof src, dst, sizeof dst);
  ...
}

Другой метод функция для распределения массива динамически и возврата указателя и размера:

char *returnArray(const char *srcArray, size_t srcSize, size_t *dstSize)
{
  char *dstArray = malloc(srcSize);
  if (dstArray)
  {
    *dstSize = srcSize;
    ...
  }
  return dstArray;
}

int main(void)
{
  char src[] = "This is a test";
  char *dst;
  size_t dstSize;

  dst = returnArray(src, sizeof src, &dstSize);
  ...
  free(dst);
  ...
}

В этом случае вызывающий отвечает за освобождение массива с помощью функции библиотеки free.

Обратите внимание, что dst в приведенном выше коде является простым указателем на char, а не указателем на массив из char. C-указатель и семантика массива таковы, что вы можете применить индексный оператор [] к выражению типа указателя типа или ; оба src[i] и dst[i] будут обращаться к i -му элементу массива (хотя только src имеет тип массива).

Вы можете объявить указатель на N-элементный массив из T и сделать что-то подобное:

char (*returnArray(const char *srcArr, size_t srcSize))[SOME_SIZE]
{
  char (*dstArr)[SOME_SIZE] = malloc(sizeof *dstArr);
  if (dstArr)
  {
    ...
    (*dstArr)[i] = ...;
    ...
  }
  return dstArr;
}

int main(void)
{
  char src[] = "This is a test";
  char (*dst)[SOME_SIZE];
  ...
  dst = returnArray(src, sizeof src);
  ...
  printf("%c", (*dst)[j]);
  ...
}

Несколько недостатков с приведенным выше. Прежде всего, более старые версии C ожидают, что SOME_SIZE будет константой времени компиляции, что означает, что функция будет работать только с одним размером массива. Во-вторых, вы должны разыменовать указатель перед применением индекса, который загромождает код. Указатели на массивы работают лучше, когда вы имеете дело с многомерными массивами.

20
ответ дан John Bode 21 August 2018 в 20:03
поделиться
  • 1
    Ваша ссылка на "развитие C & quot; сломался ... похоже, что он должен направить нас сюда: bell-labs.com/usr/dmr/www/chist.html – Dr.Queso 25 March 2016 в 03:09
  • 2
    @Kundor: То, что bar получает, является указателем, а не массивом. В контексте объявления параметра функции T a[N] и T a[] рассматриваются как T *a. – John Bode 14 April 2016 в 12:16
  • 3
    @JohnBode: Ты прав! По какой-то причине я думал, что массивы фиксированного размера передаются в стек. Я вспоминаю случай, много лет назад, когда обнаружил, что размер массива должен быть указан в сигнатуре параметра, но я, должно быть, был смущен. – Kundor 14 April 2016 в 13:22

В вашем случае вы создаете массив в стеке, и как только вы покинете область действия, массив будет освобожден. Вместо этого создайте динамически выделенный массив и верните указатель на него.

char * returnArray(char *arr, int size) {
    char *new_arr = malloc(sizeof(char) * size);
    for(int i = 0; i < size; ++i) {
        new_arr[i] = arr[i];
    }
    return new_arr;
}

int main() {

    char arr[7]= {1,0,0,0,0,1,1};
    char *new_arr = returnArray(arr, 7);

    // don't forget to free the memory after you're done with the array
    free(new_arr);

}
6
ответ дан Man of One Way 21 August 2018 в 20:03
поделиться
  • 1
    В C. нет оператора new. Это C ++. – Eric Postpischil 25 July 2012 в 19:51
  • 2
    И sizeof(char) гарантированно 1, поэтому в этом случае вы можете отбросить этот бит с malloc. – Ed S. 25 July 2012 в 19:54
  • 3
    ok so Если бы я хотел распечатать содержимое нового массива, могу ли я просто сделать свой оператор printf, но вместо 'returnArray' заменить 'arr'? – user1506919 25 July 2012 в 19:54
  • 4
    Вы не вызываете функцию должным образом (только один аргумент, когда подпись требует два). – Ed S. 25 July 2012 в 19:54
  • 5
    Вы проходите через &arr. Вы хотите arr быть char * и передать его с помощью arr. – chris 25 July 2012 в 19:56

Вы можете сделать это с помощью памяти кучи (через вызов malloc () ), как и другие ответы, описанные здесь, но вы всегда должны управлять памятью (используйте функцию free () каждый раз, когда вы вызываете свою функцию). Вы также можете сделать это со статическим массивом:

char* returnArrayPointer() 
{
static char array[SIZE];

// do something in your array here

return array; 
}

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

int main() 
{
char* myArray = returnArrayPointer();
/* use your array here */
/* don't worry to free memory here */
}

В этом примере вы должны использовать статическое ключевое слово в определение массива, чтобы установить продолжительность жизни массива в приложении, поэтому он не будет уничтожен после оператора return. Разумеется, таким образом вы занимаете байты SIZE в своей памяти на весь срок службы приложения, поэтому его размер будет правильным!

3
ответ дан mengo 21 August 2018 в 20:03
поделиться

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

void returnArray(int size, char *retArray)
{
  // work directly with retArray or memcpy into it from elsewhere like
  // memcpy(retArray, localArray, size); 
}

#define ARRAY_SIZE 20

int main(void)
{
  char foo[ARRAY_SIZE];
  returnArray(ARRAY_SIZE, foo);
}
2
ответ дан Michael Dorgan 21 August 2018 в 20:03
поделиться

Как насчет этой невероятно злой реализации?

array.h

#define IMPORT_ARRAY(TYPE)    \
    \
struct TYPE##Array {    \
    TYPE* contents;    \
    size_t size;    \
};    \
    \
struct TYPE##Array new_##TYPE##Array() {    \
    struct TYPE##Array a;    \
    a.contents = NULL;    \
    a.size = 0;    \
    return a;    \
}    \
    \
void array_add(struct TYPE##Array* o, TYPE value) {    \
    TYPE* a = malloc((o->size + 1) * sizeof(TYPE));    \
    TYPE i;    \
    for(i = 0; i < o->size; ++i) {    \
        a[i] = o->contents[i];    \
    }    \
    ++(o->size);    \
    a[o->size - 1] = value;    \
    free(o->contents);    \
    o->contents = a;    \
}    \
void array_destroy(struct TYPE##Array* o) {    \
    free(o->contents);    \
}    \
TYPE* array_begin(struct TYPE##Array* o) {    \
    return o->contents;    \
}    \
TYPE* array_end(struct TYPE##Array* o) {    \
    return o->contents + o->size;    \
}

main.c

#include <stdlib.h>
#include "array.h"

IMPORT_ARRAY(int);

struct intArray return_an_array() {
    struct intArray a;
    a = new_intArray();
    array_add(&a, 1);
    array_add(&a, 2);
    array_add(&a, 3);
    return a;
}

int main() {
    struct intArray a;
    int* it;
    int* begin;
    int* end;
    a = return_an_array();
    begin = array_begin(&a);
    end = array_end(&a);
    for(it = begin; it != end; ++it) {
        printf("%d ", *it);
    }
    array_destroy(&a);
    getchar();
    return 0;
}
7
ответ дан Snaipe 21 August 2018 в 20:03
поделиться
  • 1
    Это дьявольски восхитительно, чтобы вызвать мое любопытство. Можете ли вы объяснить немного больше, что вы там делали, или, возможно, предложить прочитать эту восхитительность, которую вы называете? Заранее спасибо. – Unheilig 8 January 2014 в 21:49
  • 2
    @Unheilig - Обратите внимание, что в этом есть потенциальные ошибки, это просто доказательство концепции. Тем не менее, трюк возвращает struct как контейнер / объект массива. Подумайте об этом, как C ++ std :: vector. Препроцессор расширил версию int до struct intArray { int* contents; int size; };. – pyrospade 9 January 2014 в 06:05
  • 3
    Мне нравится этот подход. pro: это общее решение; contra: память. Не оптимален для векторов размеров королей. Во всяком случае, это может быть модернизировано с распределением по собственному размеру. Я бы определил некоторую проверку распределения. Очень хорошее предложение, чтобы начать с :) – urkon 4 January 2018 в 14:47
  • 4
    Объектно-ориентированный-esk prepossessing mix-mash. Мне это нравится. – Jack Giffin 22 January 2018 в 04:24
Другие вопросы по тегам:

Похожие вопросы: