Načtení znaků ze souboru do matice – C / C++ – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Načtení znaků ze souboru do matice – C / C++ – Fórum – Programujte.comNačtení znaků ze souboru do matice – C / C++ – Fórum – Programujte.com

 

Sprinter
~ Anonymní uživatel
102 příspěvků
7. 1. 2013   #1
-
0
-

Ahoj,

mám soubor "temp.txt", kam ukládám matici v následujícím formátu:

M   +   (   )   d   *

S   1   1   -   -   2

A   5   3   5  -   -   

B   4   -   -   -   4

Jedná se tedy o matici různých znaků (ne jen intů). Já bych tuto matici chtěl načíst do dvourozměrného pole.

Našel jsem si tady na fóru, že už se to řešilo, použil jsem tedy kód, který tu byl k dispozici - ovšem nefunguje a já se už tři hodiny snažím najít chybu... pokud byste mi pomohli, byl bych rád :-)

Zjistil jsem, že chyba (zacyklení) je způsobena druhým while cyklem v tomto úseku kódu:

while((c = getc(fr)) != EOF) /* přečtení souboru */
{
	printf("1. while\n");
	while((c =getc(fr)) != '\n')
	{
		printf("2. while\n");
		if(c == ' ' ) //mezer je vzdy o 1 min nez cisel , nekde pridat +1
		{ 
			velikostiMnozin[i]++;
		}
	}
	velikostiMnozin[i]++; // zde pridavam tu +1
	i++;
}

Chápu, že v prvním while cyklu se jede až na konec souboru, v druhém pak na konec řádky - tím se dostanou řádky i sloupce z matice.. ale nechápu, proč se to cyklí.. (2. while se vypisuje do nekonečna)

Zde je celý kód:

#include <stdio.h>
#include <stdlib.h>

char c;
int pocetMnozin= 0;

int PocetMnozin(FILE * fr)
{ // kvuli poctu mnozin(radku) matice
	while((c = getc(fr)) != EOF)
	{
		if(c == '\n'){pocetMnozin++;}
	}
}


int main (void)
{
	FILE *fr;
	if((fr = fopen("mnoziny.txt","r")) == NULL)
	{    //test otevreni
		printf("Soubor se nepodarilo otevrit.\n");
		system("pause");
		return 1;
	}
	int i=0;
	PocetMnozin(fr);
	printf("pocet mnozin (radku) %d\n",pocetMnozin);

	int *velikostiMnozin;    //jednorozmerne pole
	velikostiMnozin= (int*) calloc( pocetMnozin , sizeof(int));
	printf("dadadad");

	rewind(fr);
	while((c = getc(fr)) != EOF) /* přečtení souboru */
	{
		printf("1. while\n");
		while((c =getc(fr)) != '\n')
		{
			printf("2. while\n");
			if(c == ' ' ) //mezer je vzdy o 1 min nez cisel , nekde pridat +1
			{ 
				velikostiMnozin[i]++;
			}
		}
		velikostiMnozin[i]++; // zde pridavam tu +1
		i++;
	}
	printf("faafaffa");

	int **mnozinyPole;  //matice pro mnoziny
	mnozinyPole = (int **)calloc( pocetMnozin , sizeof(int *)); //zde si alokuju kolik ma mit matice radku

	int j = 0;
	rewind(fr);

	for(i= 0; i< pocetMnozin ; i++)
	{
		mnozinyPole[i] = (int *)calloc( velikostiMnozin[i] , sizeof(int));  //tady alokuju sloupecky kazdeho radku
		for(j=0; j<velikostiMnozin[i]; j++)
		{
			fscanf(fr, "%d", &mnozinyPole[i][j]);   //tady matici plním
		}
	}


	printf("\n\n\n\n");
    
	for(i = 0; i < pocetMnozin ; i++)
	{     //vypis finalni matice
		for (j = 0; j < velikostiMnozin[i]; j++)
		printf("%i ", mnozinyPole[i][j]);
		printf("\n");
	}



	if (fclose(fr) == EOF)
	{ /* test zavření souboru*/
		printf("Soubor se neporadilo zavrit\n");
		return 1;
	}

	system("PAUSE");
	return 0;
}
Nahlásit jako SPAM
IP: 147.228.209.–
zlz
~ Anonymní uživatel
634 příspěvků
8. 1. 2013   #2
-
0
-
  1. getc vrací int. oříznutí na char by tady nemuselo vadit.
  2. znak načtený getc v prvním while se nezpracuje. to už by mohlo vadit.
  3. druhý while končí načtením '\n', který se z nějakého důvodu nenačte.

Takže nejdřív nepřeskakuj první znak. Ideálně tam ještě hoď int a nespoléhej se na přítomnost '\n'.

Nahlásit jako SPAM
IP: 78.156.159.–
8. 1. 2013   #3
-
0
-

Řádek v txt souboru často končí dvojicí znaků CR LF. Možná jsem zase něco přehlédl (poslední dobou se mi to stává často   ), ale asi jeho existenci neřešíš.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
cibule0
Návštěvník
8. 1. 2013   #4
-
0
-

#1 Sprinter
Možna to bude tím že u poslední řádek není odentrovaný, není znak -> '\n'

Nahlásit jako SPAM
IP: 85.70.207.–
Sprinter
~ Anonymní uživatel
102 příspěvků
8. 1. 2013   #5
-
0
-

#2 zlz
Bodům 1-3 rozumím, ale moc jsem nepobral tu poslední větu - jak nemám přeskakovat první znak? A že tam mám hodit int, tím je myšleno jako změnit char c na int c?

Nahlásit jako SPAM
IP: 147.228.209.–
Sprinter
~ Anonymní uživatel
102 příspěvků
8. 1. 2013   #6
-
0
-

#3 hlucheucho
No Windows by to tak mělo být - CRLF = "\n".. ale jak se zdá, tak to moc nefunguje.. Když dám kontrolní výpis znaků, tak se mi vše načte, ale pak už to jede s prázdnýma znakama do nekonečna...

Nahlásit jako SPAM
IP: 147.228.209.–
Sprinter
~ Anonymní uživatel
102 příspěvků
8. 1. 2013   #7
-
0
-

#4 cibule
no v tom while odentrování mám - pojede dokud nenarazí na konec řádky, nebo jak jste to myslel?

Nahlásit jako SPAM
IP: 147.228.209.–
8. 1. 2013   #8
-
0
-

#6 Sprinter
CR je '\r' (hodnota 0x0D) a LF je '\n' (hodnota 0x0A). Když si ten soubor zobrazíš hexadecimálně, uvidíš, co tam je na konci řádku a jak zde někdo napsal, jestli je LF na konci posledního řádku nebo jestli končí bez LF.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
vitamin
~ Anonymní uživatel
1092 příspěvků
8. 1. 2013   #9
-
0
-

Tusim ak otovris subor v binarnom rezime tak vo wine najdes tu dvojicu znakov CR LF ale v textovom rezime ti to prelozi na '\n'.

Nahlásit jako SPAM
IP: 195.28.77.–
8. 1. 2013   #10
-
0
-

 #5 Sprinter

while((c = getc(fr)) != EOF) // zde prectes prvni znak a dal s nim nic nedelas
	{
		printf("1. while\n");
		while((c =getc(fr)) != '\n')  //zde sice overis, ze je LF, ale neresis situaci, kdy posledni radek konci znakem EOF
		{
			printf("2. while\n");
			if(c == ' ' ) //mezer je vzdy o 1 min nez cisel , nekde pridat +1
			{ 
				velikostiMnozin[i]++;
			}
		}
		velikostiMnozin[i]++; // zde pridavam tu +1
		i++;
	}

hu

Nahlásit jako SPAM
IP: 195.178.67.–
Sprinter
~ Anonymní uživatel
102 příspěvků
8. 1. 2013   #11
-
0
-

Aha.. přidal jsem do toho posledního while podmínku

if (c == EOF){break;}

a už se to necyklí.. akorát to teda načte o jeden řádek míň.. ale na to snad už přijdu :-)

Nahlásit jako SPAM
IP: 147.228.209.–
8. 1. 2013   #12
-
0
-

#9 vitamin
máš pravdu, zkoušel jsem to.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
8. 1. 2013   #13
-
0
-

pokud dobře chápu, tak v každém řádku první znak pouze otestuješ jestli není EOF, ale pak už s ním dále nepracuješ (bylo zde již připomínkováno). To pak může vypadat jako že chybí 1 řádek.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
vitamin
~ Anonymní uživatel
1092 příspěvků
8. 1. 2013   #14
-
0
-

Preco vlastne pouyziva 2 cykly?

Nahlásit jako SPAM
IP: 195.28.77.–
8. 1. 2013   #15
-
0
-

s těmy cykly mne to napadlo taky:

while((c = getc(fr)) != EOF)
{
   if (c == '\n')
   {
      velikostiMnozin[i]++;   //pokud posledni radek nekonci LF, budou tyto hodnoty spatne
      i++
   }
   else
   {
      if(c == ' ' )
      {
         velikostiMnozin[i]++;
      }
   }
}

zkus tohle.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
8. 1. 2013   #16
-
0
-

   

int PocetMnozin(FILE * fr)
{ // kvuli poctu mnozin(radku) matice
	while((c = getc(fr)) != EOF)
	{
		if(c == '\n'){pocetMnozin++;}
	}
}

na to překladač nic nenapsal? Není tam návratová hodnota. Asi bych to dělal takto:

int PocetMnozin(FILE * fr)
{ // kvuli poctu mnozin(radku) matice
	pocMno = 0;   //lokalni promenna
	while((c = getc(fr)) != EOF)
	{
		if(c == '\n'){pocMno++;}
	}
   return pocMno;
}

má to ale stejnou slabinu: když nebude poslední řádek končit na LF, nedojde k jeho započtení

hu

Nahlásit jako SPAM
IP: 195.178.67.–
Sprinter
~ Anonymní uživatel
102 příspěvků
8. 1. 2013   #17
-
0
-

S tím jedním while cyklem máte pravdu, takhle to funguje taky a nemusím to komplikovaně projíždět dvakrát.. Každopádě ten chybějící řádek nebyl problém ve funkci main, ale v tý PocetMnozin - už tato funkce mi to vypíše chybně:

Přitom vstup je:

1 2 3 4
5 6 7 8
9 10 11 12

Protože podmínka u funkce PocetMnozin má být:

if(c == '\n'){pocetMnozin=pocetMnozin+2;}


Pak už to funguje jak má. Ale je pravda, že to zase může způsobit přičtení řádku navíc (nebo ne?)...

Jinak ano, překladači se ta funkce moc nelíbí.. návratovou hodnotu přidám

Nahlásit jako SPAM
IP: 147.228.209.–
Sprinter
~ Anonymní uživatel
102 příspěvků
8. 1. 2013   #18
-
0
-

Tak sem upravil kód tak, aby mi bral obecně znaky a ne jen čísla a pro vstup

M + ( ) d *
S 1 1 - - 2
A 5 3 5 - -
B 4 - - - 4

se mi vypsalo jen toto:

Špatně to detekuje i konce řádků a vypíše jich 6... nechápu (jen jsem změnil int na char)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char c;
int pocetMnozin= 0;

int PocetMnozin(FILE * fr)
{ 
	while((c = getc(fr)) != EOF)
	{
		if(c == '\n'){pocetMnozin=pocetMnozin+2;}
	}
	return pocetMnozin;
}


int main (void)
{
	FILE *fr;
	if((fr = fopen("mnoziny.txt","r")) == NULL)
	{    //test otevreni
		printf("Soubor se nepodarilo otevrit.\n");
		system("pause");
		return 1;
	}
	int i=0;
	PocetMnozin(fr);
	printf("pocet mnozin (radku) %d\n",pocetMnozin);

	int *velikostiMnozin;    //jednorozmerne pole
	velikostiMnozin= (int*) calloc( pocetMnozin , sizeof(int));
	
	rewind(fr);
	
	while((c = getc(fr)) != EOF)
	{
		if (c == '\n')
		{
			velikostiMnozin[i]++;
			i++;
		}
		else
		{
			if(c == ' ' )
			{
				velikostiMnozin[i]++;
			}
		}
	}
	
	char **mnozinyPole;  //matice pro mnoziny
	mnozinyPole = (char **)calloc( pocetMnozin , sizeof(int *)); //zde si alokuju kolik ma mit matice radku

	int j = 0;
	rewind(fr);

	for(i= 0; i< pocetMnozin ; i++)
	{
		mnozinyPole[i] = (char *)calloc( velikostiMnozin[i] , sizeof(int));  //tady alokuju sloupecky kazdeho radku
		for(j=0; j<velikostiMnozin[i]; j++)
		{
			fscanf(fr, "%c", &mnozinyPole[i][j]);   //tady matici plním
		}
	}


	printf("\n\n\n\n");
    
	for(i = 0; i < pocetMnozin ; i++)
	{     //vypis finalni matice
		for (j = 0; j < velikostiMnozin[i]; j++)
		printf("%c ", mnozinyPole[i][j]);
		printf("\n");
	}



	if (fclose(fr) == EOF)
	{ /* test zavření souboru*/
		printf("Soubor se neporadilo zavrit\n");
		return 1;
	}

	system("PAUSE");
	return 0;
}
Nahlásit jako SPAM
IP: 147.228.209.–
8. 1. 2013   #19
-
0
-

   

int PocetMnozin(FILE * fr)
{ // kvuli poctu mnozin(radku) matice
	int pocMno = 0;
	int priznak = 0;

	while((c = getc(fr)) != EOF)
	{
		if(c == '\n')
		{
			pocMno++;
			priznak = 0;
		}
		else priznak = 1;
	}
   return (pocMno + priznak);
}

asi takhle by započítal správně i v případě, že poslední řádek nekončí LF

hu

Nahlásit jako SPAM
IP: 195.178.67.–
8. 1. 2013   #20
-
0
-

to +2 nebyl dobrý nápad, každý řádek započítá 2x

hu

Nahlásit jako SPAM
IP: 195.178.67.–
Sprinter
~ Anonymní uživatel
102 příspěvků
8. 1. 2013   #21
-
0
-

Tak jsem použil Váš úsek kódu a přidal ten return.. Warning žádnej, ale asi to špatně detekuje konec řádky - jede to jen do třetího znaku a pak se to odentruje...

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char c;
int pocetMnozin= 0;

int PocetMnozin(FILE * fr)
{ 
	int priznak = 0;
	while((c = getc(fr)) != EOF)
	{
		if(c == '\n')
		{
			pocetMnozin++;
			priznak = 0;
		}
		else
		{
			priznak = 1;
		}
	}
	return (pocetMnozin + priznak);
}


int main (void)
{
	FILE *fr;
	if((fr = fopen("mnoziny.txt","r")) == NULL)
	{    //test otevreni
		printf("Soubor se nepodarilo otevrit.\n");
		system("pause");
		return 1;
	}
	int i=0;
	PocetMnozin(fr);
	printf("pocet mnozin (radku) %d\n",pocetMnozin);

	int *velikostiMnozin;    //jednorozmerne pole
	velikostiMnozin= (int*) calloc( pocetMnozin , sizeof(int));
	//printf("dadadad\n");

	rewind(fr);
	
	while((c = getc(fr)) != EOF)
	{
		if (c == '\n')
		{
			velikostiMnozin[i]++;
			i++;
		}
		else
		{
			if(c == ' ' )
			{
				velikostiMnozin[i]++;
			}
		}
	}
	
	char **mnozinyPole;  //matice pro mnoziny
	mnozinyPole = (char **)calloc( pocetMnozin , sizeof(int *)); //zde si alokuju kolik ma mit matice radku

	int j = 0;
	rewind(fr);

	for(i= 0; i< pocetMnozin ; i++)
	{
		mnozinyPole[i] = (char *)calloc( velikostiMnozin[i] , sizeof(int));  //tady alokuju sloupecky kazdeho radku
		for(j=0; j<velikostiMnozin[i]; j++)
		{
			fscanf(fr, "%c", &mnozinyPole[i][j]);   //tady matici plním
		}
	}


	printf("\n\n\n\n");
    
	for(i = 0; i < pocetMnozin ; i++)
	{     //vypis finalni matice
		for (j = 0; j < velikostiMnozin[i]; j++)
		printf("%c ", mnozinyPole[i][j]);
		printf("\n");
	}



	if (fclose(fr) == EOF)
	{ /* test zavření souboru*/
		printf("Soubor se neporadilo zavrit\n");
		return 1;
	}

	system("PAUSE");
	return 0;
}
Nahlásit jako SPAM
IP: 147.228.209.–
8. 1. 2013   #22
-
0
-

   

int _tmain(int argc, _TCHAR* argv[])
{
	int c, priznak, i, j;
	int radku = 0;
	int znaku = 0;
	int **pRadky;

	FILE *fr = fopen("test.txt", "r");   //zjednodusene, neresi neuspech otevreni souboru

	while((c = getc(fr)) != EOF)
	{   //projdu soubor, zaznamenam delku radku a pocet radku
		switch (c) {
		case '\n':	//<LF>
			radku++;
			priznak = 0;

		case ' ':	//mezera se ignoruje
			break;

		default:    //jiny znak
			if (radku == 0) znaku++;	//pocita delku jen prvniho radku
			priznak = 1;
			break;
		}
	}
	radku += priznak;
	rewind(fr);

	//alokace poli a naplneni poli
	pRadky = (int **) malloc(radku * sizeof(int*));
	for (i = 0; i < radku; i++) {
	   pRadky[i] = (int *) malloc(znaku*sizeof(int));
	   for (j = 0; j < znaku; j++) {
		  while ((c = getc(fr)) == ' ');
		  pRadky[i] [j] = c;
	   }
	}

	//zavrit soubor, vypis
	return 0;
}

hu

Nahlásit jako SPAM
IP: 195.178.67.–
Sprinter
~ Anonymní uživatel
102 příspěvků
8. 1. 2013   #23
-
0
-

#22 hlucheucho
Děkuji. Akorát jsem začátečník a asi jsem uplně nepochopil ten tápis funkce _tmain _TCHAR* to je nějaká struktura?

Nahlásit jako SPAM
IP: 147.228.209.–
Sprinter
~ Anonymní uživatel
102 příspěvků
8. 1. 2013   #24
-
0
-

Tak jsem kód rozjel, ale asi se tam někde ukládá navíc znak mezera.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main (void)
{
	int c, priznak, i, j;
	int radku = 0;
	int znaku = 0;
	int **pRadky;

	FILE *fr = fopen("mnoziny.txt", "r");   //zjednodusene, neresi neuspech otevreni souboru

	while((c = getc(fr)) != EOF)
	{   //projdu soubor, zaznamenam delku radku a pocet radku
		switch (c) {
		case '\n':	//<LF>
			radku++;
			priznak = 0;

		case ' ':	//mezera se ignoruje
			break;

		default:    //jiny znak
			if (radku == 0) znaku++;	//pocita delku jen prvniho radku
			priznak = 1;
			break;
		}
	}
	radku += priznak;
	rewind(fr);

	//alokace poli a naplneni poli
	pRadky = (int **) malloc(radku * sizeof(int*));
	for (i = 0; i < radku; i++) {
	   pRadky[i] = (int *) malloc(znaku*sizeof(int));
	   for (j = 0; j < znaku; j++) {
		  while ((c = getc(fr)) == ' ');
		  pRadky[i] [j] = c;
	   }
	}

	//zavrit soubor, vypis
	fclose(fr);
	
	int a;
	int b;
	printf("Matice:\n");
	for(a = 0; a < radku ; a++)
	{    
		for (b = 0; b < znaku; b++)
		{
			printf("%c\t", pRadky[a][b]);
		}
		//printf("\n");
	}
	
	return 0;
}
Nahlásit jako SPAM
IP: 147.228.209.–
8. 1. 2013   #25
-
0
-

To je šablona C++ Builderu pro konzolovou aplikaci.

Nezkoušel jsem alokaci polí a jejich plnění. Je dobré si to odkrokovat a prohlédnout si, co je v polích, pak jak se jejich obsah vypisuje

Edit1: do polí se načte i znak LF

hu

Nahlásit jako SPAM
IP: 188.95.60.–
8. 1. 2013   #26
-
0
-

   

	//alokace poli a naplneni poli
	pRadky = (int **) malloc(radku * sizeof(int*));
	for (i = 0; i < radku; i++) {
	   pRadky[i] = (int *) malloc(znaku*sizeof(int));
	   for (j = 0; j < znaku; j++) {
		  while ((c = getc(fr)) == ' ' || c == '\n');  //zde byla chyba, nacetl se LF z predchoziho radku
		  pRadky[i] [j] = c;
	   }
	}

	//zavrit soubor, vypis
	fclose(fr);

	printf("Matice:\n");
	for(i = 0; i < radku ; i++)
	{
		for (j = 0; j < (znaku-1); j++) {
		   printf("%c\t", (char)pRadky[i][j]);
		}
		printf("%c\n", (char)pRadky[i][znaku-1]);
	}

hu

Nahlásit jako SPAM
IP: 188.95.60.–
Sprinter
~ Anonymní uživatel
102 příspěvků
8. 1. 2013   #27
-
0
-

#26 hlucheucho
Funguje, děkuju

Nahlásit jako SPAM
IP: 147.228.209.–
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 4 hosté

Podobná vlákna

Podminka pri nacteni znaku — založil crash40

Matice z textového souboru ? — založil Robin93

Moderátoři diskuze

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý