Почему моя возвращаемая строка работает только в gcc-компиляторе? [Дубликат]

Я не мог заставить вышеупомянутые записи делать то, что было после.

После того, как я играл с другими ответами, я сделал это.

Для этого объекта:

var myObj = {
    pageURL    : "BLAH",
    emailBox   : {model:"emailAddress", selector:"#emailAddress"},
    passwordBox: {model:"password"    , selector:"#password"}
};

... этот код:

// Get every value in the object into a separate array item ...
function buildArray(p_MainObj, p_Name) {
    var variableList = [];
    var thisVar = "";
    var thisYes = false;
    for (var key in p_MainObj) {
       thisVar = p_Name + "." + key;
       thisYes = false;
       if (p_MainObj.hasOwnProperty(key)) {
          var obj = p_MainObj[key];
          for (var prop in obj) {
            var myregex = /^[0-9]*$/;
            if (myregex.exec(prop) != prop) {
                thisYes = true;
                variableList.push({item:thisVar + "." + prop,value:obj[prop]});
            }
          }
          if ( ! thisYes )
            variableList.push({item:thisVar,value:obj});
       }
    }
    return variableList;
}

// Get the object items into a simple array ...
var objectItems = buildArray(myObj, "myObj");

// Now use them / test them etc... as you need to!
for (var x=0; x < objectItems.length; ++x) {
    console.log(objectItems[x].item + " = " + objectItems[x].value);
}

... производит это в консоль:

myObj.pageURL = BLAH
myObj.emailBox.model = emailAddress
myObj.emailBox.selector = #emailAddress
myObj.passwordBox.model = password
myObj.passwordBox.selector = #password
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 26 August 2018 в 10:51
поделиться

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

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 26 August 2018 в 10:51
поделиться

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

    #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 26 August 2018 в 10:51
поделиться

Обработка 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 26 August 2018 в 10:51
поделиться

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

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 26 August 2018 в 10:51
поделиться

Вы можете сделать это с помощью памяти кучи (через вызов 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 26 August 2018 в 10:51
поделиться

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

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 26 August 2018 в 10:51
поделиться

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

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 26 August 2018 в 10:51
поделиться
Другие вопросы по тегам:

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