PDA

Visualizza la versione completa : [C++] Leggere stringa che rappresenta comandi


Ippo343
25-10-2009, 02:32
Sto provando un nuovo problema di UVA, il 337 (http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=5&page=show_problem&problem=273).

In sostanza, al programma viene passato sullo standard input un file che rappresenta un misto di comandi e di testo che deve essere inserito su una specie di terminale. I comandi sono introdotti dal carattere ^. Sono tutti lunghi 2 caratteri (^ seguito da una lettera che da il comando), a parte uno che lungo 3 caratteri (^ seguito da 2 cifre).

Il file costituito da un numero che indica il numero di linee di input che seguono.

Il mio un problema di design, sulla lettura dell'input. Come dovrei leggerlo? E' possibile che l'input contenga degli spazi, quindi dovr usare gets immagino.

Non sapendo la lunghezza delle stringhe, come dovrei leggerlo? Pensavo di dichiarare un array di 3 caratteri e riempirlo leggendo un carattere alla volta da cin, non sapendo quanto pu essere lunga ogni riga di input.

Avete per caso qualche consiglio? Grazie...

ant_alt
25-10-2009, 14:14
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define isInteger(a) ((a>47&&a<57) ? (1) : (0))
int getCommand(char com, char opz='.'){
printf("%c\n\n",com);

if(com=='b');
if(com=='c');
if(com=='d');

if(opz!='.'){}
}


int main (){
char a[128],c,num;
int i;
// la variabile a contiene la riga (fgets())
while(scanf("%s",&a)!=0){
num=sprintf(NULL,"%s",a);
i=0;
for(c=a[i];i<num;i++){
if(a[i]=='^'){
if(isInteger(a[i+1]))
getCommand(a[i+1],a[i+2]);
else
getCommand(a[i+1]);
}
}

}

}




ti ho fatto la parte che intercetta i comandi, un p macchinosa ma semplice da capire anche se sei alle prime armi
sinceramente molti comandi parlano di spostare il cursore di righe o colonne, non mi viene in mente niente..quindi il programma in pieno cantiere :)

Ippo343
26-10-2009, 02:34
Sar molto imbarazzante per me confessare che non ho capito il tuo codice xD

In compenso il mio codice funzionare a parte che per un solo comando, quello che sposta il cursore alle coordinate (^##).



void ExecCommand()
{
//Una volta letto il ^ che introduce il comando
//leggo il carattere che rappresenta il comando
cin.get(ch);

if (isdigit(ch))
{
//Se il carattere trovato un numero, allora
//il comando ^##, perci leggo un altro carattere
//che rappresenta la seconda coordinata

char ch2;
cin.get(ch2);

//Sposto il cursore alle coordinate lette
MoveCursor(ch, ch2);
}
else { //altri comandi semplici }
}


Questo comando viene eseguito senza problemi, MA: qualsiasi (qualsiasi) cosa venga scritta dopo questo comando causa un segmentation fault. Tutti i comandi funzionano alla perfezione. Notare che se eseguo questo comando non ricevo il sigsev.

Esempio:

^11 funziona, ma
^11helloworld va in segmentation fault.

Sotto c' il codice completo:



#include <iostream>
#include <ctype.h>

using namespace std;

void ExecCommand();
void Output(char c);
void outIns(char c);
void outOW(char c);
void MoveCursor(int x, int y);
void ClampCursor();
void cls();
void EraseLine();
void PrintTerminal();

typedef enum OutputMode { insert, overWrite } OutputMode;

char scrBoxPart[] = "+----------+";

const int screenHeigth = 10;
const int screenWidth = 10;

int testCase = 0;

int cursorX;
int cursorY;

char** screen;
char ch;

OutputMode outMode;

int main()
{
int lnNumber, lnCount;

//Creates screen
screen = new char*[screenHeigth];
for (int i = 0; i < screenHeigth; i++)
screen[i] = new char[screenWidth];

//and clears it.
cls();

//Keeps running until the end of the file
while (true)
{
//resets the terminal.
testCase++;
lnNumber = lnCount = 0;
cursorX = cursorY = 0;
outMode = overWrite;
cls();

//Reads the number of input lines
//and exits if there is no data to process
cin >> lnNumber;
if (!lnNumber) return 0;
cin.get(ch);

//Keeps processing data until all
//the lines have been processed.
while (lnCount < lnNumber)
{

//Reads a char
cin.get(ch);

switch (ch)
{
case '^':
//it's a command
ExecCommand();
break;
case '\n':
//end of line
lnCount++;
break;
default:
//ch has to be output
Output(ch);
break;
}
}

PrintTerminal();
}

return 0;
}

//Executes the commands
void ExecCommand()
{
cin.get(ch);

/*If the command is a digit, the command
is in the form ^##, so you have to read the
second digit to have the full command*/
if (isdigit(ch))
{
char ch2;
cin.get(ch2);

//Moves the cursor
MoveCursor(ch, ch2);
}
else
{
//Runs the proper command.
switch (ch)
{
case 'b':
//move to line beginning
MoveCursor(0, cursorY);
break;
case 'c':
cls();
break;
case 'd':
//move down
MoveCursor(cursorX, (cursorY + 1));
break;
case 'e':
//erase everything at the right of the cursor
EraseLine();
break;
case 'h':
//move to the top left corner
MoveCursor(0, 0);
break;
case 'i':
//enters insert mode
outMode = insert;
break;
case 'l':
//move left
MoveCursor((cursorX - 1), cursorY);
break;
case 'o':
//enters overwrite mode
outMode = overWrite;
break;
case 'r':
//move right
MoveCursor((cursorX + 1), cursorY);
break;
case 'u':
//move up
MoveCursor(cursorX, (cursorY - 1));
break;
case '^':
//print a ^
Output('^');
break;
}
}
}

//Prints a character to the screen
void Output(char c)
{
switch (outMode)
{
case insert:
outIns(c);
break;
case overWrite:
outOW(c);
break;
}
}

void MoveCursor(int x, int y)
{
cursorX = x;
cursorY = y;

ClampCursor();
}

//Clamps the cursor to the screen
void ClampCursor()
{
if (cursorX < 0) cursorX = 0;
if (cursorX > (screenWidth - 1)) cursorX = (screenWidth - 1);
if (cursorY < 0) cursorY = 0;
if (cursorY > (screenHeigth - 1)) cursorX = (screenHeigth - 1);
}

void cls()
{
for (int y = 0; y < screenHeigth; y++)
for (int x = 0; x < screenWidth; x++)
screen[y][x] = ' ';
}

void EraseLine()
{
for (int x = cursorX; x < screenWidth; x++)
screen[cursorY][x] = ' ';
}

void outIns(char c)
{
for (int x = screenWidth - 1; x > cursorX; x--)
{
screen[cursorY][x] = screen[cursorY][x - 1];
}

screen[cursorY][cursorX] = c;

MoveCursor((cursorX + 1), cursorY);
}

void outOW(char c)
{
screen[cursorY][cursorX] = c;
MoveCursor((cursorX + 1), cursorY);
}

void PrintTerminal()
{
cout << "Case " << testCase << endl;
cout << scrBoxPart << endl;

for (int y = 0; y < screenHeigth; y++)
{
cout << '|' << screen[y] << '|' << endl;
}

cout << scrBoxPart << endl;
}

Ippo343
29-10-2009, 23:40
[Magari non interessa a nessuno]

Era come al solito una stupidata (degna di un programmatore stupido xD):



if (isdigit(ch))
{
char ch2 = 0;
cin.get(ch2);

//Moves the cursor
MoveCursor(ch, ch2);
}


se sul terminale mi scrivono ^12, ad esempio, viene letto il codice ascii di 1 e di 2, e non 1 e 2 stessi. Quindi il programma cerca di muovere il cursore a 48 e a 49, non 1 e 2. La correzione :



MoveCursor( (ch - 48), (ch2 - 48) );


Mettiamo che serva a qualcuno :P

ant_alt
29-10-2009, 23:53
il 99% dei segmentation fault di tutto il mondo sono accessi illegali :stordita:

l'hai mandato?
a me per altri problemi d sempre responso negativo, anche quando i programmi sono super-testati...

MItaly
30-10-2009, 00:20
Consiglio: sempre provare i programmi con valgrind per vedere se ci sono problemi (anche non evidenti) legati ad accessi alla memoria. Vi assicuro che fa miracoli.

Ippo343
30-10-2009, 13:49
Non l'ho ancora inviato perch ha ancora dei piccoli bug (il file di input che c' nella pagina non viene eseguito correttamente, e finch non riesco a far andare almeno quello non invio).

Quando torno do un'occhiata a valgrind, in questi giorni ero un po' preso. Ho il mio primo esame universitario tra 40 minuti :S

Loading