Repository 32bit  Forum
Repository 64bit  Wiki

[C] Errori e dubbi vari

Forum dedicato alla programmazione.

Moderatore: Staff

Regole del forum
1) Citare in modo preciso il linguaggio di programmazione usato.
2) Se possibile portare un esempio del risultato atteso.
3) Leggere attentamente le risposte ricevute.
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.

[C] Errori e dubbi vari

Messaggioda anycolouryoulike » dom lug 20, 2008 15:53

In seguito a questo http://www.slacky.eu/forum/viewtopic.php?f=2&t=25445, sto cercando di fare un programmino per convertire una stringa binaria in ASCII.
A dire il vero per adesso mi basterebbe solo riuscire a memorizzare (forse c'è un termine più adatto per dirlo?) le cifre a 8 a 8, ma ottengo solo segmentation fault.
Probabilmente c'è un modo molto migliore per fare quello che sto cercando di fare, inoltre non ho idea di come fare la conversione.
Codice: Seleziona tutto
#include <malloc.h>
#include <stdio.h>

#define MAXLENGTH 1000

main()
{
  char **a=malloc(sizeof(char *)*MAXLENGTH/9);
  char *s=malloc(sizeof(char)*MAXLENGTH);
  int i,j,c;
  int k=1;
  for(i=j=0;k;i++)
    {
      *(a+i)=s+j;
      while(k&&j<8*(i+1)+i)
        {
          if(c=getchar()&&(c='0'||c='1'))
            *(s+j++)=c;
          else
            k=0;
        }
      *(s+j++)='\0';
    }
  if(k==0)
    {
      printf("Invalid string");
      exit(1);
    }
  for(j=0;j<=i;j++)
    puts(*(a+i));
  free(s);
  free(a);
}
E poi perché se invece di usare '\0' uso NULL mi dà errore?
Grazie
Avatar utente
anycolouryoulike
Packager
Packager
 
Messaggi: 1158
Iscritto il: gio ago 09, 2007 23:00
Slackware: 12.2
Kernel: 2.6.34.8
Desktop: KDE 3.5.10

Re: [C] Errori e dubbi vari

Messaggioda phobos3576 » dom lug 20, 2008 16:03

'\0' è un byte di valore ZERO che corrisponde al codice ASCII NUL (00h), da non confondere però con NULL che in C rappresenta un puntatore all'indirizzo del primo byte della RAM; in modalità protetta a 32 bit, quell'indirizzo vale 00000000h

Inoltre, questo qui:
Codice: Seleziona tutto
while(k&&j<8*(i+1)+i)

è un modo suicida di programmare!

Codice: Seleziona tutto
k && j < 8 * (i + 1) + i

Quale di queste operazioni viene eseguita per prima?
Ci si affida alle convenzioni sulla precedenza degli operatori, ma nemmeno chi ha scritto il programma poi riesce a capire il codice!
Avatar utente
phobos3576
Staff
Staff
 
Messaggi: 2980
Iscritto il: sab apr 16, 2005 23:00
Slackware: 13.1
Kernel: 2.6.37-smp
Desktop: KDE 4.5.3

Re: [C] Errori e dubbi vari

Messaggioda gioco » dom lug 20, 2008 18:36

Concordo con phobos3576.
Aggiungo:

qui
Codice: Seleziona tutto
if(c=getchar()&&(c='0'||c='1'))

mi sa che ci sono due assegnamenti di troppo.
Avatar utente
gioco
Packager
Packager
 
Messaggi: 900
Iscritto il: sab giu 18, 2005 23:00
Località: in the court of the Wesnoth king
Slackware: last stable

Re: [C] Errori e dubbi vari

Messaggioda anycolouryoulike » dom lug 20, 2008 18:54

Grazie ad entrambi.
Ho sistemato un paio di cose e reso leggibile:
Codice: Seleziona tutto
#include <malloc.h>
#include <stdio.h>

#define MAXLENGTH 1000

main ()
{
  char **a = malloc (sizeof (char *) * MAXLENGTH / 9);
  char *s = malloc (sizeof (char) * MAXLENGTH);
  int i, j, c;
  int k = 1;
  for (i = j = 0; k; i++)
    {
      *(a + i) = s + j;
      while (k && j < (8 * (i + 1) + i))
        {
          if (c = getchar () && (c == '0' || c == '1'))
            *(s + j++) = c;
          else
            k = 0;
        }
      *(s + j++) = '\0';
    }
  for (j = 0; j <= i; j++)
    puts (*(a + j));
  free (s);
  free (a);
}
Ma sempre segmentation fault:
Codice: Seleziona tutto
$ cat prova
0111000001110010011011110111011001100001
$ a.out < prova

zsh: segmentation fault  a.out < prova
Avatar utente
anycolouryoulike
Packager
Packager
 
Messaggi: 1158
Iscritto il: gio ago 09, 2007 23:00
Slackware: 12.2
Kernel: 2.6.34.8
Desktop: KDE 3.5.10

Re: [C] Errori e dubbi vari

Messaggioda FireEater » dom lug 20, 2008 20:57

Fai il debug del programma! Ti aiuterà sicuramente ad individuare l'istruzione colpevole.
Avatar utente
FireEater
Linux 2.6
Linux 2.6
 
Messaggi: 508
Iscritto il: sab feb 05, 2005 0:00
Località: Cagliari <---> Torino
Nome Cognome: Giuseppe M.
Slackware: Current
Kernel: 2.6.32.7-smp
Desktop: kde 4.3.4

Re: [C] Errori e dubbi vari

Messaggioda phobos3576 » dom lug 20, 2008 21:25

Salve.

Siamo Brian W. Kernighan e Dennis M. Ritchie; supponendo che i dati binari siano contenuti nel file binstream.bin, noi suggeriamo di procedere in questo modo:
Codice: Seleziona tutto
#include <stdio.h>

int main (void)
{
   FILE  *mystream = fopen("binstream.bin", "rb");
   int   nextbyte;
   
   while ((nextbyte = getc(mystream)) != EOF)
      printf("%c", nextbyte);

   fclose(mystream);
}
Avatar utente
phobos3576
Staff
Staff
 
Messaggi: 2980
Iscritto il: sab apr 16, 2005 23:00
Slackware: 13.1
Kernel: 2.6.37-smp
Desktop: KDE 4.5.3

Re: [C] Errori e dubbi vari

Messaggioda anycolouryoulike » dom lug 20, 2008 21:43

Sto facendo il debug con gdb. Incredibile quante cose si imparano!
Ad esempio, io sapevo che malloc non puliva la memoria, invece sto vedendo che ogni componente di s è uguale a \0. Come mai?

@phobos3576: lo terrò in considerazione, ormai però ho pensato troppo per rinunciare!
Avatar utente
anycolouryoulike
Packager
Packager
 
Messaggi: 1158
Iscritto il: gio ago 09, 2007 23:00
Slackware: 12.2
Kernel: 2.6.34.8
Desktop: KDE 3.5.10

Re: [C] Errori e dubbi vari

Messaggioda Slippery » dom lug 20, 2008 23:59

http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/lib/libc/stdlib/malloc.c?rev=1.52&content-type=text/plain
Checchè ne dica la manpage, questa implementazione della malloc sembra fare effettivamente un memset a 0 della memoria
Slippery
Linux 1.0
Linux 1.0
 
Messaggi: 44
Iscritto il: mer giu 25, 2008 17:52
Località: Treviso
Slackware: 12.2
Kernel: 2.6.29.1
Desktop: KDE 3.5.10

Re: [C] Errori e dubbi vari

Messaggioda Blizzard » lun lug 21, 2008 7:31

Slippery ha scritto:http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/lib/libc/stdlib/malloc.c?rev=1.52&content-type=text/plain
Checchè ne dica la manpage, questa implementazione della malloc sembra fare effettivamente un memset a 0 della memoria

casualità IMHO! :roll:

provate questo
Codice: Seleziona tutto
#include <stdio.h>

int main()
{
   char *p=malloc(100);
   
   printf("Print p: %s",p);
   
   p[0]=p[1]=p[2]='a';
   
   free(p);
   
   p=malloc(100);
   
   printf("\nPrint p riallocata: %s\n",p);
   
   return 0;
}


E' una sola istruzione! non fate l'errore di non considerare lo zeroing della memoria dopo una malloc. Il programma potrebbe esplodere anche la quinta volta che chiamate una funzione (e la malloc è in quella funzione). Ci sono capitato :D

ciao
Gio
Avatar utente
Blizzard
Master
Master
 
Messaggi: 1509
Iscritto il: mar gen 02, 2007 22:53
Nome Cognome: Giovanni Santostefano
Slackware: 12.2
Kernel: 2.6.27.7-smp
Desktop: Fluxbox

Re: [C] Errori e dubbi vari

Messaggioda anycolouryoulike » lun lug 21, 2008 13:31

Grazie.
Altra cosa:
The problem is distinguishing the end of input from valid data. The solution is that getchar
returns a distinctive value when there is no more input, a value that cannot be confused with
any real character. This value is called EOF, for ``end of file''. We must declare c to be a type
big enough to hold any value that getchar returns. We can't use char since c must be big
enough to hold EOF in addition to any possible char. Therefore we use int.
Ma EOF non è un carattere ASCII?
Perché non dovrebbe starci in un char?

@Blizzard:
Correggimi se sbaglio, ma quando stampi p, nel caso la memoria allocata non contenga un \0 prima della sua fine, potrebbe darti anche segmentation fault, giusto?
Avatar utente
anycolouryoulike
Packager
Packager
 
Messaggi: 1158
Iscritto il: gio ago 09, 2007 23:00
Slackware: 12.2
Kernel: 2.6.34.8
Desktop: KDE 3.5.10

Re: [C] Errori e dubbi vari

Messaggioda gioco » lun lug 21, 2008 14:15

Provato:
Codice: Seleziona tutto
printf("%d\n", EOF);
printf("%c\n", EOF);
?
EOF è una macro definita in stdio.h.
In ASCII c'è il carattere non stampabile, quello che si ottiene con CTRL-D, che mi sembra si chiami EOT (end of transmission), e viene normalmente usato per segnalare da linea di comando ad un programma interattivo che l'input è terminato (tipo se in bash si scrive "if [];", si da invio e poi si preme CTRL-D).
Sono però due cose diverse.
Avatar utente
gioco
Packager
Packager
 
Messaggi: 900
Iscritto il: sab giu 18, 2005 23:00
Località: in the court of the Wesnoth king
Slackware: last stable

Re: [C] Errori e dubbi vari

Messaggioda Blizzard » lun lug 21, 2008 15:06

@Blizzard:
Correggimi se sbaglio, ma quando stampi p, nel caso la memoria allocata non contenga un \0 prima della sua fine, potrebbe darti anche segmentation fault, giusto?

Nella maggior parte dei casi continua a stampare finchè non incontra un \0 ma penso qualora non ci siano \0 dovrebbe darti una bella segmentation fault.

Avevo scritto un post chilometrico ma l'ho cancellato.
Il fatto che azzeri la memoria mi ha incuriosito e l'ho riscontrato non solo nella malloc ma anche in altre cose.
Le variabili ad esempio non sono soggette a questa cosa ma ho fatto dei test ed ottenuto comportamenti strani (che non so fino a che punto possano essere random).

Ho il presentimento che il gcc si preoccupa per noi e non ce lo dice :D

ciao
Gio
Avatar utente
Blizzard
Master
Master
 
Messaggi: 1509
Iscritto il: mar gen 02, 2007 22:53
Nome Cognome: Giovanni Santostefano
Slackware: 12.2
Kernel: 2.6.27.7-smp
Desktop: Fluxbox

Re: [C] Errori e dubbi vari

Messaggioda phobos3576 » lun lug 21, 2008 15:14

EOF è un int!

Generalmente vale -1 ma è sempre un grave errore usare -1 al posto di EOF perché così facendo si rende il programma dipendente dal particolare SO usato.

Funzioni come int getchar(void) restituiscono, appunto, un int perchè, oltre a leggere caratteri, possono imbattersi nella fine dell'output indicata da un EOF che è un int e non un char !
Avatar utente
phobos3576
Staff
Staff
 
Messaggi: 2980
Iscritto il: sab apr 16, 2005 23:00
Slackware: 13.1
Kernel: 2.6.37-smp
Desktop: KDE 4.5.3

Re: [C] Errori e dubbi vari

Messaggioda 414N » lun lug 21, 2008 16:20

Questo thread mi ha stuzzicato e, per colpa di anycolouryoulike :D , mi sono messo sotto ad implementare un programmino per convertire da binario ad ASCII una stringa.
Qui sotto riporto il codice che ne è risultato. Probabilmente conterrà schifezze (sono un po' arrugginito col C), ma a me funziona.
Prendetene spunto tranquillamente:
Codice: Seleziona tutto
/*
bin2dec2ascii

A basic C program to convert a binary number to decimal and ASCII form,
without the use of strtol() like functions.

Made by 414N
*/



# include <stdio.h>
# include <malloc.h>
# include <string.h>
# include <ctype.h>
# include <stdlib.h>
# define MAXLENGTH 100

/*
This function checks that the char* given in input contains only '0' or '1'
Every other character (including newline, so be warned using fgets to read
the string from stdin) makes it fail.
Returns 0 if the given number is a valid binary number, -1 otherwise.
*/

int checkNumber (char *numToCheck);

/*
This function converts the given binary number (as a char sequence) to an unsigned decimal.
It ignores the sign.
*/

long convertToDec (char *numToConvert);

/*
This function converts the given binary number (as a char sequence) to a signed decimal.
*/

long convertToDecSign (char *numToConvert);

/*
This function returns the two's-complement of the binary number given in input.
This procedure is needed whenever you encounter a negative binary number (the
Most Significative Bit is set to '1') and you want to know its absolute value.
*/

char* c2 (char *number);

/*
This function returns the ASCII representation of the given binary string.
*/

char* convertToASCII (char *numToConvert);

/*
This function returns the byte index in input. The index starts at 1.
*/

char *getByte (int byteNum, char* string);

/*
This function adds '0's to the number given in order to align to a
multiple of 8
*/
void adjustBits (char *bits);


int main (int argc, char *argv[])
{
 
//   The pointer to the binary number to be read from stdin.
  char *binNumber = malloc ( (sizeof *binNumber) * MAXLENGTH );
 
  if (binNumber == NULL){
    fprintf (stderr, "First memory allocation failed. Exiting.\n");
    return 1;
  }

//   Read the number from stdin
 
  fprintf (stdout, "\nPlease enter the binary number.\n");
  fscanf (stdin, "%100s", binNumber);
  fprintf (stdout, "\nOk, you entered %s.", binNumber);
 
//   Checking that the number consists only of '0' and '1'.
 
  if (checkNumber(binNumber) != 0){
   
    fprintf (stderr, "\nYou entered an invalid binary number.\n");
    return 2;
   
  }
 
  fprintf (stdout, "\nDecimal conversion\n");
  fprintf (stdout, "\nWithout sign:\n\t%sb = %li\n", binNumber, convertToDec (binNumber));
  fprintf (stdout, "\nWith sign:\n\t%sb = %li\n", binNumber, convertToDecSign (binNumber));
 
  fprintf (stdout, "\nASCII conversion\n");
  adjustBits (binNumber);
  fprintf (stdout, "\n%s : %s\n", binNumber, convertToASCII(binNumber));
 
  free (binNumber);
 
  return 0;
}

int checkNumber (char *numToCheck)
{
  int i;
 
  for (i = 0; i < strlen (numToCheck); i++){
    if (numToCheck[i] != '0' && numToCheck[i] != '1')
      return -1;
  }
  return 0;
 
}

long convertToDec (char *numToConvert)
{
  int i;
  long num = 0;
  long exp = 1;
 
  for (i = strlen(numToConvert) - 1; i >= 0; i--){
    if (numToConvert[i] == '1')
      num += exp;
    exp *= 2;
  }
  return num;
}

long convertToDecSign (char *numToConvert)
{
 
  if (numToConvert[0] == '1'){
//     The number is negative.
    char *numC2 = c2 (numToConvert);
    return -1 * convertToDec(numC2);
   
  }else
    return convertToDec (numToConvert);
}

char* c2 (char *number)
{
  char *cNumber = NULL;
  int i = 0;
  int carry = 0;
 
  cNumber = malloc ( (sizeof *cNumber) * (strlen (number) + 1) );
 
  if (cNumber == NULL){
    fprintf (stderr, "\nMemory allocation error. Exiting.\n");
    exit (3);
  }
 
 
  for (i = 0; i <= strlen(number); i++)
    switch (number[i])
    {
      case '0':
        cNumber[i] = '1';
        break;
      case '1':
        cNumber[i] = '0';
        break;
      default:
        cNumber[i] = number[i];
    }
   
  for (i = strlen (cNumber) - 1, carry = 1; i >= 0; i--)
    switch (cNumber[i])
    {
      case '0':
        if (carry == 1){
          cNumber[i] = '1';
          carry = 0;
        }
        break;
      case '1':
        if (carry == 1)
          cNumber[i] = '0';
    }
   
  return cNumber;
}

char* convertToASCII (char *numToConvert)
{
  char *string = NULL;
  char *byte = NULL;
  int bytes = 0;
  int i = 0;
//   long number = 0;
  char character = '0';
   
//  First off, we align the bits to be a multiple of 8.   
 
  adjustBits (numToConvert); 
 
//   Next, we allocate the space to host the ASCII representation
//   of the binary number.
 
  bytes = strlen (numToConvert)/8;
 
  string = malloc ((sizeof *string) * bytes + 1);
  if (string == NULL){
    fprintf (stderr, "\nMemory allocation error. Exiting\n");
    exit (4);
  }
 
//   Now, for each byte contained inside the string, we
//   get its ASCII representation.

 
  for (i = 0; i < bytes; i++){
    byte = getByte (i + 1, numToConvert);
    if (strcmp (byte, "Error") == 0){
      fprintf (stderr, "\nError getting byte number %d out of %s", i + 1, numToConvert);
      exit (6);
    }
   
    character = (char) convertToDec (byte);
   
//     if (isgraph (character))
    string[i] = character;
   
  }
  string [i] = '\0';
 
  return string;
 
}

char* getByte (int byteNum, char* string)
{
  char *byte = NULL;
  int index1 = 0;
  int index2 = 0;
  int i = 0;
  int j = 0;
   
  if (byteNum > strlen (string) || byteNum <= 0)
    return "Error";

  index1 = (byteNum - 1) * 8;
  index2 = index1 + 7;
 
  byte = malloc ( (sizeof *byte) * 9 );
 
  if (byte == NULL){
    fprintf (stderr, "\nMemory allocation error. Exiting\n");
    exit (5);
  }
 
  for (i = index1, j = 0; i <= index2 || i < strlen (string); i++, j++)
    byte[j] = string [i];
  if (i != index2)
  byte[8] = '\0';
 
  return byte;
 
}

void adjustBits (char *bits)
{
  char *zeroes = NULL;
  char *newString = NULL;
  int i = 0;
 
  if (strlen (bits) % 8 != 0){
//     We need to fill the rest with '0's.
    int zerosToAdd = 8 - strlen(bits) % 8;
    zeroes = malloc ( (sizeof *zeroes) * zerosToAdd + 1);
    if (zeroes == NULL){
      fprintf (stderr, "\nMemory allocation error (zeroes). Exiting\n");
      exit (6);
    }
    for (i = 0; i < zerosToAdd; i++)
      zeroes[i] = '0';
    zeroes[zerosToAdd] = '\0';
   
    newString = malloc ( (sizeof *newString) * ( strlen(bits) + zerosToAdd) + 1);
    if (newString == NULL){
      fprintf (stderr, "\nMemory allocation error (newString). Exiting\n");
      exit (7);
    }
   
    strcpy (newString, zeroes);
    free (zeroes);
    strcat (newString, bits);
    strcpy (bits, newString);

  }
 
}

Una compilata con
Codice: Seleziona tutto
gcc -Wall file.c && ./a.out

e vai col lissio :D
Avatar utente
414N
Iper Master
Iper Master
 
Messaggi: 2882
Iscritto il: mer feb 13, 2008 16:19
Località: Bulagna
Slackware: 14.0 (x64)
Kernel: 3.2.29
Desktop: LXDE

Re: [C] Errori e dubbi vari

Messaggioda Blizzard » lun lug 21, 2008 17:10

scusate... non ho letto i codici :D
ma qui si parla di programmi che prendono in input una stringa di char 01 e ne restituiscono il corrispettivo ascii???
Avatar utente
Blizzard
Master
Master
 
Messaggi: 1509
Iscritto il: mar gen 02, 2007 22:53
Nome Cognome: Giovanni Santostefano
Slackware: 12.2
Kernel: 2.6.27.7-smp
Desktop: Fluxbox

Prossimo

Torna a Programmazione

Chi c’è in linea

Visitano il forum: Nessuno e 1 ospite