Newsgroup: it.comp.lang.c
Titolo: array non dimensionate

in teoria scrivendo "int array[ ];" è possibile passargli dei parametri
variabili di volta in volta e lui si riadatta la dimensione...giusto? Però
perchè se scrivo
---------------------
#include<stdio.h>
int main(void)
{
int stringa[], numero, i;
printf("Inserisci la quantità dei numeri che si intende ordinare: ");
scanf("%d",&numero);
for(i=0;i<numero;i++)
  {
  printf("Inserisci il %d° numero: ", i+1);
  scanf("%d",&stringa[i]);
  }
for(i=0;i<numero;i++)
  printf("%d\n",stringa[i]);
}
----------------------------------
in compilazione mi dice che è errato il size della 'stringa'?! non se lo
dovrebbe calcora da se!? devo aggiungere un sizeof da qualche parte?! Dove
sbaglio?!
thx
byez

variabili di volta in volta e lui si riadatta la dimensione...giusto? 
No.
int array[];
non e' una sintassi corretta, devi specificare la dimensione
dell'array.
-- 
Andrea Laforgia (
walkie...@libero.it
)
"Usenet is a strange place" [Dennis Ritchie]

sbaglio?!
L'array lo devi dichiarare della dimensione massima a priori e poi non
devi sforare, pena un overflow dagli effetti non prevedibili a priori.
Se proprio vuoi una cosa che si ridimensioni devi implementartela tu
usando la memoria dinamica.
-- 
Mox

 usando la memoria dinamica.
con il discorso di malloc e un sizeof da qualche parte giusto!?
ergo devo mettere dei controlli per es while che un tot numero o caratteri
non vadano oltre il prestabilito, pena il reinserimento del valore! è errato
come ragionamento?
Thx
byez
B@STI


Mettiamo un caso banale: vuoi un array di interi ridimensionabile.
typedef struct int_vector int_vector;
struct int_vector {
    int * datapointer;
    int size;
    int asize;
}
Ora ti servono (detta in modo semplicistico, ma non e' il caso che
parliamo ora degli orpelli):
- una (collezione di) funzione(i) per inizializzare l'ADT
- una (collezione di) funzione(i) di inserimento elementi
- una (collezione di) funzione(i) di cancellazione elementi
Ora usi solo piu' queste funzioni, senza toccare a mano i campi della
struttura (uno dei principi di base della gestione degli oggetti).
Nella funzione di init ti ricordi di settare la size a 0, e la asize
alla dimensione massima dell'array (oltre che ad allocare spazio per
sto array, mi raccomando).
Quando inserisci prima controlli che size sia minore di asize e in
caso affermativo inserisci, se no devi provvedere a riallocare lo
spazio con la realloc.
Tutto questo ha un discreto costo, quindi anche se concepisci una
struttura del genere, dovresti limitarne i ridimensionamenti :)
Penso sia il modo piu' immediato di farlo, a meno che uno non voglia
pensare a una struttura piu' complessa, composta da tanti segmenti di
array linkati tra di loro per evitare il costo della realloc (che in
casi sfigati potrebbe doverti ricopiare tutto l'arra).
In ogni caso il principio non cambia: devi far inserire e cancellare
usando delle primitive apposite, se no non funziona piu' il giochino
della programmazione a oggetti :)
Non ti ho postato una riga di codice perche' non mi pareva il caso per
ora, perche' serve a poco che ti faccia vedere come a me piace
implementare una cosa del genere... e' piu' utile se provi tu.
Tip: se le prime volte (30 o 40) cordumpa e' normale, non ti
preoccupare :)
-- 
Mox

Ecco il tuo codice corretto.
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int* stringa;
int numero, i;
printf("Inserisci la quantità dei numeri che si intende ordinare: ");
scanf("%d",&numero);
if((stringa=(int *)malloc(numero*sizeof(int)))==NULL)
  {
    printf("Memoria insufficiente.\n");
    return 1;
  }
for(i=0;i<numero;i++)
  {
  printf("Inserisci il numero %d: ", i+1);


   }
Questo brano di codice contiene una ridondanza ed ingenera un dubbio che 
mi ha sempre lasciato interdetto e sul quale non mi sono mai preso la 
briga di riflettere il tempo dovuto per giungere ad una conclusione 
sensata, per cui ve lo espongo, cosi` mi confronto con le vostre 
esperienze e conoscenze.
La ridondanza e` il casting del valore ritornato dalla malloc(), resa 
inutile dal fatto che il C converte automaticamente il puntatore a void, 
tipo di ritorno della funzione in oggetto, al tipo della variabile cui 
esso viene assegnato.
Il dubbio e` il seguente: posto che malloc() non riesce ad ottenere dal 
sistema sufficiente memoria per le esigenze future del programma, e` 
ragionevole supporre che il programma stesso riesca a gestire la stampa 
del messaggio di errore? Ovvero, non e` pensabile che eventuali 
richieste di memoria nella printf() non ottengano la stessa risposta 
della malloc()?
Puo` sembrare un dubbio peregrino, tuttavia esistono almeno due casi nei 
quali l'eccezione per la mancanza di memoria e` gestita in modi che 
lasciano pensare che il porselo sia lecito. In particolare, mi riferisco 
alla versione della malloc() implementata nella glib, la quale, in caso 
di fallimento, provoca essa stessa la terminazione anormale del 
programma, ed una discussione di Stroustrup sulla terza edizione del suo 
libro sul C++, nel quale prende in considerazione la definizione di 
un'area di memoria di "emergenza" da utilizzare proprio in caso di 
fallimento dell'allocazione run-time.
Che ne pensate?
-- 
Baci,
Mony

 del messaggio di errore?
Se ci sono le condizioni per cui malloc() restituisca NULL, allora
vuol dire che il sistema ha cominciato a strisciare gia' da un bel
pezzo.  Il sistema si inchioda, a mio avviso, molto prima che malloc() 
possa restituire NULL.  In ogni caso, e' chiaro che e' ragionevole
supporre che il programma riesca a recuperare la condizione d'errore,
perche' molti sistemi potrebbero garantirlo.
Sotto Windows, sicuramente, il sistema sara' stato resettato dall'utente
molto prima che malloc() lo avvisi ;)
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 molto prima che malloc() lo avvisi ;)
Purtroppo, non ho un sistema Windows sotto mano, ma non stento a 
crederlo. ;)
-- 
Baci,
Mony

 crederlo. ;)
runtime error R6017
- unexpected multithread lock error
e una bella finestrella con scritto
Your system is running low on virtual memory.
Ma, almeno NT, sopravvive.


 Ma, almeno NT, sopravvive.
Perfetto, era quello che mi attendevo, scherzi a parte. L'importante, 
pero`, e` che riesca a stampare la stringa "Ouch!\n". Mi sai dire 
qualcosa in proposito? Grazie! ;)
-- 
Baci,
Mony

 qualcosa in proposito? Grazie! ;)
No, la stringa "Ouch!\n" non viene stampata. Il perche' bisognerebbe
chiederlo in quei di Redmond.
Quei "sistemi" sono sempre, come dire, "originali". :-)
C:\>iao Angelo


 Quei "sistemi" sono sempre, come dire, "originali". :-)
In ogni caso, questi test non offrono un granche' di conclusione,
se non quella che un programmino scritto in C cerca di prendere
per se' tutta la memoria e se non ci riesce reagisce diversamente,
a seconda del sistema, ma sempre in modo recuperabile.
Quello a cui io mi riferivo e' che uno stress *vero* del sistema,
potrebbe mettere il tuo programma nelle condizioni di non 
raggiungere mai il punto limite, perche' avra' cominciato il tutto
a funzionare in modo talmente lento che l'avrai resettato molto
prima ;)


 prima ;)
Sorge il lecito dubbio che talune piattaforme ti costringano a riavviare 
il sistema senza darti la possibilita` immediata di comprendere il 
motivo del rallentamento.
Chiudo con questa "chicca" suggeritami da un mio amico:
<code>
	#include <stdlib.h>
	int main(void) { while(1) malloc(1000); return 0; }
</code>
Buon warm reboot! ;)
-- 
Baci,
Mony

 a seconda del sistema, ma sempre in modo recuperabile.
Su questo non ci sono dubbi. Converrai che
" runtime error R6017
  - unexpected multithread lock error"
come tutti i messaggi di errore di Windows e' chiarissimo :-)
C:\>iao Angelo


 stile della glib. ;)
eh, ma comunque non ci fai nulla, con quella memoria, e resta solo 
virtualmente occupata: a me fallisce dopo aver ottenuto (mem totale+ 
swap), il che e' eccessivo, credo.
prova cosi', e vediamo :)
#include <stdio.h>
#include <stdlib.h>
void touch(char* p, long size) {
  while (size--) { *p = '\0'; ++p;} 
}
int main() {
  char* p;
  while((p = malloc(0x400000))!=NULL) touch(p,0x400000);
  while((p = malloc(0x10000))!=NULL) touch(p,0x10000);
  while((p = malloc(0x40))!=NULL) touch(p,0x40);
  while((p = malloc(1))!=NULL) touch(p,1);


 
Denigrare Windows e' uno dei miei sport preferiti, ma ti garantisco
che quel programma ad NT non fa niente.
Il sistema rimane usabile e ti consente di ammazzare il processo
senza problemi.
Se vuoi fare veramente male ad NT, Win200 &Co
prova 
#include <stdio.h>
int main(void)
{
   while(1)
      printf("\t\b\b");
   return 0;
}
Il riavvio e' garantito.
C:\>iao Angelo
P.S. Su OS X cosa succede con
int main(void)
{
   while(1)
      fork();
   return 0;
}
Ocio che Linux si e' congelato all'istante!


 perche' 5?
Quattro per le malloc() a livello piu` alto ed una, presumibilmente, per 
qualcosa di oscuro che accade all'interno della printf(). Lo stesso 
codice senza printf(), infatti, genera solo quattro messaggi di errore.
-- 
Baci,
Mony

 codice senza printf(), infatti, genera solo quattro messaggi di errore.
certo che se una malloc fallisce in una printf, e poi scrive lo stesso, 
i casi sono 2: o la libreria fa i salti mortali, oppure il warning e' 
tutta scena :)

Ocio che Linux si e' congelato all'istante!
<OT>
cavoli dell'amministratore.
man ulimit e vedrai che se ben settato una cosa del genere _NON_ fa
danni
</OT>
-- 
+---- | Un OS per domarli, Un OS per trovarli,             |  -o)
+---+ | Un OS per ghermirli e nel buio incatenarli         |  /\\
 O  | | Nella terra di Redmond, ove l'ombra cupa scende... | _\_V
                    raffaele punto salmaso presso libero punto it

come tutti i messaggi di errore di Windows e' chiarissimo :-)
ROTFL ! :)


della malloc()?
Io da molto tempo ho l'abitudine di considerare l'esaurimento della
memoria un errore fatale e che non merita di essere intercettato
se la quantita' di memoria e' ragionevolmente bassa.
Per fare questo scrivo sempre un mio allocatore che incapsula
la chiamata a malloc e che termina il programma se la memoria
non e' sufficiente.
Il motivo per cui lo faccio e' che il programma che scrivo
diventa tremendamente piu' semplice (grazie alla garanzia implicita
che tutte le allocazioni riescono... in altri termini il mio
allocatore "promette di piu'" e come tale e' piu' comodo da
utilizzare) e in secondo luogo se una allocazione di diciamo 100
byte fallisce secondo me ci sono buone probabilita' che ben poco
del resto delle funzioni di libreria possa essere utilizzato.
Aprire un file per salvare il lavoro dell'utente ? Dubito.
Aprire una finestra gui per informare l'utente ? non scherziamo.
L'utilizzare una funzione di allocazione custom mi permette
anche di affrontare il problema in modo piu' serio (se lo
desidero) ad esempio gestendo un "pool di riserva": se l'allocazione
fallisce allora genero un messaggio di allarme e rendo usabile
l'ultimo megabyte (messo da parte inizialmente) in modo da cercare
di offrire una via di fuga al povero utente. Anche in questo
caso il programma puo' restare molto "semplice" e ignaro di
questo meccanismo di sicurezza.
Per esperienza personale poi ti posso dire che il codice C
che cerca di gestire la memoria dinamica controllando il
risultato di ogni singola malloc e "disfando" tutte le mezze
operazioni compiute quando la memoria e' venuta a mancare
e' praticamente sempre errato (ovvero non libera tutto
e non rimette tutte le cose a posto).
Nulla di che stupirsi... il linguaggio non offre nulla per
aiutare in una simile complicatissima impresa.
Come ultima nota e' inoltre inutile verificare se la memoria
si esaurisce in tutti i sistemi dotati di memoria virtuale...
Il codice di intervento non verrebbe comunque mai invocato
visto che prima di finire la memoria il sistema andrebbe in
"trashing" paginando come un matto su disco...
In questi casi spesso il programma viene "ammazzato"
dall'esterno con il commento triste "si e' piantato" in modo
anche piu' brutale che con 'exit' perche' l'utente (giustamente)
non ha intenzione di aspettare che prima gli venga riempito
tutto il disco fisso oltre che la RAM.
Andrea

 tutta scena :)
Oppure esiste un pool di riserva, per i casi critici.
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
Mi piace avere amici rispettabili;
Mi piace essere il peggiore della compagnia.

se la quantita' di memoria e' ragionevolmente bassa.
Intendevo dire "se la quantita' di memoria -->richiesta<-- e'
ragionevolmente bassa".
Diverso e' il caso di allocazione, ad esempio, di una immagine
bitmap da 20 megabyte in cui controllare che l'allocazione riesca
e gestirne il fallimento mi sembra sensato e doveroso.
Andrea