Yo soy relativamente nuevo en C y necesito un poco de ayuda con los métodos de tratar con matrices. Viniendo de programación Java, estoy acostumbrado a ser capaz de decir int [] method()con el fin de devolver una matriz. Sin embargo, he descubierto que con C tienes que utilizar punteros para las matrices cuando regrese a ellos. Un nuevo programador, yo realmente no entiendo de todo esto, aún con los muchos foros que he visto.

Básicamente, estoy tratando de escribir un método que devuelve una matriz de char en C. voy a proporcionar el método (vamos a llamarlo returnArray) con una matriz. Se va a crear una nueva matriz a partir de la matriz anterior y devuelve un puntero a él. Sólo necesito un poco de ayuda sobre cómo obtener este comenzó y cómo leer el puntero una vez que se envía fuera de la matriz. Cualquier ayuda que explica esto es apreciado.

Propuesta de Código de Formato para la Matriz devuelve la Función

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

De llamada de la Función

int main(){
 int i=0;
 char array []={1,0,0,0,0,1,1};
 char arrayCount=0;
 char* returnedArray = returnArray(&arrayCount); ///is this correct?
 for (i=0; i<10;i++)
  printf(%d, ",", returnedArray[i]);  //is this correctly formatted?
}

No he probado este pero como mi compilador de C no está funcionando en el momento, pero me gustaría averiguarlo

  • Es el regreso de la matriz de un tamaño conocido, como se indica en el ejemplo de código? La única otra gotcha puedo ver, además de la pila de temas mencionados en las respuestas es que si su matriz es de un tamaño indeterminado, dada la forma en que los punteros/matrices de trabajo en C, usted no sabe lo grande que es.
  • Sí, sé que el tamaño de la incomming matriz en todo momento. El tamaño de la entrada y la salida de la matriz no lo cambio.
  • El Desarrollo del Lenguaje C* – bell-labs.com/usr/dmr/www/chist.html
InformationsquelleAutor user1506919 | 2012-07-25

8 Comentarios

  1. 191

    Usted no puede devolver las matrices de funciones en C. Usted también no puede (no debe) hacer esto:

    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 se crea con el almacenamiento automático de la duración y las referencias a la misma será válido una vez que sale a declarar su alcance, es decir, cuando se devuelve la función.

    Deberá asignar dinámicamente la memoria dentro de la función o de llenar un preasignados búfer proporcionado por el autor de la llamada.

    Opción 1:

    asignar dinámicamente la memoria dentro de la función (llamada responsable de la cancelación de la asignación 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;
    }

    Llaman así:

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

    Opción 2:

    llenar un preasignados búfer proporcionado por la persona que llama (caller asigna buf y pasa a la función)

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

    Y lo llaman así:

    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)
    }
    • Opción 3: (una matriz estática)
    • Sí, dejé que fuera a propósito para mantener las cosas simples, pero sí, puede devolver un puntero a los datos estáticos declarado desde dentro de la función.
    • Me gusta tu primer método. Así que, ¿cómo iba yo haga referencia ret en mi principal?
    • Yo realmente preferiría la opción 2 ya que es claro que asigna y cancela la asignación de memoria, pero voy a añadir un ejemplo para usted.
    • S. En el segundo ejemplo, donde hace ret vienen? En caso de que buf?
    • Sí, lo siento, error tipográfico
    • Opción 4: el Regreso de un struct que contiene una matriz de tamaño fijo.
    • Usted dijo que una vez que la función devuelve la matriz se convierte en inválida. Pero, esto también es lo que sucede con cualquier variable local. Así que, ¿por qué todavía una función puede devolver un primitivo(int, por ejemplo) y no una matriz?
    • Opción 5: Devolver una unión que contiene una matriz de tamaño fijo.
    • Sencillamente, porque las matrices son extraños.
    • Porque está devolviendo una copia de ese int. Usted no puede devolver un array, el idioma no lo permite. Así se puede devolver un puntero a la mala memoria. Una mejor analogía sería devolver un int* que apunta a un int local a la función.
    • Opción 5: Estática puntero a un búfer asignado dinámicamente que se reasignaron en caso de ser necesario. Mismo fuera de uso como la Opción 3, pero no pone un límite en la longitud de la cadena que pueden ser devueltos.
    • Lo que tengo que hacer esto? char devuelve[10]; char* ptr = devueltos; return ptr ?
    • mismo problema. usted está devolviendo un puntero a una matriz que no es válida una vez que sale de la función.
    • Dejando fuera las matrices estáticas no está justificada. Algunas variedades de C no permiten a los punteros. Creo que GLSL.
    • Sí, por supuesto, usted puede regresar un puntero de datos estáticos. La respuesta es fácil derivar si usted tiene una comprensión conceptual de la duración de los objetos. El problema aquí se deriva de la OP tratando de devolver un puntero a un local. Que es el problema, y que tiene que ver con la duración de los objetos, todas contestadas anteriormente.
    • Realmente me gustaría añadir la * sizeof *p aquí… ya que este se utiliza de forma genérica

  2. 24

    C tratamiento de matrices es muy diferentes de Java, y usted tendrá que ajustar su pensamiento en consecuencia. Las matrices en C no son objetos de primera clase (es decir, una matriz de expresión no conserva es «matriz-ness» en la mayoría de los contextos). En C, una expresión del tipo «N-elemento de la matriz de T» se convierte de forma implícita («decadencia») a una expresión del tipo «puntero a T«, excepto cuando el vector de expresión es un operando de la sizeof o unario & operadores, o si la matriz de expresión es un literal de cadena se utiliza para inicializar otra matriz en una declaración.

    Entre otras cosas, esto significa que no se puede pasar un array de expresión para una función, y han recibido como un tipo de matriz; esta función recibe un puntero de tipo:

    void foo(char *a, size_t asize)
    {
      //do something with a
    }
    
    int bar(void)
    {
      char str[6] = "Hello";
      foo(str, sizeof str);
    }

    En la llamada a foo, la expresión str se convierte de tipo char [6] a char *, es por eso que el primer parámetro de foo se declara char *a en lugar de char a[6]. En sizeof str, ya que la matriz de expresión es un operando de la sizeof operador, es que no se convierten a un tipo de puntero, por lo que obtener el número de bytes de la matriz (6).

    Si estás realmente interesado, puede leer Dennis Ritchie, El Desarrollo del Lenguaje C para entender de donde este tratamiento viene.

    El resultado de todo esto es que las funciones no pueden volver tipos de matriz, lo cual está bien ya que la matriz de expresiones no puede ser el objetivo de una tarea, ya sea.

    El método más seguro es el de la persona que llama para definir la matriz, y de paso la dirección y el tamaño de la función que se supone que va a escribir en él:

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

    Otro método es la de la función para asignar la matriz de forma dinámica y devolver el puntero y el tamaño:

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

    En este caso, la persona que llama es responsable de la cancelación de la asignación de la matriz con el free función de la librería.

    Nota que dst en el código anterior es un simple puntero a char, no un puntero a una matriz de char. C del puntero y la matriz semántica son tales que se puede aplicar el operador de subíndice [] a una expresión de tipo array de o tipo de puntero; ambos src[i] y dst[i] tendrán acceso a la i‘ésimo elemento de la matriz (aunque sólo src tiene tipo de matriz).

    Que puede declarar un puntero a un N-elemento de la matriz de T y hacer algo similar:

    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]);
      ...
    }

    Varios inconvenientes con los de arriba. Primero de todos, las versiones anteriores de C esperar SOME_SIZE a ser una constante en tiempo de compilación, lo que significa que la función de sólo trabajar con una matriz de tamaño. En segundo lugar, usted tiene que eliminar el puntero antes de aplicar el subíndice, que abarrota el código. Punteros a arrays funcionan mejor cuando usted está tratando con matrices multidimensionales.

    • Su vínculo con el desarrollo de «la C» se ha roto… parece que debería directo con nosotros aquí: bell-labs.com/usr/dmr/www/chist.html
    • Lo bar recibe es un puntero, no una matriz. En el contexto de un parámetro de la función de la declaración, T a[N] y T a[] son tratados como T *a.
    • Estás en lo cierto! Por alguna razón pensé vectores de tamaño fijo se aprobaron en la pila. Recuerdo que en una ocasión, hace muchos años, cuando me enteré de que una matriz del tamaño que se especifica en el parámetro de la firma, pero me debe haber sido confundido.
    • en segundo código de la parte primera línea:void returnArray(const char *srcArray, size_t srcSize, char *dstArray, char dstSize) último parámetro debe estar en size_t tipo no char.
  3. 8

    Cómo acerca de esta deliciosa mal implementación?

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

    principal.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;
    }
    • Esta es una deliciosa suficiente para surgió mi curiosidad. ¿Puedes explicar un poco más lo que hizo hasta allí, o tal vez, sugerir una lectura a esta exquisitez se llama? Gracias de antemano.
    • Tenga en cuenta que hay sime errores potenciales en esto, era sólo una prueba de Concepto. Dicho esto, el truco está volviendo un struct como una matriz de contenedores/objeto. Piense en ello como un C++ std::vector. El preprocesador se ampliará el int versión de este a struct intArray { int* contents; int size; };.
    • Me gusta el enfoque. pro: esta es la solución genérica; contra: intensivo de memoria de la solución. No es óptima para los vectores de la ostenta tamaños. De todos modos, este puede ser optimizado con la inicial de la asignación de tamaño. Me gustaría definitley agregar algunos asignación de verificación. Muy buena propuesta para empezar 🙂
    • Orientado a objetos-esk encantadora mezcla de puré. Me gusta.
  4. 6

    No estoy diciendo que esta es la mejor solución o la solución preferida para el problema dado. Sin embargo, puede ser útil recordar que las funciones pueden devolver estructuras. Aunque las funciones no devuelven matrices, matrices pueden ser envueltos en las estructuras y la función puede devolver la estructura de ese modo la realización de la matriz con ella. Esto funciona de longitud fija matrices.

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

    Invito a los comentarios sobre las fortalezas y debilidades de esta técnica. No me he molestado en hacerlo.

  5. 6

    En su caso, se crea una matriz en la pila y una vez que abandona el ámbito de la función, la matriz será desasignado. En su lugar, cree una asignación dinámica de matriz y devuelve un puntero a él.

    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);
    
    }
    • No hay new operador en C. Que es C++.
    • Y sizeof(char) está garantizado para ser 1, por lo que en este caso se puede colocar un poco de malloc.
    • ok, así que Si quería imprimir el contenido de la nueva matriz, podría acabo de hacer mi ‘printf’ declaración, pero sustituir el ‘returnedArray’ con ‘arr’?
    • No llamar a la función correctamente (sólo un argumento cuando la firma requiere de dos).
    • Que está pasando en &arr. Desea arr a ser un char *, y que se apruebe en el uso de arr.
    • de acuerdo a su código está pasando un array que almacena en la pila
    • Oh, my bad. Luego arr debe ser un char[], y todavía se pasa por arr.
    • es del tipo de pointer to array of char, i.e., char (*arr)[N], no pointer to char. La matriz se va a desintegrar en un puntero, no toma la dirección.
    • Sí gracias, corregido.

  6. 4

    Usted puede hacer uso de la memoria heap (a través de malloc() invocación) al igual que otras respuestas que se informa aquí, pero siempre hay que gestionar la memoria (uso libre() función cada vez que usted llame a su función).
    También se puede hacer con una matriz estática:

    char* returnArrayPointer() 
    {
    static char array[SIZE];
    
    //do something in your array here
    
    return array; 
    }

    Usted puede utilizarlo sin tener que preocuparse acerca de la gestión de la memoria.

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

    En este ejemplo, usted debe utilizar la palabra clave static en la definición de la matriz para establecer la aplicación largo de la matriz de toda la vida, por lo que no serán destruidos después de la instrucción return.
    Por supuesto, en esta manera de ocupar el TAMAÑO de bytes en la memoria para toda la vida de la aplicación, por lo que su tamaño correctamente!

    • sí, tienes razón. Gracias
  7. 2

    Su método devolverá una pila local variable que va a fallar mal. Para devolver una matriz, crear uno fuera de la función, pasan por su dirección en la función, a continuación, modificar, o crear una matriz en la pila y volver de esa variable. Ambos van a trabajar, pero la primera no requiere de asignación dinámica de memoria para que funcione correctamente.

    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);
    }
  8. 0

    Puede utilizar un código como este:

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

    Al hacer esto, la memoria debe ser luego liberado, pasando la dirección a la libre.

    Hay otras opciones. Una rutina puede devolver un puntero a un array (o parte de un array) que es parte de alguna estructura existente. La persona que llama puede pasar un array, y la rutina simplemente escribe en la matriz, en lugar de asignar espacio para una nueva matriz.

Dejar respuesta

Please enter your comment!
Please enter your name here