Diskuze: C-Maticová kalkulačka
V předchozím kvízu, Online test znalostí C++, jsme si ověřili nabyté zkušenosti z kurzu.


David Novák:8.4.2015 23:48
Tohle je projekt do programování v druhém semestru?
Jsou na vás nějak moc hodní..
No.. Co umíš? Dělal jsi nějaké I/O?
Před každou tou maticí máš zadané její rozměry.. Takže si je načteš,
naalokuješ prostor a pak načteš jednotlivé řádky.. jelikož víš, kolik
tam toho bude, tak to bude velmi jednoduchá funkce.
Jednotlivé hodnoty si převedeš pomocí strtod().. Hotovo
Jo a jednotlivé matice jsou odděleny prázdnými řádky.. A navíc taky
víš, kolik jich má být.. Ten vzorec na začátku musíš parsovat nebo je
pevně zadaný? Asi parsovat, co?
David Novák:9.4.2015 8:21
tak mohl bys udělat třeba pole struktur, ve kterých by byly operand1 a 2,
operace a pořadí...
ale je to jedinná zajímavější věc, v tom zadání.. takže bys to měl
udělat bez problému
Sedím u toho skoro celý den a jediné co jsem vytvořil je rozpoznání, kdy se má vytvořit
nová matice.. I když je to asi blbost...
char buffer[1024];
//čtení jednotlivých řádků
while (fscanf(psoubor, "\n", buffer) != EOF)
{
if (2 == sscanf(buffer, "%u %u", &radky, &sloupce))
{
Matice A;
A = novaMatice(radky, sloupce);
}
}
To ostatní nemůžu nějak rozlousknout :/
Jestli to chápu dobře, tak vstupní soubor má následující formát:
<výraz>
<prázdný řádek>
<počet_řádků> <počet_sloupců>
<1. řádek matice>
....
<N. řádek matice>
Přičemž počet matic zjistíš z výrazu tak, že se podíváš, kolik různých písmen tam je (stačí projít ten řetězec a nepočítat znaky jako závorky, krát, plus...).
Můžeš si klidně načtení jedné matice zapouzdřit do funkce. Přes fscanf půjde načíst první řádek a zjistit počet sloupců a řádků oné matice. Pak je otázka, jak dál postupovat. Já bych asi jednotlivé řádky matice získal tak, že bych načetl celou řádku ze souboru, rozdělil na čísla podle mezer a přes atoi převedl (nebo možná atof, něco takového).
Tím získáš všechny matice a stačí jen provést výpočet, tedy vyhodnotit výraz. Možná by nebylo špatné použít převést jej do reverzní polské notace (postfix), pak se vyhodnocuje dobře.
David Novák:9.4.2015 20:41
jen k těm atoi, atof.. To jsou nebezpečné funkce.. Pokud opravdu neví, co
dělá, tak by je neměl používat
Předpokládám, že určitě budou chtít ošetření chybových stavů a neočekávaných vstupních dat.. takže by to měl asi zabít, kdyby mu tam napsali třeba písmeno.. A to pomocí atof snadno a spolehlivě nepoznáš
takže dneska jsem udělal zjištění počtu matic, kde předám řádek a vyberu jen ty znaky..
int PocetMatic(char* radek[100])
{
int i = 0, j = 0, pocet = 0;
char znaky[10] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J' };
for (i; i < 100; i++)
{
for (j; j < 10; j++)
{
if(radek[i] == znaky[j])
{
pocet++;
znaky[j] = ' ';
}
}
}
return pocet;
}
a taky plnění pole matice daty, to sice ještě nemám odzkoušené, ale...
int i = 0, j = 0, pocet, pruchod = -1, radky, sloupce, idmatice = -1, indexVradku = 0;
char radek[100];
Matice* poleMatic;
//čtení jednotlivých řádků
while (fscanf(psoubor, "\n", radek) != EOF)
{
//zadani
if (pruchod == -1)
{
pocet = (PocetMatic(radek));
poleMatic = (Matice*)malloc(pocet * sizeof(Matice));
pruchod = 0;
continue;
}
//prazdny radek
else if (radek == NULL)
{
pruchod = 0;
i = 0;
j = 0;
indexVradku = 0;
idmatice++;
continue;
}
else
{
//pruchod = 0 značí, že jsem na řádku s rozměry => vytvoření nové matice
if (pruchod == 0)
{
radky = (int)radek[0];
sloupce = (int)radek[2];
poleMatic[idmatice] = novaMatice(radky, sloupce);
pruchod++;
}
//plnění matice
else
{
for (i; i<poleMatic[idmatice]->sloupce; i++)
{
poleMatic[idmatice]->data[j * poleMatic[idmatice]->sloupce + i] = (double)radek[indexVradku];
//zvětšení o 2, jelikoš mezery jsou liché znaky...
indexVradku += 2;
}
//na jakém jsem řádku v dalším průchodu
j++;
}
}
}
ale s tím výpočtem bych potřeboval pomoct... popř, jak spustit
konzolovku s parametry zadanýma v konzoli, neboli jak zjistím, co ze je za
příkazem: aplikace.exe
To s těmi znaky máš zbytečně složité A vůbec.. Nechápu moc, proč
takhle..
Asi mi něco
uniká.. máš to omezené na délku 100 znaků, což není úplně moc..
Kdybys to měl dovolené, řeknu, ať použiješ isalpha().. ale takhle si to budeš muset vytvořit.
Být tebou bych načítal prostě do konce řádku (po znacích) a uděláš jednoduchou podmínku:
if (znak >= 'A' && znak <= 'Z')
// něco dělám - např. kontrola, jestli už takový znak znám, jestli ne, zvýší počet
A máš to neomezené na
délku výrazu.. a není to omezené jen na 10 různých písmen máš všech
26..
Martin Dráb:11.4.2015 20:51
jen k těm atoi, atof....
To máš pravdu, problém je v tom, že z návratové hodnoty se nedá poznat, zda-li se konverze povedla či ne. Bral jsem to spíš jako jednoduchý postup, jak celý ten příklad začít postupně rozcházet.
David Novák:11.4.2015 20:55
Jo, je mi to jasné..
A neměla to být kritika nebo tak.. Spíš jsem to řekl kvůli němu - je
to začátečník, tak ať se neučí používat nebezpečné věci v reálných
programech
švrčajs:11.4.2015 21:26
To s tím počtem matic upravím... Ale mám jiný problém, chci udělat
funkci, která mi s daty předělá na double[], jako oddělovač bude logicky
mezera ale problém je v
tom, že nevím, jak to rozdělit... např. něco jako v c# string.split...
// KalkulackaZp2.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Nazev "nevim.txt"
struct Matice
{
int radky;
int sloupce;
int pocetPrvku;
double data[];
};
typedef struct Matice *Matice;
///vytvoření nové matice
struct Matice *novaMatice(int radky, int sloupce)
{
struct Matice *m;
m = calloc(sizeof m + radky * sloupce * sizeof(double), 1);
m->sloupce = sloupce;
m->radky = radky;
m->pocetPrvku = radky * sloupce;
return m;
}
//vrátí data z matice
double *VratData(Matice A)
{
return A->data;
}
int sectiMatice(Matice A, Matice B, Matice *C)
{
int i, pocetPrvku;
double *ARadky, *BRadky, *CRadky;
pocetPrvku = A->radky * A->sloupce;
if ((*C)->pocetPrvku >= pocetPrvku)
{
ARadky = A->data;
BRadky = B->data;
CRadky = (*C)->data;
}
else
{
*C = novaMatice(A->radky, A->sloupce);
ARadky = A->data;
BRadky = B->data;
CRadky = (*C)->data;
}
for (i = 0; i < pocetPrvku; i++)
{
*CRadky++ = *ARadky++ + *BRadky++;
}
return 0;
}
int vynasobMatice(Matice A, Matice B, Matice *C)
{
int i, j, k, pocetPrvku;
double *ARadek, *BSloupec, *radek, *sloupec, *vystup, suma;
if (A->sloupce == B->radky)
{
pocetPrvku = A->radky * B->sloupce;
if (((*C)->pocetPrvku >= pocetPrvku))
{
(*C)->radky = A->radky;
(*C)->sloupce = B->sloupce;
}
else
{
*C = novaMatice(A->radky, B->sloupce);
}
vystup = (*C)->data;
radek = ARadek = A->data;
for (i = 0; i < A->radky; i++)
{
sloupec = BSloupec = B->data;
for (k = 0; k < B->sloupce; k++, radek = ARadek, sloupec = ++BSloupec)
{
for (suma = 0, j = 0; j < A->sloupce; j++, radek++, sloupec += B->sloupce)
{
suma += *radek * *sloupec;
}
*vystup++ = suma;
}
radek = (ARadek += A->sloupce);
}
return pocetPrvku;
}
return -1;
}
int PocetMatic(char *radek)
{
int i, j, pocet = 0;
char znaky[10] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J' };
for (i = 0; i < 255; i++)
{
for (j = 0; j < 10; j++)
{
if(radek[i] == znaky[j])
{
pocet++;
znaky[j] = '.';
}
}
}
return pocet;
}
double* dataZtextu(char znaky[255], int sloupce)
{
}
void matice_print(Matice A)
{
unsigned i, j;
double *data;
printf("%u %u\n", A->radky, A->sloupce);
data = A->data;
for (i = 0; i < A->radky; i++)
{
for (j = 0; j < A->sloupce; j++) {
printf("%g ", *data++);
} putchar('\n');
}
}
int main()
{
int i = 0, j = 0, pocet, pruchod = -1, radky, sloupce, idmatice = -1, indexVradku = 0;
char radek[255];
Matice* poleMatic;
FILE * psoubor;
psoubor = fopen(Nazev, "r");
if (psoubor == NULL)
{
printf("zadani je prazdne");
return -1;
}
//čtení jednotlivých řádků
//while (fscanf(psoubor, " %244[^\n]", radek) != EOF)
while (fgets(radek, sizeof(radek), psoubor) != NULL)
{
//zadani
if (pruchod == -1)
{
pocet = (PocetMatic(radek));
poleMatic = (Matice*)malloc(pocet * sizeof(Matice));
pruchod++;
*radek = NULL;
continue;
}
//prazdny radek
else if (radek[0] == '\n')
{
pruchod = 0;
i = 0;
j = 0;
indexVradku = 0;
idmatice++;
*radek = NULL;
continue;
}
else
{
//pruchod = 0 značí, že jsem na řádku s rozměry => vytvoření nové matice
if (pruchod == 0)
{
radky = (int)radek[0] - 48;
sloupce = (int)radek[2] - 48;
poleMatic[idmatice] = novaMatice(radky, sloupce);
pruchod++;
*radek = NULL;
}
//plnění matice
else
{
for (i; i<poleMatic[idmatice]->sloupce; i++)
{
poleMatic[idmatice]->data[j * poleMatic[idmatice]->sloupce + i] = //pole pomocí dataZtextu (double)radek[indexVradku];
//zvětšení o 2, jelikoš mezery jsou liché znaky...
indexVradku += 2;
}
//na jakém jsem řádku v dalším průchodu
j++;
*radek = NULL;
}
}
}
system("pause");
return 0;
}
David Novák:11.4.2015 21:58
Tak buď použij funkci http://www.manpagez.com/man/3/strsep/
Nebo můžeš načítat po znacích do bufferu a ten pak převést pomocí strtod()
švrčajs:12.4.2015 1:01
Díky..
Ještě jeden asi stupidní dotaz, pole struktur mám správně vytvořené ? Chyby mi to nehází, ale při debugu si procházím jednotlivé proměnné a po alokování pole matic se mi v tom poli zobrazí jen jedna matice, což neodpovídá počtu např. malloc(3*sizeof(Matice))
Matice* poleMatic
poleMatic = (Matice*)malloc(pocet * sizeof(Matice));
David Novák:12.4.2015 17:02
Debugger si s polem příliš nerozumí a pokud ho nenastavíš správně,
získáš divné výsledky.. Doporučuju spíš vyzkoušet v praxi
Ručně si to takhle naalokuj a nasypej tam požadovaný počet matic.. a pak
to zkus z toho pole zase vypsat
David Novák:14.4.2015 12:52
no.. to je jediná obtížnější věc v celém zadání..
Zkus popřemýšlet.. Vezmi papír a napiš si kroky, které bys jako člověk dělal, kdybys to měl zpracovat.
Tak já to beru tak, asi jako každý že se nejdřív podívám,
jestli to obsahuje závorky, když jo, tak najdu to nejvnitřnější a pak to
nabaluju, ale nevím, jak to naprogramovat
jinak tady ta funkce, která mi řádek převede na čísla..
double* dataZtextu(char* znaky, int sloupce)
{
int i = 0, id = 0, ib = 0;
double* data = (double *)malloc(sloupce * sizeof(double));
char buffer[15];
while (znaky[i] != NULL)
{
if (znaky[i] != ' ' && znaky[i] != '\n')
{
buffer[ib] = znaky[i];
ib++;
i++;
}
else
{
data[id] = (double)strtod(buffer, NULL);
ib = 0;
i++;
id++;
memset(buffer, ' ', sizeof(buffer));
}
}
return data;
}
David Novák:14.4.2015 14:32
Tak si to zkus rozepsat fakt po atomických krocích, co děláš (aniž si to uvědomuješ).. Např.
1. Podívám se na první znak
2. Je to levá závorka?
ANO - Pamatuju si, že jsem ve výrazu.
3. Jdu na další znak.
4. Je to levá závorka?
ANO - Jsem ve výrazu?
ANO - Mám dva výrazy v sobě - musím najít dvě pravé závorky, abych měl kompletní výraz.
NE - Jsem ve výrazu
5. Je to pravá závorka?
ANO - Jsem ve výrazu?
ANO - Potřebný počet pravých závorek k ukončení výrazu - 1; Je potřebný počet nulový?
ANO - konec výrazu. Třeba si ho někam nakopíruju..
NE - hledá se dál
NE - pravá závorka a nejsem ve výrazu! Chyba!
atd.
Takhle nějak si to musíš rozložit na podproblémy.. Všímej, že ty operace, co jsem
prováděl jdou v C snadno napsat. Neber to ale, že by to muselo být tak, jak
jsem řekl..
To jsem tu
vymyslel během deseti minut jen tak.. Vůbec to nemusí fungovat.. A určitě
je spousta dalších přístupů a nejspíš i nějaký lepší..
Prostě přemýšlej a zkoušej. Ber to tak, jako bys to parsování měl
naučit někoho, kdo vůbec nic neumí.
Jo, asi to bude hromada ifů ... a když tak aplikace se má spouštět pomocí konzole
(kalkulacka.exe vstup.txt vystup.txt), jak se dostanu k těm parametrům vstup a
výstup ? Hledal jsem to na netu, ale docela z toho už chytám nervy
tak jsem ni nenašel
Takže, pokročil jsem, ale mám problém a nevím si s ním rady, když
spustím program, tak mi to hodí error s přístupem do pamětiUnhandled
exception at 0x00F516A1 in KalkulackaZp2.exe: 0xC0000005: Access violation
reading location 0x00000041. u funkce sectiMatice(..)
Nemrkl by na to někdo ?
zde je celý kód programu
// KalkulackaZp2.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define Nazev "nevim.txt"
#define POCETZNAKUNARADKU 255
///shunting-yard alg...
#define MAXOPSTACK 64
#define MAXNUMSTACK 64
enum { ASSOC_NONE = 0, ASSOC_LEFT, ASSOC_RIGHT };
struct Matice
{
char* jmeno;
int radky;
int sloupce;
int pocetPrvku;
double data[];
};
typedef struct Matice *Matice;
///vytvoření nové matice
struct Matice *novaMatice(int radky, int sloupce, char jmeno)
{
struct Matice *m;
m = calloc(sizeof m + radky * sloupce * sizeof(double), 1);
m->jmeno = jmeno;
m->sloupce = sloupce;
m->radky = radky;
m->pocetPrvku = radky * sloupce;
return m;
}
//vrátí data z matice
double *VratData(Matice A)
{
return A->data;
}
double sectiMatice(Matice *A, Matice *B, Matice *C)
{
int i, pocetPrvku;
double *ARadky, *BRadky, *CRadky;
pocetPrvku = (*A)->radky * (*A)->sloupce;
if ((*C)->pocetPrvku >= pocetPrvku)
{
ARadky = (*A)->data;
BRadky = (*B)->data;
CRadky = (*C)->data;
}
else
{
*C = novaMatice((*A)->radky, (*A)->sloupce, 'X');
ARadky = (*A)->data;
BRadky = (*B)->data;
CRadky = (*C)->data;
}
for (i = 0; i < pocetPrvku; i++)
{
*CRadky++ = *ARadky++ + *BRadky++;
}
return 0;
}
double vynasobMatice(Matice *A, Matice *B, Matice *C)
{
/*int i, j, k, pocetPrvku;
double *ARadek, *BSloupec, *radek, *sloupec, *vystup, suma;
if ((*A)->sloupce == (*B)->radky)
{
pocetPrvku = (*A)->radky * (*B)->sloupce;
if (((*C)->pocetPrvku >= pocetPrvku))
{
(*C)->radky = (*A)->radky;
(*C)->sloupce = (*B)->sloupce;
}
else
{
*C = novaMatice((*A)->radky, (*B)->sloupce, 'X');
}
vystup = (*C)->data;
radek = ARadek = A->data;
for (i = 0; i < A->radky; i++)
{
sloupec = BSloupec = B->data;
for (k = 0; k < B->sloupce; k++, radek = ARadek, sloupec = ++BSloupec)
{
for (suma = 0, j = 0; j < A->sloupce; j++, radek++, sloupec += B->sloupce)
{
suma += *radek * *sloupec;
}
*vystup++ = suma;
}
radek = (ARadek += A->sloupce);
}
return pocetPrvku;
}*/
return -1;
}
Matice EvalSoucet(Matice n, Matice m)
{
Matice C = NULL;
sectiMatice(n, m, &C);
return C;
}
Matice EvalNasobeni(Matice n, Matice m)
{
Matice C = NULL;
vynasobMatice(n, m, &C);
return C;
}
///předělat pomocí ifu...
int PocetMatic(char *radek)
{
int i, j, pocet = 0;
//dodělat na více znaků!
char znaky[10] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J' };
for (i = 0; i < POCETZNAKUNARADKU; i++)
{
for (j = 0; j < 10; j++)
{
if(radek[i] == znaky[j])
{
pocet++;
znaky[j] = '.';
}
}
}
return pocet;
}
double* dataZtextu(char* znaky, int sloupce)
{
int i = 0, id = 0, ib = 0;
double* data = (double *)malloc(sloupce * sizeof(double));
char buffer[15];
while (znaky[i] != NULL)
{
if (znaky[i] != ' ' && znaky[i] != '\n')
{
buffer[ib] = znaky[i];
ib++;
i++;
}
else
{
data[id] = (double)strtod(buffer, NULL);
ib = 0;
i++;
id++;
memset(buffer, ' ', sizeof(buffer));
}
}
return data;
}
Matice vratMatici(char name, Matice pole[], int pocetMatic)
{
int i = 0;
for (i; i < pocetMatic;i++)
{
if (pole[i]->jmeno == name)
{
return pole[i];
break;
}
}
return 0;
}
void matice_print(Matice A)
{
unsigned i, j;
double *data;
printf("%u %u\n", A->radky, A->sloupce);
data = A->data;
for (i = 0; i < A->radky; i++)
{
for (j = 0; j < A->sloupce; j++) {
printf("%g ", *data++);
} putchar('\n');
}
}
struct op_s {
char op;
int prec;
int assoc;
int unary;
Matice (*eval)(Matice a1, Matice a2);
} ops[] = {
{ '*', 8, ASSOC_LEFT, 0, EvalNasobeni },
{ '+', 5, ASSOC_LEFT, 0, EvalSoucet },
{ '(', 0, ASSOC_NONE, 0, NULL },
{ ')', 0, ASSOC_NONE, 0, NULL }
};
struct op_s *getop(char ch)
{
int i;
for (i = 0; i < sizeof ops / sizeof ops[0]; ++i) {
if (ops[i].op == ch) return ops + i;
}
return NULL;
}
struct op_s *opstack[MAXOPSTACK];
int nopstack = 0;
Matice numstack[MAXNUMSTACK];
int nnumstack = 0;
void push_opstack(struct op_s *op)
{
if (nopstack>MAXOPSTACK - 1) {
fprintf(stderr, "ERROR: Operator stack overflow\n");
exit(EXIT_FAILURE);
}
opstack[nopstack++] = op;
}
struct op_s *pop_opstack()
{
if (!nopstack) {
fprintf(stderr, "ERROR: Operator stack empty\n");
exit(EXIT_FAILURE);
}
return opstack[--nopstack];
}
void push_numstack(Matice M)
{
if (nnumstack > MAXNUMSTACK - 1)
{
fprintf(stderr, "ERROR: Number stack overflow\n");
exit(EXIT_FAILURE);
}
numstack[nnumstack++] = M;
}
Matice pop_numstack()
{
if (!nnumstack) {
fprintf(stderr, "ERROR: Number stack empty\n");
exit(EXIT_FAILURE);
} return numstack[--nnumstack];
}
void shunt_op(struct op_s *op)
{
struct op_s *pop;
Matice n1, n2;
if (op->op == '(')
{
push_opstack(op);
return;
}
else if (op->op == ')')
{
while (nopstack > 0 && opstack[nopstack - 1]->op != '(') {
pop = pop_opstack();
n1 = pop_numstack();
if (pop->unary) push_numstack(pop->eval(n1, 0));
else
{
n2 = pop_numstack();
push_numstack(pop->eval(n2, n1));
}
}
if (!(pop = pop_opstack()) || pop->op != '(')
{
fprintf(stderr, "ERROR: Stack error. No matching \'(\'\n");
exit(EXIT_FAILURE);
}
return;
}
if (op->assoc == ASSOC_RIGHT) {
while (nopstack && op->prec < opstack[nopstack - 1]->prec)
{
pop = pop_opstack();
n1 = pop_numstack();
if (pop->unary) push_numstack(pop->eval(n1, 0));
else
{
n2 = pop_numstack();
push_numstack(pop->eval(n2, n1));
}
}
}
else
{
while (nopstack && op->prec <= opstack[nopstack - 1]->prec)
{
pop = pop_opstack();
n1 = pop_numstack();
if (pop->unary) push_numstack(pop->eval(n1, 0));
else
{
n2 = pop_numstack();
push_numstack(pop->eval(n2, n1));
}
}
}
push_opstack(op);
}
int main(int argc, char *argv[])
{
int i = 0, j = 0, pocet, pruchod = -1, radky, sloupce, idmatice = -1, indexVpoli = 0, maticeJmeno = 'A';
double* dataRadek;
char radek[POCETZNAKUNARADKU];
char zadani[POCETZNAKUNARADKU];
Matice* poleMatic;
FILE * psoubor;
psoubor = fopen(Nazev, "r");
if (psoubor == NULL)
{
printf("zadani je prazdne");
return -1;
}
//čtení jednotlivých řádků
//while (fscanf(psoubor, " %244[^\n]", radek) != EOF)
while (fgets(radek, sizeof(radek), psoubor) != NULL)
{
//zadani
if (pruchod == -1)
{
memcpy(zadani, radek, strlen(radek) + 1);
pocet = (PocetMatic(radek));
poleMatic = (Matice*)malloc(pocet * sizeof(Matice));
pruchod++;
memset(radek, ' ', sizeof(radek));
continue;
}
//prazdny radek
else if (radek[0] == '\n')
{
pruchod = 0;
i = 0;
j = 0;
idmatice++;
memset(radek, ' ', sizeof(radek));
continue;
}
else
{
//pruchod = 0 značí, že jsem na řádku s rozměry => vytvoření nové matice
if (pruchod == 0)
{
dataRadek = dataZtextu(radek, 2);
radky = (int)dataRadek[0];
sloupce = (int)dataRadek[1];
poleMatic[idmatice] = novaMatice(radky, sloupce, maticeJmeno);
maticeJmeno++;
pruchod++;
memset(dataRadek, 0, sizeof(dataRadek));
memset(radek, ' ', sizeof(radek));
}
//plnění matice
else
{
dataRadek = dataZtextu(radek, poleMatic[idmatice]->sloupce);
for (i = 0; i<poleMatic[idmatice]->sloupce; i++)
{
poleMatic[idmatice]->data[j * poleMatic[idmatice]->sloupce + i] = dataRadek[i];
}
j++;
memset(radek, ' ', sizeof(radek));
}
}
}
///průběh výpočtu
Matice *tstart = NULL;
struct op_s startop = { 'X', 0, ASSOC_NONE, 0, NULL };
struct op_s *op = NULL;
Matice n1, n2;
struct op_s *lastop = &startop;
int indexwhile = 0;
//printf("%i", zadani[0]);
while (zadani[indexwhile] != '\n')
{
indexwhile++;
if (!tstart)
{
if ((op = getop(zadani[indexwhile-1]))) {
if (lastop && (lastop == &startop || lastop->op != ')'))
{
if (op->op != '(')
{
fprintf(stderr, "ERROR: Illegal use of binary operator (%c)\n", op->op);
exit(EXIT_FAILURE);
}
}
shunt_op(op);
lastop = op;
}
else if (zadani[indexwhile-1] >= 'A' && zadani[indexwhile-1] <= 'Z')
{
tstart = vratMatici(zadani[indexwhile-1], poleMatic, pocet);///funkci, která vrátí matici, dle jména!!!!!!;
i++;
}
else if (!isspace(zadani[indexwhile-1]))
{
i++;
fprintf(stderr, "ERROR: Syntax error\n");
return EXIT_FAILURE;
}
}
else
{
if (isspace(zadani[indexwhile-1]))
{
push_numstack(*tstart);
tstart = NULL;
lastop = NULL;
i++;
}
else if ((op = getop(zadani[indexwhile-1])))
{
push_numstack(*tstart);
tstart = NULL;
shunt_op(op);
lastop = op;
i++;
}
else if (!zadani[indexwhile-1] >= 'A' && zadani[indexwhile-1] <= 'Z')
{
fprintf(stderr, "ERROR: Syntax error\n");
i++;
return EXIT_FAILURE;
}
}
}
if (tstart) push_numstack(*tstart);
while (nopstack) {
op = pop_opstack();
n1 = pop_numstack();
if (op->unary) push_numstack(op->eval(n1, 0));
else {
n2 = pop_numstack();
push_numstack(op->eval(n2, n1));
}
}
if (nnumstack != 1) {
fprintf(stderr, "ERROR: Number stack has %d elements after evaluation. Should be 1.\n", nnumstack);
return EXIT_FAILURE;
}
matice_print(numstack[0]);
system("pause");
return 0;
}
a zadání:
(A + B)
2 3
1.1 1 2
4 5 6
3 4
1 2 3 4
5 6 7 8
9 0 1 2
takže tohle jsem si už
vyřešil... Ale vyskytl se další problém, kalkulačka funguje, tak jak má,
ovšem, když jí spustím pomocí konzole, předám vstupní a výstupní
soubor, tak přestane pracovat... Dal jsem ladit a hodilo mi to ve VS error:
Unhandled exception at 0x77165624 (ntdll.dll) in KalkulackaZp2.exe: 0xC0000374:
Halda byla poškozena (parameters: 0x77181378). Chyba je v souboru malloc.c
takhle otevírám soubory...
FILE *s_vstup, *s_vystup;
s_vstup = fopen(*argv[0], "r");
s_vystup = fopen(*argv[1], "a+");
Neví někdo, kde by mohl být problém?
Jakub Horák:24.4.2015 14:43
Pokud vím, tak v argv[0] je první věc na příkazovém řádku = jméno programu, který spouštíš. Parametry jsou až od argv[1].
to jsem upravila na agrv[1], argv[2]... Kalkulačka se při spuštění pomocí cmd, dostane až k cyklu, kde se provádí samotný výpočet a tam spadne se stejným errorem :/ ale to už fakt nevím, co s tím, protože když do těch souborů dám napevno název a spustím ve visual studiu, tak to běží...
Libor Šimo (libcosenior):25.4.2015 15:46
FILE *s_vstup, *s_vystup;
s_vstup = fopen(*argv[0], "r");
s_vystup = fopen(*argv[1], "a+");
Nemas to osetrene.
švrčajs:25.4.2015 16:17
Tady v tom problém asi nebude.. Nebo spíše, co nemám ošetřené ? když je argv = NULL ?
Libor Šimo (libcosenior):25.4.2015 16:25
Asi tak. Druha vec, ked ti toidevo VS av conzole nie, skes to v code blocks a daj si tam volby, ako pisal david novak v clanku o nom. Malby ti vypisat chyby.
Boze, samy preklep
Boze, samy preklep
švrčajs:25.4.2015 17:11
No v CodeBlocku se mi to
ani nespustí
ale určitě
to bude nějaká kravinka
asi se poptám učitele
Libor Šimo (libcosenior):25.4.2015 17:15
Urcite sa neda skompilovat a vypisuje chyby ...
no error list mám čistý, tak nevím no... Jinak na linku je celá appka
(http://leteckaposta.cz/908170318) kdyby se někdo nudil a
nešel by ten problém, byl bych hodně vděčný
David Novák:25.4.2015 20:14
No.. Nevím, jestli je to tím, ale před argv se typicky hvězdička
nedává
Navíc to rozhodně ošetři.. Nějak takhle:
if (!(s_vstup = fopen(argv[1], "r")))
{
fprintf(stderr, "File cannot be open\n");
return 1;
}
Pokud to problém neřeší, můžeš zkusit dosadit místo argv přímo
název tvého souboru. Pokud to ani pak nebude fungovat, problém je jinde..
PS: Pokud bys sem znova dával celý kód, tak kdyžtak jen odkaz na nějaký
pastebin nebo tak..
švrčajs:25.4.2015 20:23
No, když tam dosadím soubory ručně, tak se to vypočítá, vypíše se výsledná matice na konzoli, ale neuloží do souboru... Když to pustím pomocí cmd s parametrama, tak se jen načte zadání, vytvoří matice a pak to spadne, což je divné..
David Novák:25.4.2015 20:27
tak to je problém asi s přístupovými právy k zápisu do souboru..
když ten soubor (do kterého chceš zapisovat) normálně otevřeš v notepad a změníš, jde bez problému uložit?
problém při tisknutí matice do souboru je v této funkci v souboru output.c
#else /* _UNICODE */
if (flags & (FL_LONG|FL_WIDECHAR)) {
if (text.wz == NULL) /* NULL passed, use special string */
text.wz = __wnullstring;
bufferiswide = 1;
pwch = text.wz;
while ( i-- && *pwch )
++pwch;
textlen = (int)(pwch - text.wz);
/* textlen now contains length in wide chars */
} else {
if (text.sz == NULL) /* NULL passed, use special string */
text.sz = __nullstring;
p = text.sz;
while (i-- && *p) //přesněji tady...
++p;
textlen = (int)(p - text.sz); /* length of the string */
}
v mé funkci:
void uloz_matici_do_souboru(Matice A, char *soubor)
{
printf("Uklada se matice do vystupniho souboru...");
int i, j;
double *data;
fprintf(soubor,"%u u%\n", A->radky, A->sloupce);
data = A->data;
for (i = 0; i < A->radky; i++)
{
for (j = 0; j < A->sloupce; j++) {
fprintf(soubor, "%g ", *data++);
}
if (i < A->radky - 1) fprintf(soubor, "\n", NULL);
}
}
Jakmile se projedou fory a funkce má končit, vyhodí to error... Zkoušel jsem i založit nový projekt, jestli jsem nepřepsal omylem vnitřní soubory, ale to taky nepomohlo.. Fakt už nevím, co s tím..
švrčajs:28.4.2015 17:32
Překvapivě jednoduché řešení bylo místo fopen použit freopen, s tím to jede bez problémů... Ale furt je problém s tím, když to spustím pomocí té konzole, že mi to spadne a hodí to error s porušenou haldou ve funkci
__forceinline void * __cdecl _heap_alloc (size_t size)
{
if (_crtheap == 0) {
#if !defined (_CRT_APP) || defined (_DEBUG)
_FF_MSGBANNER(); /* write run-time error banner */
_NMSG_WRITE(_RT_CRT_NOTINIT); /* write message */
#endif /* !defined (_CRT_APP) || defined (_DEBUG) */
__crtExitProcess(255); /* normally _exit(255) */
}
return HeapAlloc(_crtheap, 0, size ? size : 1);
}
v souboru malloc.c...
hledal jsem na netu i jiné způsoby, jak otevřít soubory pomocí te konzole, ale nic jsem nenašel...
Když to spustím konzolí, tak se načtou matice do pole, zadání do charu,
ale samotný výpočet se již neprovede... Docela z toho chytám nervy, když
ve VS to jde, ale pomocí konzole ne
// KalkulackaZp2.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define Nazev "nevim.txt"
#define POCETZNAKUNARADKU 255
///shunting-yard alg...
#define MAXOPSTACK 64
#define MAXNUMSTACK 64
enum { ASSOC_NONE = 0, ASSOC_LEFT, ASSOC_RIGHT };
struct Matice
{
char* jmeno;
int radky;
int sloupce;
int pocetPrvku;
double data[];
};
typedef struct Matice *Matice;
///vytvoření nové matice
struct Matice *novaMatice(int radky, int sloupce, char jmeno)
{
struct Matice *m;
m = calloc(sizeof m + radky * sloupce * sizeof(double), 1);
m->jmeno = jmeno;
m->sloupce = sloupce;
m->radky = radky;
m->pocetPrvku = radky * sloupce;
return m;
}
//vrátí data z matice
double *VratData(Matice A)
{
return A->data;
}
void matice_print(Matice A)
{
int i, j;
double *data;
printf("%u %u\n", A->radky, A->sloupce);
data = A->data;
for (i = 0; i < A->radky; i++)
{
for (j = 0; j < A->sloupce; j++) {
printf("%d ", *data++);
} putchar('\n');
}
}
double sectiMatice(Matice A, Matice B, Matice *C)
{
int i, pocetPrvku;
double *ARadky, *BRadky, *CRadky;
pocetPrvku = A->radky * A->sloupce;
if ((*C)->pocetPrvku >= pocetPrvku)
{
ARadky = A->data;
BRadky = B->data;
CRadky = (*C)->data;
}
else
{
(*C) = novaMatice(A->radky, B->sloupce, ' ');
ARadky = A->data;
BRadky = B->data;
CRadky = (*C)->data;
}
for (i = 0; i < pocetPrvku; i++)
{
*CRadky++ = *ARadky++ + *BRadky++;
}
return 0;
}
double vynasobMatice(Matice A, Matice B, Matice *C)
{
int i, j, k, pocetPrvku;
double *ARadek, *BSloupec, *radek, *sloupec, *vystup, suma;
if (A->sloupce == B->radky)
{
pocetPrvku = A->radky * B->sloupce;
if (((*C)->pocetPrvku >= pocetPrvku))
{
(*C)->radky = A->radky;
(*C)->sloupce = B->sloupce;
}
else
{
*C = novaMatice(A->radky, B->sloupce, 'X');
}
vystup = (*C)->data;
radek = ARadek = A->data;
for (i = 0; i < A->radky; i++)
{
sloupec = BSloupec = B->data;
for (k = 0; k < B->sloupce; k++, radek = ARadek, sloupec = ++BSloupec)
{
for (suma = 0, j = 0; j < A->sloupce; j++, radek++, sloupec += B->sloupce)
{
suma += *radek * *sloupec;
}
*vystup++ = suma;
}
radek = (ARadek += A->sloupce);
}
return pocetPrvku;
}
}
Matice EvalSoucet(Matice n, Matice m)
{
Matice C = novaMatice(0, 0, ' ');
sectiMatice(n, m, &C);
return C;
}
Matice EvalNasobeni(Matice n, Matice m)
{
Matice C = novaMatice(0, 0, ' ');
vynasobMatice(n, m, &C);
return C;
}
///předělat pomocí ifu...
int PocetMatic(char *radek)
{
int i, j, pocet = 0;
//dodělat na více znaků!
char znaky[12] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L' };
for (i = 0; i < POCETZNAKUNARADKU; i++)
{
for (j = 0; j < 10; j++)
{
if(radek[i] == znaky[j])
{
pocet++;
znaky[j] = '.';
}
}
}
return pocet;
}
double* dataZtextu(char* znaky, int sloupce)
{
int i = 0, id = 0, ib = 0;
double* data = (double *)malloc(sloupce * sizeof(double));
char buffer[15];
while (znaky[i] != NULL)
{
if (znaky[i] != ' ' && znaky[i] != '\n')
{
buffer[ib] = znaky[i];
ib++;
i++;
}
else
{
data[id] = (double)strtod(buffer, NULL);
ib = 0;
i++;
id++;
memset(buffer, ' ', sizeof(buffer));
}
}
return data;
}
Matice vratMatici(char name, Matice pole[], int pocetMatic)
{
int i = 0;
for (i; i < pocetMatic;i++)
{
if (pole[i]->jmeno == (char)name)
{
return pole[i];
}
}
return 0;
}
void uloz_matici_do_souboru(Matice A, char *soubor)
{
printf("Uklada se matice do vystupniho souboru...");
FILE *s_vystup;
s_vystup = freopen(soubor, "w", stdout);
int i, j;
double *data;
fprintf(s_vystup, "%i ", A->radky);
fprintf(s_vystup, "%i\n", A->sloupce);
data = A->data;
for (i = 0; i < A->radky; i++)
{
for (j = 0; j < A->sloupce; j++) {
fprintf(s_vystup, "%.2f ", *data++);
}
fprintf(s_vystup, "\n", NULL);
}
fclose(s_vystup);
}
struct op_s {
char op;
int prec;
int assoc;
int unary;
Matice (*eval)(Matice a1, Matice a2);
} ops[] = {
{ '*', 8, ASSOC_LEFT, 0, EvalNasobeni },
{ '+', 5, ASSOC_LEFT, 0, EvalSoucet },
{ '(', 0, ASSOC_NONE, 0, NULL },
{ ')', 0, ASSOC_NONE, 0, NULL }
};
struct op_s *getop(char ch)
{
int i;
for (i = 0; i < sizeof ops / sizeof ops[0]; ++i) {
if (ops[i].op == ch) return ops + i;
}
return NULL;
}
struct op_s *opstack[MAXOPSTACK];
int nopstack = 0;
/////////////////
Matice numstack[MAXNUMSTACK];
int nnumstack = 0;
void push_opstack(struct op_s *op)
{
if (nopstack>MAXOPSTACK - 1) {
fprintf(stderr, "ERROR: Operator stack overflow\n");
exit(EXIT_FAILURE);
}
opstack[nopstack++] = op;
}
struct op_s *pop_opstack()
{
if (!nopstack) {
fprintf(stderr, "ERROR: Operator stack empty\n");
exit(EXIT_FAILURE);
}
return opstack[--nopstack];
}
void push_numstack(Matice M)
{
if (nnumstack > MAXNUMSTACK - 1)
{
fprintf(stderr, "ERROR: Number stack overflow\n");
exit(EXIT_FAILURE);
}
numstack[nnumstack++] = M;
}
Matice pop_numstack()
{
if (!nnumstack) {
fprintf(stderr, "ERROR: Number stack empty\n");
exit(EXIT_FAILURE);
} return numstack[--nnumstack];
}
void shunt_op(struct op_s *op)
{
struct op_s *pop;
Matice n1, n2;
if (op->op == '(')
{
push_opstack(op);
return;
}
else if (op->op == ')')
{
while (nopstack > 0 && opstack[nopstack - 1]->op != '(') {
pop = pop_opstack();
n1 = pop_numstack();
if (pop->unary) push_numstack(pop->eval(n1, 0));
else
{
n2 = pop_numstack();
push_numstack(pop->eval(n1, n2));
}
}
if (!(pop = pop_opstack()) || pop->op != '(')
{
fprintf(stderr, "ERROR: Stack error. No matching \'(\'\n");
exit(EXIT_FAILURE);
}
return;
}
if (op->assoc == ASSOC_RIGHT) {
while (nopstack && op->prec < opstack[nopstack - 1]->prec)
{
pop = pop_opstack();
n1 = pop_numstack();
if (pop->unary) push_numstack(pop->eval(n1, 0));
else
{
n2 = pop_numstack();
push_numstack(pop->eval(n2, n1));
}
}
}
else
{
while (nopstack && op->prec <= opstack[nopstack - 1]->prec)
{
pop = pop_opstack();
n1 = pop_numstack();
if (pop->unary) push_numstack(pop->eval(n1, 0));
else
{
n2 = pop_numstack();
push_numstack(pop->eval(n2, n1));
}
}
}
push_opstack(op);
}
int main(int argc, char *argv[])
{
//if (argv[1] = NULL || argv[2] = NULL) return EXIT_FAILURE;
int i = 0, j = 0, pocet, pruchod = -1, radky, sloupce, idmatice = -1, indexVpoli = 0, maticeJmeno = 'A';
double* dataRadek;
char radek[POCETZNAKUNARADKU];
char zadani[POCETZNAKUNARADKU];
Matice* poleMatic;
FILE *s_vstup;
s_vstup = freopen(argv[1], "r", stdin);
if (s_vstup == NULL)
{
printf("Zadani je prazdne...\n");
return -1;
}
//čtení jednotlivých řádků
//while (fscanf(s_vstup, " %244[^\n]", radek) != EOF)
printf("Probiha nacteni zadani a vytoreni matic...\n");
while (fgets(radek, sizeof(radek), s_vstup) != NULL)
{
//zadani
if (pruchod == -1)
{
memcpy(zadani, radek, strlen(radek) + 1);
pocet = (PocetMatic(radek));
poleMatic = (Matice*)malloc(pocet * sizeof(Matice));
pruchod++;
memset(radek, ' ', sizeof(radek));
continue;
}
//prazdny radek
else if (radek[0] == '\n')
{
pruchod = 0;
i = 0;
j = 0;
idmatice++;
memset(radek, ' ', sizeof(radek));
continue;
}
else
{
//pruchod = 0 značí, že jsem na řádku s rozměry => vytvoření nové matice
if (pruchod == 0)
{
dataRadek = dataZtextu(radek, 2);
radky = (int)dataRadek[0];
sloupce = (int)dataRadek[1];
poleMatic[idmatice] = novaMatice(radky, sloupce, maticeJmeno);
maticeJmeno++;
pruchod++;
memset(dataRadek, 0, sizeof(dataRadek));
memset(radek, ' ', sizeof(radek));
}
//plnění matice
else
{
dataRadek = dataZtextu(radek, poleMatic[idmatice]->sloupce);
for (i = 0; i<poleMatic[idmatice]->sloupce; i++)
{
poleMatic[idmatice]->data[j * poleMatic[idmatice]->sloupce + i] = dataRadek[i];
}
j++;
memset(radek, ' ', sizeof(radek));
}
}
}
///průběh výpočtu
Matice tstart = NULL;
struct op_s startop = { 'X', 0, ASSOC_NONE, 0, NULL };
struct op_s *op = NULL;
Matice n1, n2;
struct op_s *lastop = &startop;
int indexwhile = 0;
printf("Probiha vypocet...\n");
while (zadani[indexwhile] != '\n')
{
indexwhile++;
if (!tstart)
{
if ((op = getop(zadani[indexwhile-1]))) {
if (lastop && (lastop == &startop || lastop->op != ')'))
{
if (op->op != '(')
{
fprintf(stderr, "ERROR: Illegal use of binary operator (%c)\n", op->op);
exit(EXIT_FAILURE);
}
}
shunt_op(op);
lastop = op;
}
else if (zadani[indexwhile-1] >= 'A' && zadani[indexwhile-1] <= 'Z')
{
tstart = vratMatici(zadani[indexwhile-1], poleMatic, pocet);///funkci, která vrátí matici, dle jména!!!!!!;
i++;
}
else if (!isspace(zadani[indexwhile-1]))
{
i++;
fprintf(stderr, "ERROR: Syntax error\n");
return EXIT_FAILURE;
}
}
else
{
if (isspace(zadani[indexwhile-1]))
{
push_numstack(tstart);
tstart = NULL;
lastop = NULL;
i++;
}
else if ((op = getop(zadani[indexwhile-1])))
{
push_numstack(tstart);
tstart = NULL;
shunt_op(op);
lastop = op;
i++;
}
else if (!zadani[indexwhile-1] >= 'A' && zadani[indexwhile-1] <= 'Z')
{
fprintf(stderr, "ERROR: Syntax error\n");
i++;
return EXIT_FAILURE;
}
}
}
if (tstart) push_numstack(tstart);
while (nopstack) {
op = pop_opstack();
n1 = pop_numstack();
if (op->unary) push_numstack(op->eval(n1, 0));
else {
n2 = pop_numstack();
push_numstack(op->eval(n2, n1));
}
}
if (nnumstack != 1) {
fprintf(stderr, "ERROR: Number stack has %d elements after evaluation. Should be 1.\n", nnumstack);
return EXIT_FAILURE;
}
matice_print(numstack[0]);
uloz_matici_do_souboru(numstack[0], argv[2]);
return EXIT_SUCCESS;
system("pause");
return 0;
}
Libor Šimo (libcosenior):30.4.2015 7:46
A ko posledné je celý program, dal som to do Code:Blocks a nastavil:
gcc -std=c99 -Wall -Wextra -pedantic
Vyhodilo to 8 warningov a každý z nich môže spôsobovať problém. Tak sa
najprv zbav warningov.
V prílohe.
Libor Šimo (libcosenior):30.4.2015 12:25
Začal som pomaly odstraňovať warningy a ukazujú sa stále nové errory aj
warningy. Už sa mi nechce, je to na dlho.
VS podľa všetkého nedostatky v kóde odstráni sám, ale conzola nie. To
musíš sám, ale odporúčam v Code:Blocks a pridaj si do volieb ešte aj
-Werror, aby si to nemohol scompilovať, kým nebudú všetky warningy
odstránené.
Voľby teda budú:
gcc -std=c99 -Wall -Wextra -Werror -pedantic
Navyše by si mal program písať ako projekt a podeliť ho na malé kompaktné časti, bude to podstatne prehľadnejšie.
David Novák:30.4.2015 12:40
hlavně mrkni na chyby na řádcích 34, 169, 199, 253.. to jsou obvykle
největší "střelby do nohy".. jestli tam někde pracuješ s ukazatelem jako s
číslem, nemůžeš se divit, že to nefunguje
Libor Šimo (libcosenior):30.4.2015 12:42
Presne tútu chybu som zanamenal niekoľko krát.
švrčajs:30.4.2015 14:33
Díky za rady, opravil jsem, co se dalo snad ... Bohužel v CodeBlocku si to
nespustím, jelikož mi háže error, že mu chybí GCC, i po doinstalování...
a ve virtuálu je to strašně pomalé..
Tak CodeBlock už jsem opravil ale teď mám problém, přidám si v CB do projektu txt soubory a
když je chci otevřít, hodí to error s tím, že soubor nebyl nalezen..
cestu k souboru mám dobře...
s_vstup = freopen("C:\Users\Havana\Desktop\kalkulacka\vstup.txt", "r", stdin);
Zobrazeno 50 zpráv z 57.