Newsgroup: it.comp.lang.c
Titolo: modifica char * da funzione

scusate, se faccio cosi' non modifico l'indirizzo a cui punta???perche' 
fuori dalla funzione il char * passato (e allocato con calloc) rimane 
invariato???
grazie 1000
Dade
void basefilename(char *filename){
 char *pos=NULL;
 pos=strrchr(filename,'\\');
 pos++;
 filename=pos;
}

 }
ok, prova a seguire il ragionamento...
Immagina di avere f, un puntatore a char inizializzato a NULL.
Poi chiami basefilename passandogli f:
char *f = NULL;
basefilename(f);
bene, f viene passato per valore. Il suo valore e' NULL.
basefilename() ha una variabile locale che si chiama filename di tipo
char* che viene inizializzata con il valore NULL che abbiamo passato.
tutte le modifiche che apportiamo a filename non si rispecchieranno su
f, infatto filename e f sono due puntatori diversi che puntano
(inizialmente) allo stesso posto: NULL.
quello che tu vuoi fare e':
void basefilename(char **filename){
...
e la chiamata diventa:
basefilename(&f);
in questo caso f e' sempre il puntatore che punta a NULL.
Noi pero' non passiamo piu' f per valore (quindi NULL) ma bensi'
l'indirizzo di f (&f).
Dall'altra parte, nella funzione, riceviamo un puntatore a puntatore a
char (char**).
questo conterra' l'indirizzo di f, e facendo *filename accediamo quindi
ad f. Non accediamo solamente ad un puntatore che punta a NULL, ma
accediamo proprio ad f (che ovviamente punta a NULL). Quindi essendo f
stesso (e non una copia) qualunque modifica facciamo a *filename la
facciamo ad f.
Quindi devi cambiare varie righe di codice, tipo:
filename=pos;
in
*filename=pos;
etc...
Buona notte,
Tommaso
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG


Grazie 1000 Tommaso,
spero che tu mi possa chiarire anche il dubbio che ti ho illustrato sopra 
:-)
Ciao
Dade 

 modificarlo la dichiarazione sarebbe stata f(char pippo[]) sbaglio?
Sbagli. Nella dichiarazione degli argomenti di una funzione, "char a[]" è 
perfettamente equivalente a "char* a".
Max


Grazie 1000 Max
Ciao
Dade 

 inizio a capire :-)
mi sa che ti manchi ancora un pochino per capire...
char **ptr[100][10]; non e' un array di stringhe e non e' nemmeno un
puntatore a puntatore e':
ptr e' un array bidimensionale di puntatori a puntatori.
quindi, se proprio vuoi, non e' char** ma char****.


 Tommaso
Grazie ancora
Dade 

 quindi, se proprio vuoi, non e' char** ma char****.
Ehm, no. Ora l'OP si suicida. :-)
Dunque, se abbiamo una variabile 'ptr' dichiarata così:
 char ** ptr[100][10];
Le possibili signature di una funzione a cui passare 'ptr' sono:
 func( char * * ptr [] [10] )
 func( char * * (*ptr) [10] )
che  sono in realtà due scritture della stessa cosa.
Il '10', invece, *non* può assolutamente essere eliminato, in quanto è la
dimensione degli elementi che compongono l'array di 100, i quali sono,
appunto, degli array (di 10), e non dei puntatori. (Ovviamente, ciascuno di
questi array potrà decadere in puntatore se verrà passato individualmente a
un'altra funzione, ma questa è un'altra storia.)
Max

 cosi credo che sia ok? (aspetto smentite :P)
No. Non puoi eliminare il '10'. Nell'altro messaggio spiego il motivo.
Max

 Ehm, no. Ora l'OP si suicida. :-)
certo, quello che dici e' verissimo. volevo solo mettere in risalto il
livello di 'indirezione'. nel farlo in modo superficiale sono stato
impreciso.
quel "se proprio vuoi" stava ad indicare che volevo essere superficiale
e rifermi solo al livello di 'indirezione'.


 quindi, se proprio vuoi, non e' char** ma char****.
come mi ha fatto notare Max questo messaggio puo' essere frainteso (e
rileggendolo io stesso lo fraintenderei!)
il livello di indirezione e' **** (4 livelli), se vogliamo, ma
ovviamente la signature deve essere:
char **(*p)[10]
in quanto non possiamo per ovvi motivi eliminare il 10.
Ringrazio Max per avermi fatto notare che il mio messaggio, cosi' come
era scritto, era errato.


 un'altra funzione, ma questa è un'altra storia.)
scusa Max, ma perche' devo passare 10 e non 100??? e' per standard oppure 
c'e' qualche motivo logico?
Pensandoci mi verrebbe da dire che sarebbe piu' importante il numero di 
puntatori piuttosto che la dimensione delle locazioni puntate...
scusami ma c'ho la testa dura :-)
grazie
Dade

 c'e' qualche motivo logico?
Certo che c'è un motivo logico. Mi pareva che la mia spiegazione, unita al
già noto principio di "decadenza" di un array nel puntatore al primo
elemento, fosse sufficientemente chiara. Ma forse non lo era.
Dunque, considera questa dichiarazione (T è un tipo, A e B sono due
constanti):
   T a[ A ] [ B ];
La notazione usata per dichiarare gli array potrebbe confondere, perciò
semplifichiamo usando un typedef:
   typedef T  array_B_t [ B ];
'array_B_t' ora significa: array di B elementi di tipo T.
Ora, la nostra dichiarazione iniziale può essere riscritta come
    array_B_t a[ A ];
Ci sei? Se non ci sei, rileggi finché non è chiaro.
A questo punto è evidente che, quando viene passato a una funzione, 'a' può
decadere in un puntatore ad un 'array_B_t'. Quindi come argomento della
funzione potremmo specificare:
  func( array_B_t* arg  );
che, esplicitando il typedef, diviene:
  func( T  (* arg) [ B ]  );
La dimensione B non può essere eliminata, perché deve essere noto il tipo a
cui punta il puntatore. Tale puntatore può essere usato per scorrere
l'array di 'array_B_t', perciò la dimensione di 'array_B_t' deve essere
nota all'interno della funzione; diversamente non sapremmo come è
strutturato l'array.
La tua difficoltà credo derivi dall'errata convinzione che gli array siano
delle specie di puntatori. No, gli array sono sequenze contigue di elementi
di un certo tipo. Un array di array non contiene puntatori, contiene array.
Max

Max M. ha scritto:

Questo riguarda l'indirizzamento, vero? Esempio: se ho:
righe=5;
colonne=6;
int ar[colonne][righe];
ar[2][3];
una volta compilata l'ultima istruzione diventa equivalente a:
*(ar+colonne*3+2)
giusto? (magari ho fatto casino con colonne e righe ma il ragionamento 
e' quello?)
-- 
Devaraja (Xdevaraja87^gmail^c0mX)
Linux Registerd User #338167
http://counter.li.org


Grazie Max della spiegazione, cosi' le cose sono piu' chiare! Il mio sbaglio 
e' associare mentalmente un vettore di ptr a un array... quindi locazioni di 
memoria contigue etc. Per questo non capisco, se ho un puntatore di [2][2] 
mi immagino 4 locazioni di memoria cotinue, e quindi posso scegliere se 
leggere come [2][2] o come [4] e basta! Credo che questo sia dovuto anche 
alla mia poca esperienza :(
Sei stato gentilissimo! Grazie 1000
Dade 

 ma il ragionamento e' quello?)
ma ti eri dimenticato il secondo errore, che l'aritmetica dei puntatori
e' "intelligente":
*(*(ar+2)+3)
quando fai ar+2 automaticamente lui sa che non deve aggiungere due *
sizeof(int), ma due * sizeof(int[righe]).
Per favore, ora, dimenticati di:
*((*ar) + 2*righe +3)
che e' uno schifo e spero non scateni polemiche ;-)
il modo giusto e':
*(*(ar+2)+3)


 sizeof(int), ma due * sizeof(int[righe]).
e per ricongiungersi al discorso di prima...
il motivo per cui sa questa cosa e' perche ar e':
int ar[colonne][righe]
o
int (*ar)[righe]
per questo non possiamo omettere la dimensione di righe. Se la
omettessimo non saprebbe piu' come comportarsi e
ar[2][3] darebbe tutt'altro risultato!
In piu' per evitare problemi, il codice nemmeno compila in C++ e
dovrebbe dare almeno una warning in C89.
Prova (per sperare che compili devi compilarlo in modalita' C89 e non
C++):
#include<stdio.h>
#define DIM1 10
#define DIM2 15
int main()
{
	int ar[DIM1][DIM2] = {0};
	int (*p1)[DIM2] = ar;
	int *p2 = ar;
	ar[2][3] = 7;
	printf("%d\n", ar[2][3]       );
	printf("%d\n", *(*(p1+2)+3)   );
	printf("%d\n", *(p2+2*DIM2+3) );
	return 0;
}
come vedi con p1 usiamo la signature corretta e basta:
*(*(p1+2)+3)
l'aritmetica dei puntatori fa tutto.
con p2 invece usiamo la signature *errata* e:
*(p2+2*DIM2+3)
(questa e' sempre una cosa orribile da dimenticare) bisogna fare a mano.
Ora la cosa interessante e' che p1[2][3] funziona, mentre p2[2][3]
ovviamente assolutamente no (e non compila nemmeno)!


 leggere come [2][2] o come [4] e basta! 
[2][2] e' fuori dal range dell'array, penso intendessi [1][1].
e [1][1] al limite lo potresti accedere come [3].
ed il 3 deriva da questo: 1*2+1 = 3
ovvero il primo indice per la dimensione della seconda dimensione +
l'indice della seconda dimensione.
char a[2][2] = {0};
char *p = a;
a[1][1] = 7;
printf("%d\n", p[3] );
// stampa 7, p[3] legge a[1][1]
e... ovviamente questo e' l'ennesima cosa da "dimenticare".
ultimamente ho postato volutamente piu' volte codice "errato" per
cercare di far capire, a basso livello, come funzionano le cose.
Tommaso
P.S. puoi provare se il tuo vecchio compilatore C89 te lo compila e fare
tutti gli esperimenti del caso;-)


 
Quindi se ho capito bene:
int ar[cols][rows];
puo' essere visto anche come un array di rows elementi, ognuno dei quali 
e' un array di cols elementi.
Quindi ar decade in un puntatore al suo primo elemento cioe' un int[cols].
Sommando 2 ad ar ottengo un puntatore al suo terzo elemento, che e' 
sempre un int[cols].
Dereferenziando quel puntatore ottengo un int[cols] che decade in un 
puntatore al suo primo elemento, cioe' un int.
Se sommo 3 a quel puntatore ottengo un puntatore al quarto elemento 
dell'array.
Quindi
*(*(ar+2)+3)==ar[2][3]  giusto?


 *(*(ar+2)+3)==ar[2][3]  giusto?
la conclusione e' giusta, il ragionamento non proprio.
Prova a leggere gli altri messaggi che ho scritto e che ha scritto Max.


 la conclusione e' giusta, il ragionamento non proprio.
Cosa c'e' di sbagliato? Solo che invertito righe e colonne o anche il 
discorso del nome dell'array che decade in un puntatore al primo 
elemento? Quello l'avete detto voi, ma forse ho frainteso.
Adesso ci riprovo:
float ar[x][y];
ar[2][3]==*(*(ar+2)+3);
+ ar e' un array di x array di y float.
+ il nome ar, tranne che in casi speciali, decade in un puntatore 
(*)float[y] al suo primo elemento: un float[y] (per questo y deve essere 
conosciuto).
+ ar+2 e' un (*)float[y] quindi *(ar+2) e' un float[y] che a sua volta 
decade in un puntatore al suo primo elemento, che e' un float.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^su questo non sono sicuro
+ *(ar+2)+3 e' un puntatore al quarto elemento di quell'array. Quindi 
*(*(ar+2)+3) e' un float.
Scusa se ti faccio perdere ancora tempo, ma per me questo argomento e' 
il piu' difficile del c. Per ora grazie per le risposte.


 ^^^^^^^^^^^^su questo non sono sicuro
si, e' cosi'. Se fai **(ar+2) ne hai conferma, o ancora meglio se fai:
ar[2] == &ar[2][0]


Tommaso Galleri ha scritto:

Ok grazie per la pazienza.
