Cuando se debe a un doble direccionamiento indirecto se utiliza en C? ¿Alguien puede explicar con un ejemplo?

Lo que yo sé es que un doble direccionamiento indirecto es un puntero a un puntero. ¿Por qué necesito un puntero a un puntero?

  • Tenga cuidado; la frase «doble puntero» también se refiere al tipo double*.
  • A tomar nota: la respuesta a esta pregunta es diferente para C y C++ – no agregue c+ etiqueta a este muy vieja pregunta.
InformationsquelleAutor manju | 2011-04-07

17 Comentarios

  1. 448

    Si quieres tener una lista de personajes (una palabra), puede utilizar char *word

    Si quieres una lista de palabras (una pena), puede utilizar char **sentence

    Si quieres una lista de frases (un monólogo), puede utilizar char ***monologue

    Si quieres una lista de monólogos (una biografía), puede utilizar char ****biography

    Si quieres una lista de biografías (bio-biblioteca), puede utilizar char *****biolibrary

    Si quieres una lista de bio-bibliotecas (una ??lol), puede utilizar char ******lol

    … …

    sí, sé que estos podrían no ser las mejores estructuras de datos


    Ejemplo de uso con un muy muy muy aburrido lol

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    int wordsinsentence(char **x) {
    int w = 0;
    while (*x) {
    w += 1;
    x++;
    }
    return w;
    }
    int wordsinmono(char ***x) {
    int w = 0;
    while (*x) {
    w += wordsinsentence(*x);
    x++;
    }
    return w;
    }
    int wordsinbio(char ****x) {
    int w = 0;
    while (*x) {
    w += wordsinmono(*x);
    x++;
    }
    return w;
    }
    int wordsinlib(char *****x) {
    int w = 0;
    while (*x) {
    w += wordsinbio(*x);
    x++;
    }
    return w;
    }
    int wordsinlol(char ******x) {
    int w = 0;
    while (*x) {
    w += wordsinlib(*x);
    x++;
    }
    return w;
    }
    int main(void) {
    char *word;
    char **sentence;
    char ***monologue;
    char ****biography;
    char *****biolibrary;
    char ******lol;
    //fill data structure
    word = malloc(4 * sizeof *word); //assume it worked
    strcpy(word, "foo");
    sentence = malloc(4 * sizeof *sentence); //assume it worked
    sentence[0] = word;
    sentence[1] = word;
    sentence[2] = word;
    sentence[3] = NULL;
    monologue = malloc(4 * sizeof *monologue); //assume it worked
    monologue[0] = sentence;
    monologue[1] = sentence;
    monologue[2] = sentence;
    monologue[3] = NULL;
    biography = malloc(4 * sizeof *biography); //assume it worked
    biography[0] = monologue;
    biography[1] = monologue;
    biography[2] = monologue;
    biography[3] = NULL;
    biolibrary = malloc(4 * sizeof *biolibrary); //assume it worked
    biolibrary[0] = biography;
    biolibrary[1] = biography;
    biolibrary[2] = biography;
    biolibrary[3] = NULL;
    lol = malloc(4 * sizeof *lol); //assume it worked
    lol[0] = biolibrary;
    lol[1] = biolibrary;
    lol[2] = biolibrary;
    lol[3] = NULL;
    printf("total words in my lol: %d\n", wordsinlol(lol));
    free(lol);
    free(biolibrary);
    free(biography);
    free(monologue);
    free(sentence);
    free(word);
    }

    De salida:

    total de palabras en mi lol: 243
    • Sólo quería señalar que un arr[a][b][c] no es un ***arr. Puntero de punteros referencias de uso de referencias, mientras que arr[a][b][c] se almacena como una serie habitual en orden de fila principal.
  2. 161

    Una de las razones es que desea cambiar el valor del puntero se pasa a una función como argumento de la función, para ello se requieren puntero a un puntero.

    En palabras simples, Uso ** cuando desea conservar (O retener un cambio en) la Asignación de Memoria o de la Asignación incluso fuera de una llamada de función. (Así, Pasar de la función con doble puntero arg.)

    Esto no puede ser un muy buen ejemplo, pero le mostrará el uso básico:

    void allocate(int** p)
    {
    *p = (int*)malloc(sizeof(int));
    }
    int main()
    {
    int* p = NULL;
    allocate(&p);
    *p = 42;
    free(p);
    }
    • ¿qué sería diferente si asignar fueron void allocate(int *p) y se llama como allocate(p)?
    • Sí. El código de violación de segmento. Por favor, consulte Silviu la Respuesta.
    • ¿cuál es la diferencia entre asignar(p) y asignar(&p)?
    • No podemos simplemente volver al puntero? Si debemos mantenerlo vacío, a continuación, cuál es una práctica de caso de uso de este escenario?
  3. 76

    Aquí es una SIMPLE respuesta!!!!

    • digamos que usted tiene un puntero que su valor es una dirección.
    • pero ahora quiere cambiar esa dirección.
    • podría, haciendo pointer1 = pointer2, y pointer1 ahora, la dirección de pointer2.
    • PERO! si desea una función para hacer esto por usted, y usted desea que el resultado de persistir después de la función se hace, usted necesita hacer algún trabajo extra, se necesita un nuevo pointer3 justo a punto para pointer1, y pasar pointer3 a la función.

    • aquí es un ejemplo divertido (echa un vistazo a la salida de fuelle en primer lugar, comprender!):

    #include <stdio.h>
    int main()
    {
    int c = 1;
    int d = 2;
    int e = 3;
    int * a = &c;
    int * b = &d;
    int * f = &e;
    int ** pp = &a;  //pointer to pointer 'a'
    printf("\n a's value: %x \n", a);
    printf("\n b's value: %x \n", b);
    printf("\n f's value: %x \n", f);
    printf("\n can we change a?, lets see \n");
    printf("\n a = b \n");
    a = b;
    printf("\n a's value is now: %x, same as 'b'... it seems we can, but can we do it in a function? lets see... \n", a);
    printf("\n cant_change(a, f); \n");
    cant_change(a, f);
    printf("\n a's value is now: %x, Doh! same as 'b'...  that function tricked us. \n", a);
    printf("\n NOW! lets see if a pointer to a pointer solution can help us... remember that 'pp' point to 'a' \n");
    printf("\n change(pp, f); \n");
    change(pp, f);
    printf("\n a's value is now: %x, YEAH! same as 'f'...  that function ROCKS!!!. \n", a);
    return 0;
    }
    void cant_change(int * x, int * z){
    x = z;
    printf("\n ----> value of 'a' is: %x inside function, same as 'f', BUT will it be the same outside of this function? lets see\n", x);
    }
    void change(int ** x, int * z){
    *x = z;
    printf("\n ----> value of 'a' is: %x inside function, same as 'f', BUT will it be the same outside of this function? lets see\n", *x);
    }
    • y aquí está el resultado:
     a's value: bf94c204
    b's value: bf94c208 
    f's value: bf94c20c 
    can we change a?, lets see 
    a = b 
    a's value is now: bf94c208, same as 'b'... it seems we can, but can we do it in a function? lets see... 
    cant_change(a, f); 
    ----> value of 'a' is: bf94c20c inside function, same as 'f', BUT will it be the same outside of this function? lets see
    a's value is now: bf94c208, Doh! same as 'b'...  that function tricked us. 
    NOW! lets see if a pointer to a pointer solution can help us... remember that 'pp' point to 'a' 
    change(pp, f); 
    ----> value of 'a' is: bf94c20c inside function, same as 'f', BUT will it be the same outside of this function? lets see
    a's value is now: bf94c20c, YEAH! same as 'f'...  that function ROCKS!!!. 
    • Esta es una gran respuesta y realmente me ayudó a visualizar el propósito y la utilidad de un doble puntero.
    • hizo usted echa un vistazo a mi respuesta anterior a este? su limpiador 🙂
    • Gran respuesta, sólo le falta explicar que <code>void cant_change(int * x, int * z)</código de> falla, ya que sus parámetros son sólo de un nuevo local en el ámbito de los punteros que se inicializan asimismo a y f de los punteros (por lo que no son los mismos que una y f).
    • Simple? De verdad? 😉
    • Ejemplo fantástico, bien hecho, señor!
  4. 44

    Añadir a Asha respuesta, si usted utiliza único puntero en el ejemplo de abajo (por ejemplo, alloc1() ) perderá la referencia a la memoria asignada dentro de la función.

    void alloc2(int** p) {
    *p = (int*)malloc(sizeof(int));
    **p = 10;
    }
    void alloc1(int* p) {
    p = (int*)malloc(sizeof(int));
    *p = 10;
    }
    int main(){
    int *p = NULL;
    alloc1(p);
    //printf("%d ",*p);//undefined
    alloc2(&p);
    printf("%d ",*p);//will print 10
    free(p);
    return 0;
    }

    La razón por la que se produce como este es que en alloc1 el puntero se pasa por valor. Así, cuando se reasigna al resultado de la malloc llamada dentro de alloc1, el cambio no pertenecen al código en un ámbito diferente.

    • ¿Qué sucede si p es estática puntero entero? Obtener un fallo de Segmentación.
    • free(p) no es suficiente, es necesario if(p) free(*p) así
    • No. *p evalúa a un int sosteniendo el valor de 10 , pasando esta int a free()` es una mala idea.
    • La asignación se hace en alloc1() presenta una pérdida de memoria. El valor del puntero para ser aprobada libre se pierde, al regresar de la función.
    • No (!) necesita para lanzar el resultado de malloc en C.
  5. 21

    Vi un muy buen ejemplo de hoy, a partir de este blog, como voy a resumir a continuación.

    Imagine que usted tiene una estructura de nodos de una lista enlazada, que probablemente es

    typedef struct node
    {
    struct node * next;
    ....
    } node;

    Ahora desea implementar un remove_if función que acepta un criterio de eliminación de rm como uno de los argumentos y se recorre la lista enlazada: si una entrada satisface el criterio (algo así como rm(entry)==true), su nodo será eliminado de la lista. En la final, remove_if vuelve la cabeza (que puede ser diferente de la original de la cabeza) de la lista enlazada.

    Puede escribir

    for (node * prev = NULL, * curr = head; curr != NULL; )
    {
    node * const next = curr->next;
    if (rm(curr))
    {
    if (prev)  //the node to be removed is not the head
    prev->next = next;
    else       //remove the head
    head = next;
    free(curr);
    }
    else
    prev = curr;
    curr = next;
    }

    como su for bucle. El mensaje es, sin doble punteros, usted tiene que mantener un prev variable para re-organizar los punteros, y manejar los dos casos diferentes.

    Pero con el doble de los punteros, en realidad se puede escribir

    //now head is a double pointer
    for (node** curr = head; *curr; )
    {
    node * entry = *curr;
    if (rm(entry))
    {
    *curr = entry->next;
    free(entry);
    }
    else
    curr = &entry->next;
    }

    Usted no necesita un prev ahora porque puede modificar directamente lo prev->next señaló.

    Para hacer las cosas más claras, vamos a seguir el código un poco. Durante la eliminación:

    1. si entry == *head: será *head (==*curr) = *head->nexthead ahora apunta el puntero de la nueva rúbrica nodo. Usted puede hacer esto por cambiar directamente head‘s contenido a un nuevo puntero.
    2. si entry != *head: de la misma manera, *curr es lo que prev->next, señaló, y ahora apunta a entry->next.

    No importa en cuyo caso, puede volver a organizar los punteros en una forma unificada con el doble de punteros.

  6. 21

    1. Concepto Básico –

    Cuando se declaran de la siguiente manera : –

    1. char *cad (llamado puntero de carácter)

    – ch contiene la dirección de un solo carácter.

    – (*ch) va a eliminar la referencia al valor del carácter..

    2. char **ch –

    ‘ch’ contiene la dirección de una Matriz de punteros a caracteres. (como en 1)

    ‘*ch’ contiene la dirección de un solo carácter. (Tenga en cuenta que es diferente de 1, debido a la diferencia en la declaración).

    (**ch) va a eliminar el valor exacto del personaje..

    La adición de más punteros de ampliar la dimensión de un tipo de datos, de carácter a la cadena, a una matriz de cadenas, y así sucesivamente… Usted puede relacionarse con una 1d, 2d, 3d matrix..

    Así, el uso de puntero depende de cómo declararla.

    Aquí es un código simple..

    int main()
    {
    char **p;
    p = (char **)malloc(100);
    p[0] = (char *)"Apple";      //or write *p, points to location of 'A'
    p[1] = (char *)"Banana";     //or write *(p+1), points to location of 'B'
    cout << *p << endl;          //Prints the first pointer location until it finds '\0'
    cout << **p << endl;         //Prints the exact character which is being pointed
    *p++;                        //Increments for the next string
    cout << *p;
    }

    2. Otra Aplicación de la Doble Punteros –

    (esto abarcaría también el paso por referencia)

    Supongamos que usted desea actualizar a un personaje de una función. Si intenta lo siguiente : –

    void func(char ch)
    {
    ch = 'B';
    }
    int main()
    {
    char ptr;
    ptr = 'A';
    printf("%c", ptr);
    func(ptr);
    printf("%c\n", ptr);
    }

    La salida será AA. Esto no funciona, como te han «Pasado Por Valor» a la función.

    La forma correcta de hacerlo sería –

    void func( char *ptr)        //Passed by Reference
    {
    *ptr = 'B';
    }
    int main()
    {
    char *ptr;
    ptr = (char *)malloc(sizeof(char) * 1);
    *ptr = 'A';
    printf("%c\n", *ptr);
    func(ptr);
    printf("%c\n", *ptr);
    }

    Ahora ampliar este requisito para la actualización de una cadena en lugar de caracteres.

    Para esto, usted necesita para recibir el parámetro en la función como un doble puntero.

    void func(char **str)
    {
    strcpy(str, "Second");
    }
    int main()
    {
    char **str;
    //printf("%d\n", sizeof(char));
    *str = (char **)malloc(sizeof(char) * 10);          //Can hold 10 character pointers
    int i = 0;
    for(i=0;i<10;i++)
    {
    str = (char *)malloc(sizeof(char) * 1);         //Each pointer can point to a memory of 1 character.
    }
    strcpy(str, "First");
    printf("%s\n", str);
    func(str);
    printf("%s\n", str);
    }

    En este ejemplo, el método espera un doble puntero como parámetro para actualizar el valor de una cadena.

    • #include <stdio.h> int main() { char *ptr = 0; ptr = malloc(255); // allocate some memory strcpy( ptr, "Stack Overflow Rocks..!!"); printf("%s\n", ptr); printf("%d\n",strlen(ptr)); free(ptr); return 0; } , Pero se puede hacer sin el uso de doble puntero demasiado.
    • «char **ch – ‘ch’ contiene la dirección de una Matriz de punteros a caracteres.» No, contiene la dirección de la 1er elemento de una matriz de char punteros. Un puntero a una matriz de char* sería escribió, por ejemplo como este: char(*(*p)[42]) define p como puntero a una matriz de 42 puntero a char.
    • El último fragmento de código es completamente roto. Para empezar: Aquí*str = ... str se eliminan las referencias no inicializado la invocación de un comportamiento indefinido.
    • Este malloc(sizeof(char) * 10); no asignar espacio para 10 puntero a char pero por 10 char solo..
    • Este bucle for(i=0;i<10;i++) { str = ... pierde a utilizar el índice de i.
    • Aquí void func(char **str) { strcpy(str, "Second"); ... el tipo de mal se pasa a strcpy(). Mismo para las dos llamadas a printf() en main().
    • No (!) necesita para lanzar el resultado de malloc en C.

  7. 15

    Punteros a punteros también son útiles como «asas» de la memoria donde desea que pasen un «mango», entre las funciones de re-localizable de la memoria. Que básicamente significa que la función se puede cambiar la tarjeta de memoria que está siendo apuntado por el puntero dentro de la manija de la variable, y cada función o el objeto que está utilizando el controlador correctamente el punto a la recién reubicado (o asignados) de la memoria. Las bibliotecas como hacer esto con «opaco»-tipos de datos, que es-tipos de datos fueron usted no tiene que preocuparse acerca de lo que están haciendo con la memoria que se apunta a hacer, simplemente pasar alrededor de la «manija» entre las funciones de la biblioteca para realizar algunas operaciones en la memoria … la biblioteca de funciones que se pueden asignar y de la asignación de la memoria bajo el capó sin tener que explícitamente preocuparse por el proceso de la gestión de la memoria o donde el mango se apunta.

    Por ejemplo:

    #include <stdlib.h>
    typedef unsigned char** handle_type;
    //some data_structure that the library functions would work with
    typedef struct 
    {
    int data_a;
    int data_b;
    int data_c;
    } LIB_OBJECT;
    handle_type lib_create_handle()
    {
    //initialize the handle with some memory that points to and array of 10 LIB_OBJECTs
    handle_type handle = malloc(sizeof(handle_type));
    *handle = malloc(sizeof(LIB_OBJECT) * 10);
    return handle;
    }
    void lib_func_a(handle_type handle) { /*does something with array of LIB_OBJECTs*/ }
    void lib_func_b(handle_type handle)
    {
    //does something that takes input LIB_OBJECTs and makes more of them, so has to
    //reallocate memory for the new objects that will be created
    //first re-allocate the memory somewhere else with more slots, but don't destroy the
    //currently allocated slots
    *handle = realloc(*handle, sizeof(LIB_OBJECT) * 20);
    //...do some operation on the new memory and return
    }
    void lib_func_c(handle_type handle) { /*does something else to array of LIB_OBJECTs*/ }
    void lib_free_handle(handle_type handle) 
    {
    free(*handle);
    free(handle); 
    }
    int main()
    {
    //create a "handle" to some memory that the library functions can use
    handle_type my_handle = lib_create_handle();
    //do something with that memory
    lib_func_a(my_handle);
    //do something else with the handle that will make it point somewhere else
    //but that's invisible to us from the standpoint of the calling the function and
    //working with the handle
    lib_func_b(my_handle); 
    //do something with new memory chunk, but you don't have to think about the fact
    //that the memory has moved under the hood ... it's still pointed to by the "handle"
    lib_func_c(my_handle);
    //deallocate the handle
    lib_free_handle(my_handle);
    return 0;
    }

    Espero que esto ayude,

    Jason

    • ¿Cuál es la razón para el identificador de tipo unsigned char**? Sería void** trabajo así como así?
    • unsigned char se utiliza específicamente porque estamos almacenar un puntero a los datos binarios que serán representados como raw bytes. El uso de void requerirá de un elenco en algún momento, y que generalmente no es tan legible como a la intención de lo que se está haciendo.
  8. 6

    Simple ejemplo que usted probablemente ha visto muchas veces antes

    int main(int argc, char **argv)

    En el segundo parámetro tiene que: puntero a puntero a char.

    Tenga en cuenta que la notación de puntero (char* c) y la notación de matriz (char c[]) son intercambiables en los argumentos de la función. Así que usted podría también escribir char *argv[]. En otras palabras char *argv[] y char **argv son intercambiables.

    Lo que el de arriba representa es en realidad una matriz de secuencias de caracteres (los argumentos de línea de comandos que se dan a un programa en el inicio).

    Ver también esta respuesta para obtener más detalles acerca de la función anterior de la firma.

    • «notación de puntero (char* c) y la notación de matriz (char c[]) son intercambiables» (y tienen el mismo significado exacto) en función de los argumentos. Ellos son diferentes, sin embargo fuera de los argumentos de la función.
    • editar su información. Gracias.
  9. 5

    Cadenas son un gran ejemplo de los usos de doble punteros. La cadena es un puntero, así que en cualquier momento que usted necesita para que apunte a una cadena, se necesita un doble puntero.

  10. 5

    Por ejemplo, puede que desee asegurarse de que cuando se libere la memoria de algo que establecer el puntero a null después.

    void safeFree(void** memory) {
    if (*memory) {
    free(*memory);
    *memory = NULL;
    }
    }

    Al llamar a esta función se llamaría con la dirección de un puntero

    void* myMemory = someCrazyFunctionThatAllocatesMemory();
    safeFree(&myMemory);

    Ahora myMemory se establece en NULL y cualquier intento de reutilización será muy obviamente erróneo.

    • debe ser if(*memory) y free(*memory);
    • Buen punto, la pérdida de la señal entre el cerebro y el teclado. He editado para hacer un poco más de sentido.
    • ¿Por qué no podemos hacer lo siguiente … void safeFree(void* memoria) { if (memoria) { free(memoria); memoria = NULL; } }
    • Asignación de memoria a null no ayuda porque tienes que pasar un puntero por valor y no por referencia (de ahí el ejemplo de un puntero a un puntero).
  11. 2

    Por ejemplo, si desea un acceso aleatorio a los datos no contiguos.

    p -> [p0, p1, p2, ...]  
    p0 -> data1
    p1 -> data2

    — en C

    T ** p = (T **) malloc(sizeof(T*) * n);
    p[0] = (T*) malloc(sizeof(T));
    p[1] = (T*) malloc(sizeof(T));

    Se almacena un puntero p que apunta a un array de punteros. Cada uno de los puntos de puntero a un elemento de datos.

    Si sizeof(T) es grande, puede que no sea posible asignar un bloque contiguo (es decir, usando malloc) de sizeof(T) * n bytes.

    • No (!) necesita para lanzar el resultado de malloc en C.
  12. 2

    Una cosa yo los uso para constantemente es cuando tengo un array de objetos y necesito realizar búsquedas (búsqueda binaria) en ellos por los distintos campos.

    Sigo a la matriz original…

    int num_objects;
    OBJECT *original_array = malloc(sizeof(OBJECT)*num_objects);

    A continuación, hacer una matriz de ordenadas punteros a objetos.

    int compare_object_by_name( const void *v1, const void *v2 ) {
    OBJECT *o1 = *(OBJECT **)v1;
    OBJECT *o2 = *(OBJECT **)v2;
    return (strcmp(o1->name, o2->name);
    }
    OBJECT **object_ptrs_by_name = malloc(sizeof(OBJECT *)*num_objects);
    int i = 0;
    for( ; i<num_objects; i++)
    object_ptrs_by_name[i] = original_array+i;
    qsort(object_ptrs_by_name, num_objects, sizeof(OBJECT *), compare_object_by_name);

    Usted puede hacer como muchos ordenados puntero matrices como usted necesita, a continuación, utilizar una búsqueda binaria en el ordenados puntero del array para acceder al objeto que necesita, por los datos que tenemos. La matriz original de los objetos pueden permanecer sin clasificar, pero cada puntero de la matriz, serán ordenados por su campo especificado.

  13. 2

    El siguiente es un muy sencillo ejemplo de C++ que muestra que si usted desea utilizar una función para establecer un puntero para apuntar a un objeto, usted necesita un puntero a un puntero. De lo contrario, el puntero mantendrá regresando a null.

    (C++ respuesta, pero creo que es el mismo que en C.)

    (También para referencia: Google(«pasar por valor de c++») = «Por defecto, los argumentos en C++ se pasan por valor. Cuando un argumento se pasa por valor, el argumento del valor se copia en el parámetro de la función.»)

    Lo que se desea configurar el puntero b igual a la cadena a.

    #include <iostream>
    #include <string>
    void Function_1(std::string* a, std::string* b) {
    b = a;
    std::cout << (b == nullptr);  //False
    }
    void Function_2(std::string* a, std::string** b) {
    *b = a;
    std::cout << (b == nullptr);  //False
    }
    int main() {
    std::string a("Hello!");
    std::string* b(nullptr);
    std::cout << (b == nullptr);  //True
    Function_1(&a, b);
    std::cout << (b == nullptr);  //True
    Function_2(&a, &b);
    std::cout << (b == nullptr);  //False
    }
    //Output: 10100

    Lo que sucede en la línea de Function_1(&a, b);?

    • El «valor» de &main::a (una dirección) se copia en el parámetro std::string* Function_1::a. Por lo tanto Function_1::a es un puntero a (es decir, la dirección de memoria) la cadena de main::a.

    • El «valor» de main::b (una dirección en la memoria) se copia en el parámetro std::string* Function_1::b. Por lo tanto, ahora hay 2 de estas direcciones en la memoria, tanto los punteros null. En la línea de b = a;, la variable local Function_1::b a continuación, se cambia a la igualdad de Function_1::a (= &main::a), pero la variable main::b es invariable. Después de la llamada a Function_1, main::b se sigue un puntero nulo.

    Lo que sucede en la línea de Function_2(&a, &b);?

    • El tratamiento de la a variable es el mismo: dentro de la función, Function_2::a es la dirección de la cadena de main::a.

    • Pero la variable b ahora se pasa como un puntero a un puntero. El «valor» de &main::b (el la dirección del puntero main::b) se copian en std::string** Function_2::b. Por tanto, dentro de Function_2, eliminar la referencia de este como *Function_2::b va a acceder y modificar main::b . Por lo que la línea *b = a; es en realidad la configuración de main::b (una dirección) igual a Function_2::a (= dirección de main::a) que es lo que queremos.

    Si desea utilizar una función para modificar una cosa, sea un objeto o una dirección (puntero), tendrá que pasar un puntero a esa cosa. La cosa que en realidad pase no se puede modificar (en el ámbito de la llamada) porque una copia.

    (Una excepción es si el parámetro es una referencia, tales como std::string& a. Pero por lo general estos son const. Por lo general, si usted llama f(x), si x es un objeto que debe ser capaz de asumir que f no modificar x. Pero si x es un puntero, entonces usted debe asumir que f podría modificar el objeto apuntado por x.)

    • El código de C++ para responder a una C pregunta no es la mejor idea.
  14. 1

    ¿Por qué el doble de punteros?

    El objetivo es cambiar lo que studentA puntos, mediante el uso de una función.

    #include <stdio.h>
    #include <stdlib.h>
    typedef struct Person{
    char * name;
    } Person; 
    /**
    * we need a ponter to a pointer, example: &studentA
    */
    void change(Person ** x, Person * y){
    *x = y; //since x is a pointer to a pointer, we access its value: a pointer to a Person struct.
    }
    void dontChange(Person * x, Person * y){
    x = y;
    }
    int main()
    {
    Person * studentA = (Person *)malloc(sizeof(Person));
    studentA->name = "brian";
    Person * studentB = (Person *)malloc(sizeof(Person));
    studentB->name = "erich";
    /**
    * we could have done the job as simple as this!
    * but we need more work if we want to use a function to do the job!
    */
    //studentA = studentB;
    printf("1. studentA = %s (not changed)\n", studentA->name);
    dontChange(studentA, studentB);
    printf("2. studentA = %s (not changed)\n", studentA->name);
    change(&studentA, studentB);
    printf("3. studentA = %s (changed!)\n", studentA->name);
    return 0;
    }
    /**
    * OUTPUT:
    * 1. studentA = brian (not changed)
    * 2. studentA = brian (not changed)
    * 3. studentA = erich (changed!)
    */
    • No (!) necesita para lanzar el resultado de malloc en C.
  15. 1

    Un poco tarde a la fiesta, pero esperemos que esto ayude a alguien.

    En C matrices siempre asignar memoria en la pila, por lo que una función no puede devolver
    una (no estática) de la matriz debido al hecho de que la memoria asignada en la pila
    obtiene libera automáticamente cuando la ejecución llega al final del bloque actual.
    Eso es realmente molesto cuando usted quiere tratar con dos dimensiones de las matrices
    (es decir, las matrices) y aplicar un par de funciones que pueden alterar y retorno de las matrices.
    Para lograr esto, usted podría usar un puntero a puntero a implementar una matriz con
    asignación dinámica de memoria:

    /* Initializes a matrix */
    float** init_matrix(int num_rows, int num_cols){
    //Allocate memory for num_rows float-pointers
    float** A = calloc(num_rows, sizeof(double*));
    //return NULL if the memory couldn't allocated
    if(A == NULL) return NULL;
    //For each float-pointer (row) allocate memory for num_cols floats
    for(int i = 0; i < num_rows; i++){
    A[i] = calloc(num_cols, sizeof(double));
    //return NULL if the memory couldn't allocated
    //and free the already allocated memory
    if(A[i] == NULL){
    for(int j = 0; j < i; j++){
    free(A[j]);
    }
    free(A);
    return NULL;
    }
    }
    return A;
    } 

    Aquí un ejemplo:

     float**        float*            float
    -------------       ---------------------------------------------------------
    A ------> |   A[0]    | ----> | A[0][0] | A[0][1] | A[0][2] | ........ | A[0][cols-1] |
    | --------- |       ---------------------------------------------------------
    |   A[1]    | ----> | A[1][0] | A[1][1] | A[1][2] | ........ | A[1][cols-1] |
    | --------- |       ---------------------------------------------------------
    |     .     |                                    .
    |     .     |                                    .
    |     .     |                                    .
    | --------- |       ---------------------------------------------------------
    |   A[i]    | ----> | A[i][0] | A[i][1] | A[i][2] | ........ | A[i][cols-1] |
    | --------- |       ---------------------------------------------------------
    |     .     |                                    .
    |     .     |                                    .
    |     .     |                                    .
    | --------- |       ---------------------------------------------------------
    | A[rows-1] | ----> | A[rows-1][0] | A[rows-1][1] | ... | A[rows-1][cols-1] |
    -------------       ---------------------------------------------------------

    El flotador-puntero-a-float-puntero apunta al primer elemento a[0] de un
    bloque de memoria cuyos elementos son de flotación-los punteros de la misma. Usted puede imaginar estos
    float-punteros como las filas de la matriz. Esa es la razón por la que cada
    float-puntero asigna memoria para num_cols float-elementos.
    Por otra parte, Una[i] apunta a la i-ésima fila, es decir, a[i] apunta a Un[i][0] y
    eso es sólo la primera de flotación de los elementos del bloque de memoria para la i-ésima fila.
    Por último, se puede acceder al elemento en la i-ésima fila
    y la j-ésima columna fácilmente con Un[i][j].

    He aquí un ejemplo completo en el que se muestra el uso de:

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    /* Initializes a matrix */
    float** init_matrix(int num_rows, int num_cols){
    //Allocate memory for num_rows float-pointers
    float** matrix = calloc(num_rows, sizeof(double*));
    //return NULL if the memory couldn't allocated
    if(matrix == NULL) return NULL;
    //For each float-pointer (row) allocate memory for num_cols
    //floats
    for(int i = 0; i < num_rows; i++){
    matrix[i] = calloc(num_cols, sizeof(double));
    //return NULL if the memory couldn't allocated
    //and free the already allocated memory
    if(matrix[i] == NULL){
    for(int j = 0; j < i; j++){
    free(matrix[j]);
    }
    free(matrix);
    return NULL;
    }
    }
    return matrix;
    }
    /* Fills the matrix with random float-numbers between -1 and 1 */
    void randn_fill_matrix(float** matrix, int rows, int cols){
    for (int i = 0; i < rows; ++i){
    for (int j = 0; j < cols; ++j){
    matrix[i][j] = (float) rand()/RAND_MAX*2.0f-1.0f;
    }
    }
    }
    /* Frees the memory allocated by the matrix */
    void free_matrix(float** matrix, int rows, int cols){
    for(int i = 0; i < rows; i++){
    free(matrix[i]);
    }
    free(matrix);
    }
    /* Outputs the matrix to the console */
    void print_matrix(float** matrix, int rows, int cols){
    for(int i = 0; i < rows; i++){
    for(int j = 0; j < cols; j++){
    printf(" %- f ", matrix[i][j]);
    }
    printf("\n");
    }
    }
    int main(){
    srand(time(NULL));
    int m = 3, n = 3;
    float** A = init_matrix(m, n);
    randn_fill_matrix(A, m, n);
    print_matrix(A, m, n);
    free_matrix(A, m, n);
    return 0;
    }
  16. 0

    He usado doble punteros de hoy en día, mientras yo estaba de programación de algo para el trabajo, así que puedo responder a eso hemos tenido el uso de ellos (es la primera vez que tuve que usar el doble de punteros). Hemos tenido que lidiar con tiempo real de codificación de fotogramas contenidos en los búferes de que son miembros de ciertas estructuras. En el codificador tuvimos que utilizar un puntero a una de esas estructuras. El problema era que nuestro puntero estaba siendo cambiado a punto para otras estructuras de otro hilo. Con el fin de utilizar la estructura actual en el codificador, he tenido que utilizar un doble puntero, con el fin de señalar el puntero de la que fue modificada en otro hilo. No fue evidente en la primera, al menos para nosotros, que hemos tenido que adoptar este enfoque. Un montón de dirección fueron impresos en el proceso :)).

    DEBE utilizar doble punteros cuando se trabaja en punteros que se han cambiado en otros lugares de su aplicación. Usted también puede encontrar el doble de punteros a ser una necesidad cuando se trata de hardware que devuelve y dirección.

  17. 0

    Comparar la modificación de valor de la variable frente a la modificación de valor de puntero:

    #include <stdio.h>
    #include <stdlib.h>
    void changeA(int (*a))
    {
    (*a) = 10;
    }
    void changeP(int *(*P))
    {
    (*P) = malloc(sizeof((*P)));
    }
    int main(void)
    {
    int A = 0;
    printf("orig. A = %d\n", A);
    changeA(&A);
    printf("modi. A = %d\n", A);
    /*************************/
    int *P = NULL;
    printf("orig. P = %p\n", P);
    changeP(&P);
    printf("modi. P = %p\n", P);
    free(P);
    return EXIT_SUCCESS;
    }

    Esto me ayudó a evitar devolver el valor del puntero cuando el puntero fue modificado por la llamada función de (utilizados en forma individual lista enlazada).

    De EDAD (malo):

    int *func(int *P)
    {
    ...
    return P;
    }
    int main(void)
    {
    int *pointer;
    pointer = func(pointer);
    ...
    }    

    NUEVO (mejor):

    void func(int **pointer)
    {
    ...
    }
    int main(void)
    {
    int *pointer;
    func(&pointer);
    ...
    }    

Dejar respuesta

Please enter your comment!
Please enter your name here