Pagina 1 di 2

[C] Errori e dubbi vari

Inviato: dom 20 lug 2008, 16:53
da anycolouryoulike
In seguito a questo 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

Re: [C] Errori e dubbi vari

Inviato: dom 20 lug 2008, 17:03
da phobos3576
'\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!

Re: [C] Errori e dubbi vari

Inviato: dom 20 lug 2008, 19:36
da gioco
Concordo con phobos3576.
Aggiungo:

qui

Codice: Seleziona tutto

if(c=getchar()&&(c='0'||c='1'))
mi sa che ci sono due assegnamenti di troppo.

Re: [C] Errori e dubbi vari

Inviato: dom 20 lug 2008, 19:54
da anycolouryoulike
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

Re: [C] Errori e dubbi vari

Inviato: dom 20 lug 2008, 21:57
da FireEater
Fai il debug del programma! Ti aiuterà sicuramente ad individuare l'istruzione colpevole.

Re: [C] Errori e dubbi vari

Inviato: dom 20 lug 2008, 22:25
da phobos3576
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);
}

Re: [C] Errori e dubbi vari

Inviato: dom 20 lug 2008, 22:43
da anycolouryoulike
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!

Re: [C] Errori e dubbi vari

Inviato: lun 21 lug 2008, 0:59
da Slippery
http://cvsweb.netbsd.org/bsdweb.cgi/~ch ... text/plain
Checchè ne dica la manpage, questa implementazione della malloc sembra fare effettivamente un memset a 0 della memoria

Re: [C] Errori e dubbi vari

Inviato: lun 21 lug 2008, 8:31
da Blizzard
Slippery ha scritto:http://cvsweb.netbsd.org/bsdweb.cgi/~ch ... 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

Re: [C] Errori e dubbi vari

Inviato: lun 21 lug 2008, 14:31
da anycolouryoulike
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?

Re: [C] Errori e dubbi vari

Inviato: lun 21 lug 2008, 15:15
da gioco
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.

Re: [C] Errori e dubbi vari

Inviato: lun 21 lug 2008, 16:06
da Blizzard
@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

Re: [C] Errori e dubbi vari

Inviato: lun 21 lug 2008, 16:14
da phobos3576
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 !

Re: [C] Errori e dubbi vari

Inviato: lun 21 lug 2008, 17:20
da 414N
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

Re: [C] Errori e dubbi vari

Inviato: lun 21 lug 2008, 18:10
da Blizzard
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???