sirven que punteros puntero parametros para operaciones los funciones ejemplo dev declaracion con como cadenas aritmetica apuntadores c

que - punteros como parametros de funciones en c



¿Cómo funciona puntero a punteros en C? (14)

¿Cómo funcionan los punteros a punteros en C? ¿Cuándo los usarías?


Cómo funciona: es una variable que puede almacenar otro puntero.

Cuándo los usaría: muchos usos uno de ellos es si su función quiere construir una matriz y devolverla a la persona que llama.

//returns the array of roll nos {11, 12} through paramater // return value is total number of students int fun( int **i ) { int *j; *i = (int*)malloc ( 2*sizeof(int) ); **i = 11; // e.g., newly allocated memory 0x2000 store 11 j = *i; j++; *j = 12; ; // e.g., newly allocated memory 0x2004 store 12 return 2; } int main() { int *i; int n = fun( &i ); // hey I don''t know how many students are in your class please send all of their roll numbers. for ( int j=0; j<n; j++ ) printf( "roll no = %d /n", i[j] ); return 0; }


Cuando cubrimos punteros en un curso de programación en la universidad, recibimos dos pistas sobre cómo comenzar a aprender sobre ellos. El primero fue ver Pointer Fun With Binky . El segundo fue pensar en el pasaje de Haddocks ''Eyes de Lewis Carroll''s Through the Looking-Glass

"Estás triste", dijo el Caballero en un tono ansioso: "Déjame cantarte una canción para consolarte".

"¿Es muy largo?", Preguntó Alice, porque había escuchado mucha poesía ese día.

"Es largo", dijo el Caballero, "pero es muy, muy hermoso. Todo el mundo que me escucha cantarlo, o les hace llorar a los ojos, o si no ... "

"O bien, ¿qué?", ​​Dijo Alicia, porque el Caballero había hecho una pausa repentina.

"O de lo contrario no, ya sabes. El nombre de la canción se llama ''Haddocks'' Eyes ''".

"Oh, ese es el nombre de la canción, ¿verdad?" Dijo Alice, tratando de sentirse interesada.

"No, no entiendes", dijo el Caballero, luciendo un poco molesto. "Así es como se llama el nombre. El nombre es realmente ''El hombre de edad avanzada'' ".

"Entonces debería haber dicho ''¿Así se llama la canción''?" Alice se corrigió a sí misma.

"No, no deberías: ¡eso es otra cosa! La canción se llama ''Formas y medios'': ¡pero eso es solo lo que se llama, ya sabes!

"Bueno, ¿cuál es la canción, entonces?", Dijo Alicia, que en ese momento estaba completamente desconcertada.

"Estaba llegando a eso", dijo el Caballero. "La canción realmente es ''A-sitting on a gate'': y la canción es mi propia invención".


Cuando se requiere una referencia a un puntero. Por ejemplo, cuando desea modificar el valor (dirección apuntada a) de una variable de puntero declarada en el alcance de una función llamante dentro de una función llamada.

Si pasa un único puntero como argumento, modificará las copias locales del puntero, no el puntero original en el alcance de la llamada. Con un puntero a un puntero, usted modifica el último.


Es posible que desee leer esto: Punteros a punteros

Espero que esto ayude a aclarar algunas dudas básicas.


Hay tantas explicaciones útiles, pero no encontré solo una breve descripción, así que ...

Básicamente, el puntero es la dirección de la variable. Breve código de resumen:

int a, *p_a;//declaration of normal variable and int pointer variable a = 56; //simply assign value p_a = &a; //save address of "a" to pointer variable *p_a = 15; //override the value of the variable //print 0xfoo and 15 //- first is address, 2nd is value stored at this address (that is called dereference) printf("pointer p_a is having value %d and targeting at variable value %d", p_a, *p_a);

También se puede encontrar información útil en el tema Qué significa referencia y desreferencia

Y no estoy tan seguro, cuando pueden ser útiles los punteros, pero en común es necesario usarlos cuando se está realizando una asignación de memoria manual / dinámica: malloc, calloc, etc.

Así que espero que también ayude a aclarar la problemática :)


Me gusta este ejemplo de código del "mundo real" de puntero a uso de puntero, en Git 2.0, commit 7b1004b :

Linus dijo una vez:

De hecho, me gustaría que más gente entendiera el tipo de codificación realmente de bajo nivel. No es algo grande y complejo como la búsqueda de nombres sin bloqueos, sino simplemente un buen uso de punteros a punteros, etc.
Por ejemplo, he visto demasiadas personas que eliminan una entrada de la lista enlazada de forma individual al hacer un seguimiento de la entrada "anterior" y luego eliminar la entrada, haciendo algo como

if (prev) prev->next = entry->next; else list_head = entry->next;

y cada vez que veo un código como ese, simplemente digo "Esta persona no entiende los punteros". Y es tristemente bastante común.

Las personas que entienden los punteros simplemente usan un " puntero al puntero de entrada " e inicializan eso con la dirección del list_head. Y luego, a medida que atraviesan la lista, pueden eliminar la entrada sin usar ninguna condición, simplemente haciendo un

*pp = entry->next

La aplicación de esa simplificación nos permite perder 7 líneas de esta función, incluso al agregar 2 líneas de comentario.

- struct combine_diff_path *p, *pprev, *ptmp; + struct combine_diff_path *p, **tail = &curr;

Chris señala en los comentarios del video de 2016 " El problema del doble puntero de Linus Torvalds " por Philip Buuck .

kumar señala en los comentarios la entrada del blog " Linus on Understanding Pointers ", donde Grisha Trubetskoy explica:

Imagine que tiene una lista vinculada definida como:

typedef struct list_entry { int val; struct list_entry *next; } list_entry;

Debe iterar sobre él desde el principio hasta el final y eliminar un elemento específico cuyo valor sea igual al valor de to_remove.
La forma más obvia de hacer esto sería:

list_entry *entry = head; /* assuming head exists and is the first entry of the list */ list_entry *prev = NULL; while (entry) { /* line 4 */ if (entry->val == to_remove) /* this is the one to remove ; line 5 */ if (prev) prev->next = entry->next; /* remove the entry ; line 7 */ else head = entry->next; /* special case - first entry ; line 9 */ /* move on to the next entry */ prev = entry; entry = entry->next; }

Lo que estamos haciendo arriba es:

  • iterar sobre la lista hasta que la entrada sea NULL , lo que significa que hemos llegado al final de la lista (línea 4).
  • Cuando encontramos una entrada que queremos eliminar (línea 5),
    • asignamos el valor del siguiente puntero actual al anterior,
    • eliminando así el elemento actual (línea 7).

Hay un caso especial anterior: al comienzo de la iteración no hay entrada previa ( prev es NULL ), por lo que para eliminar la primera entrada de la lista debe modificar el encabezado mismo (línea 9).

Lo que Linus estaba diciendo es que el código anterior podría simplificarse haciendo que el elemento anterior sea un puntero a un puntero en lugar de solo un puntero .
El código se ve así:

list_entry **pp = &head; /* pointer to a pointer */ list_entry *entry = head; while (entry) { if (entry->val == to_remove) *pp = entry->next; pp = &entry->next; entry = entry->next; }

El código anterior es muy similar a la variante anterior, pero observe cómo ya no necesitamos ver el caso especial del primer elemento de la lista, ya que pp no es NULL al principio. Simple e inteligente.

Además, alguien en ese hilo comentó que la razón por la que esto es mejor es porque *pp = entry->next es atómico. Ciertamente NO es atómico .
La expresión anterior contiene dos operadores de desreferencia ( * y -> ) y una asignación, y ninguna de esas tres cosas es atómica.
Este es un concepto erróneo común, pero lamentablemente casi nada en C se debe suponer que sea atómico (incluidos los operadores ++ y -- ).


Supongamos una computadora de 8 bits con direcciones de 8 bits (y, por lo tanto, solo 256 bytes de memoria). Esto es parte de esa memoria (los números en la parte superior son las direcciones):

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ | | 58 | | | 63 | | 55 | | | h | e | l | l | o | /0 | | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+

Lo que puede ver aquí, es que en la dirección 63 comienza la cadena "hola". Entonces, en este caso, si esta es la única ocurrencia de "hola" en la memoria, entonces,

const char *c = "hello";

... define c para ser un puntero a la cadena (de solo lectura) "hello", y por lo tanto contiene el valor 63. c debe almacenarse en alguna parte: en el ejemplo anterior en la ubicación 58. Por supuesto, no solo podemos señalar a los personajes, sino también a otros punteros. P.ej:

const char **cp = &c;

Ahora cp apunta a c , es decir, contiene la dirección de c (que es 58). Podemos ir aún más lejos. Considerar:

const char ***cpp = &cp;

Ahora cpp almacena la dirección de cp . Entonces tiene el valor 55 (basado en el ejemplo anterior), y lo adivinó: se almacena en la dirección 60.

En cuanto a por qué uno usa punteros a punteros:

  • El nombre de una matriz generalmente arroja la dirección de su primer elemento. Entonces, si la matriz contiene elementos de tipo t , una referencia a la matriz tiene tipo t * . Ahora considere una matriz de matrices de tipo t : naturalmente, una referencia a esta matriz 2D tendrá el tipo (t *)* = t ** , y por lo tanto, es un puntero a un puntero.
  • Aunque una serie de cadenas suena unidimensional, de hecho es bidimensional, ya que las cadenas son matrices de caracteres. Por lo tanto: char ** .
  • Una función f necesitará aceptar un argumento de tipo t ** si va a alterar una variable de tipo t * .
  • Muchas otras razones que son demasiado numerosas para enumerarlas aquí.

Un puntero a puntero es, bueno, un puntero a puntero.

Un ejemplo significativo de someType ** es una matriz bidimensional: tiene una matriz, llena de punteros a otras matrices, de modo que cuando escriba

dpointer [5] [6]

accede a la matriz que contiene punteros a otras matrices en su quinta posición, obtiene el puntero (deje que su nombre sea fpointer) y luego acceda al sexto elemento de la matriz referenciada a esa matriz (por lo tanto, fpointer [6]).


Un puntero a un puntero también se llama asa . Un uso para ello suele ser cuando un objeto se puede mover en la memoria o eliminar. Uno es a menudo responsable de bloquear y desbloquear el uso del objeto para que no se mueva al acceder a él.

A menudo se usa en entornos con memoria restringida, es decir, Palm OS.

computer.howstuffworks.com Enlace >>

www.flippinbits.com Enlace >>


Usted tiene una variable que contiene una dirección de algo. Eso es un puntero.

Luego tienes otra variable que contiene la dirección de la primera variable. Eso es un puntero al puntero.


es un puntero al valor de la dirección del puntero. (Eso es terrible, lo sé)

Básicamente, le permite pasar un puntero al valor de la dirección de otro puntero, de modo que puede modificar desde dónde apunta otro puntero desde una función secundaria, como:

void changeptr(int** pp) { *pp=&someval; }


¿Cómo funcionan los punteros a punteros en C?

Primero, un puntero es una variable, como cualquier otra variable, pero contiene la dirección de una variable.

Un puntero a un puntero es una variable, como cualquier otra variable, pero que contiene la dirección de una variable. Esa variable simplemente es un puntero.

¿Cuándo los usarías?

Puede usarlos cuando necesite devolver un puntero a alguna memoria en el montón, pero no usar el valor de retorno.

Ejemplo:

int getValueOf5(int *p) { *p = 5; return 1;//success } int get1024HeapMemory(int **p) { *p = malloc(1024); if(*p == 0) return -1;//error else return 0;//success }

Y lo llamas así:

int x; getValueOf5(&x);//I want to fill the int varaible, so I pass it''s address in //At this point x holds 5 int *p; get1024HeapMemory(&p);//I want to fill the int* variable, so I pass it''s address in //At this point p holds a memory address where 1024 bytes of memory is allocated on the heap

También hay otros usos, como el argumento principal () de cada programa C tiene un puntero a un puntero para argv, donde cada elemento contiene una matriz de caracteres que son las opciones de línea de comando. Sin embargo, debe tener cuidado cuando utiliza punteros de punteros para apuntar a 2 matrices dimensionales, en su lugar, es mejor utilizar un puntero a una matriz bidimensional.

¿Por qué es peligroso?

void test() { double **a; int i1 = sizeof(a[0]);//i1 == 4 == sizeof(double*) double matrix[ROWS][COLUMNS]; int i2 = sizeof(matrix[0]);//i2 == 240 == COLUMNS * sizeof(double) }

Aquí hay un ejemplo de un puntero a una matriz bidimensional hecha correctamente:

int (*myPointerTo2DimArray)[ROWS][COLUMNS]

Sin embargo, no puede usar un puntero a una matriz de dos dimensiones si desea admitir una cantidad variable de elementos para las FILAS y COLUMNAS. Pero cuando sabes de antemano usarías una matriz bidimensional.


Considere la siguiente figura y el programa para comprender mejor este concepto .

Según la figura, ptr1 es un único puntero que tiene la dirección de la variable num .

ptr1 = &num;

De manera similar, ptr2 es un puntero al puntero (doble puntero) que tiene la dirección del puntero ptr1 .

ptr2 = &ptr1;

Un puntero que apunta a otro puntero se conoce como puntero doble. En este ejemplo, ptr2 es un puntero doble.

Valores del diagrama de arriba:

Address of variable num has : 1000 Address of Pointer ptr1 is: 2000 Address of Pointer ptr2 is: 3000

Ejemplo:

#include <stdio.h> int main () { int num = 10; int *ptr1; int **ptr2; // Take the address of var ptr1 = &num; // Take the address of ptr1 using address of operator & ptr2 = &ptr1; // Print the value printf("Value of num = %d/n", num ); printf("Value available at *ptr1 = %d/n", *ptr1 ); printf("Value available at **ptr2 = %d/n", **ptr2); }

Salida:

Value of num = 10 Value available at *ptr1 = 10 Value available at **ptr2 = 10