Odstranění části char... – C / C++ – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Odstranění části char... – C / C++ – Fórum – Programujte.comOdstranění části char... – C / C++ – Fórum – Programujte.com

 

Toto vlákno bylo označeno za vyřešené — příspěvek s řešením.
CZIvo0
Newbie
6. 7. 2017   #1
-
0
-

poradí někdo? už se s tím zlobím celé odpoledne..

Mám char mojepole[512];

v každém kole se do toho charu pomocí strcat přidá obsah na novém řádku (\nblablabla...) - takže výsledný char je

bla bla\nblablabla\nblablabla\nblablabla

může mi někdo poradit jak můžu v tom arrayi najít PRVNÍ místo z LEVA kde je '\n' a SMAZAT všechno VLEVO od něj, včetně jeho?

tzn. aby mi z "bla bla\nblablabla\nblablabla\nblablabla" zbylo jen "blablabla\nblablabla\nblablabla"..

potřebuju aby ten char prostě níkdy neměl víc jak 7 řádků.. a aby s každým přidaným řádkem který by ho dělal delší umazal jeden řádek ze začátku..

Děkuji..

Nahlásit jako SPAM
IP: 77.48.132.–
7. 7. 2017   #2
-
0
-

Najdeš první výskyt znaku /n např pomocí funkce strchr a zkopíruješ to, co je za ním až po konec řetězce. Při kopírování je potřeba buď alokovat jinou paměť a nebo kopírovat s definovaným pořadím. To by mohla umět memmove.  V C++ by bylo lepší použít std::string a jeho metody.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
7. 7. 2017   #3
-
0
-

Možná bude šikovnější strcat namísto strchr.... 

hu

Nahlásit jako SPAM
IP: 195.178.67.–
CZIvo0
Newbie
7. 7. 2017   #4
-
0
-

No, já zkoušel

char *szSg=mojepole;
while(*szSg=='\n')
szSg++;

a posléze

memset(mojepole,'\0',512);
sprintf(mojepole, "%s", szSg);
 

ale nějak mě to neposlouchalo.. zkusím mrknout na ten strchr/strcat

Nahlásit jako SPAM
IP: 77.48.132.–
7. 7. 2017   #5
-
0
-

#4 CZIvo
V prvé řadě, cyklus while běží, dokud podmínka vrací true. Takže pokud první znak není \n, tak cyklus neproběhne ani jednou. char *szSg=mojepole; kopíruje jen ukazatel. Kromě toho memset(mojepole,'\0',512); to pole pak celé vynuluje. sprintf už pak nemá co přidávat.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
CZIvo0
Newbie
7. 7. 2017   #6
-
0
-

tu chybu v tom for si uz uvedomuju, ale v memsetu se pletes.. ja vynuloval "mojepole" a pak do toho vynulovaneho "mojepole" chtel nakopirovat obsah oriznutyho "szSg" :D takova byla teorie :D

Dela mi v tom dost bordel to pretypovani, no :D nakonec to dopadne tak ze to pretypuju na string a budu delat s nim.. chci se mu vyhnout abych tam zbytecne nemusel co 10 sekund ten char pretypovavat na string a zpet.. ale co mi asi jinyho zbude :D

ted se pokousim o to strchr :)

(omluv ze tu neni diakritika, pisu z telefonu)

Nahlásit jako SPAM
IP: 77.48.132.–
7. 7. 2017   #7
-
0
-

   

int delka;
char *zacatek;

zacatek = strtok(mojepole, "'\n'");
delka = strlen(zacatek);
memove(mojepole, zacatek, delka);

něco takového.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
7. 7. 2017   #8
-
0
-

#6 CZIvo
Znovu: char *szSg=mojepole; kopíruje jen ukazatel. Takže ten szSg ukazuje na mojepole.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
7. 7. 2017   #9
-
0
-

#7 hlucheucho
strtok moc vhodný není, přecejen strchr: 

int delka;
char *zacatek;

zacatek = strchr(mojepole, "'\n'");
zacatek++; //posune ukazatel za \n
delka = strlen(zacatek);
memove(mojepole, zacatek, delka);

Kopírování zbytku řetězce není moc efektivní. Jiný postup by byl pomocí dvou ukazatelů udržovat přehled, kde je první a poslední platný znak v kusu paměti a vytvořit tak FIFO.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
CZIvo0
Newbie
7. 7. 2017   #10
-
0
-

aha..

Tvé řešení se strchr se dá funkční, ALE..

tvůj kód se zzavolá, pokud je v tom charu 8 a víc \n, to funguje ok, vidíš že to ty první odmazalo, to je správně, ALE s každou tou úpravou to zkopíruje tu část.. vidíš, že 5,6,7,8 je OK, neopakuje se.. ale 9,10,11,12 se tam vždycky vecpou 2x

Připojen obrázek.

Připojen obrázek.

ten celej kód vypadá nějak takhle, nevíš kde mám chybku?


void MultiplayerMgr::kms(char szKiller[32], char szVictim[32], int Type)
{
	test++;

	int kmscnt = 0;
	for(int aa=0;aa<strlen(mojepole);aa++)
	{
		if(mojepole[aa] == '\n')
			kmscnt++;
	}

	if(kmscnt>=8)
	{
		//memset(mojepole,'�',512);
		int delka;
		char *zacatek;

		zacatek = strchr(mojepole, '\n');
		zacatek++; //posune ukazatel za \n
		delka = strlen(zacatek);
		memmove(mojepole, zacatek, delka);
	}

	char Addme[96];

	if(Type==0)
		sprintf(Addme, "%s killed by %s!\n", szVictim, szKiller);
	else if(Type==1)
		sprintf(Addme, "%s terminate himself!%d\n", szKiller, test);
	else if(Type==2)
		sprintf(Addme, "%s teamkilled by %s!\n", szVictim, szKiller);

	strcat(mojepole,Addme);

	PositionMessage(280,-45,SDD_FONT_SMALL,0.0f,997,SDD_JUSTIFY_RIGHT,SETRGB(148,148,148),0,mojepole,NULL);
}
Nahlásit jako SPAM
IP: 77.48.132.–
CZIvo0
Newbie
7. 7. 2017   #11
-
0
-

zakomentoval jsem řádek

zacatek++; //posune ukazatel za \n

a opakování přestalo, JENOM se to zopakuje při tom úplně prvním zavoláním..

viz

EDIT: aha, až teď z toho obrázku jsem si všiml že je tam víc než 8 řádků, tak já už nevím...Připojen obrázek.

Nahlásit jako SPAM
IP: 77.48.132.–
7. 7. 2017   #12
-
0
-

Ono se to nenakopíruje 2x. memmove nezkopíruje znak '\0'. Stačí udělat memove(mojepole, zacatek, delka+1); a pak kopíruje i bílý znak na konci řetězce.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
Radek Chalupa
~ Redaktor
+1
Super člen
7. 7. 2017   #13
-
0
-

Můžeš začít o konce řetězce počítat výskyty \n a pokud najdeš 7, udělat memmove, nějak takhle:

char pole[512];

void uprav()
{
	char* pom = pole + strlen(pole);
	int pocrad = 0;
	while (pom > pole)
	{
		if (*pom == '\n')
		{
			pocrad++;
			if (pocrad == 7)
			{
				break;
			}
		}
		pom--;
	}
	if (pocrad < 7)
		return;
	memmove(pole, pom, strlen(pom) + 1);
}

Radek Chalupa
- individuální konzultace, školení programování, (C/C++, C#, WinAPI, .NET, COM, ATL, MFC...)
- vývoj software na zakázku
http://www.radekchalupa.cz

Nahlásit jako SPAM
IP: 89.177.51.–
7. 7. 2017   #14
-
0
-

Úvaha: strlen dělá interně cyklus. memmove dělá interně cyklus. Obě funkce procházejí stejnou část pole. Pokud to nezoptimalizuje překladač (myslím, že nezoptimalizuje), pak si můžeš kopírování napsat sám: 

char *to_copy, dest;

to_copy = strchr(mojepole, "'\n'");
dest = mojepole;
while(++to_copy != '\0')
{
  dest++ = to_copy;
}
dest = '\0';

nezkoušel jsem to, ale podstata je začni kopírovat za prvním \n a kopíruj dokud nenarazíš na \0. 

hu

Nahlásit jako SPAM
IP: 195.178.67.–
CZIvo0
Newbie
7. 7. 2017   #15
-
0
-

EDIT: zkouším řešení pana Chalupy, uvidíme (vyzkoušeno, zdá se, že to nedělá vůbec nic :D) KONEC EDITU:

Po úpravě na

memove(mojepole, zacatek, delka+1); 

už to funguje jak má, ale z nějakýho důvodu mi to přestalo počítat ty řádky a místo 8 jich tam mám třeba 20 xD xD

Připojen obrázek.

Nahlásit jako SPAM
IP: 77.48.132.–
CZIvo0
Newbie
7. 7. 2017   #16
-
0
-

Takže děkuji oboum, nakonec jsem malou úpravou dosáhl toho co potřebuji kódem pana Chalupy.

finální kód:

void MultiplayerMgr::KillMessage(char szKiller[32], char szVictim[32], int Type)
{
	test++;

	char* pom = KillMessages + strlen(KillMessages);
	int pocrad = 0;
	while (pom > KillMessages)
	{
		if (*pom == '\n')
		{
			pocrad++;
			if (pocrad == 8)
			{
				break;
			}
		}
		pom--;
	}
	if (pocrad == 8)
		memmove(KillMessages, pom, strlen(pom) + 1);

	char Addme[96];

	if(Type==0)
		sprintf(Addme, "%s killed by %s!\n", szVictim, szKiller);
	else if(Type==1)
		sprintf(Addme, "%s terminate himself! %d\n", szKiller, test);
	else if(Type==2)
		sprintf(Addme, "%s teamkilled by %s!\n", szVictim, szKiller);

	strcat(KillMessages,Addme);

	memset(Addme,'\0',96);

	PositionMessage(280,-45,SDD_FONT_SMALL,0.0f,997,SDD_JUSTIFY_RIGHT,SETRGB(148,148,148),0,KillMessages,NULL);
}
Nahlásit jako SPAM
IP: 77.48.132.–
7. 7. 2017   #17
-
0
-

#15 CZIvo
Protože můj algoritmus umí odstranit jen jeden řádek. Doslova odstranit vše před prvním \n jak jsi chtěl. Asi potřebuješ aby bylo zachováno posledních 8 řádků, tedy odzadu najít 9 výskyt \n a odstranit vše předním včetně toho \n pro úplné řádky (tedy zakončené \n) a pro poslední řádek neúplný (bez \n) by to byl 8 výskyt \n odzadu. V podstatě lze přeskočit poslední znak a od předposledního počínaje najít 8 výskytů \n. A pak zkopírovat vše, co je za takto nalezeným \n.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
CZIvo0
Newbie
7. 7. 2017   #18
-
0
-

Aha HU, v tom případě se omlouvám, asi jsem to špatně vysvětlil..

ano, šlo mi o to aby to odstranilo první řádek a zbytek tam samozřejmě zanechalo :)

Nahlásit jako SPAM
IP: 77.48.132.–
Radek Chalupa
~ Redaktor
+1
Super člen
7. 7. 2017   #19
-
0
-

#15 CZIvo
No nevím tohle je kompletní kód i s testem a mě funguje, vypíše posledních 7 řádků, akorát záleží zda na konci text je \n a pak je těch řádku ve výpisu jen 6

char pole[512];

void uprav()
{
	char* pom = pole + strlen(pole);
	int pocrad = 0;
	while (pom > pole)
	{
		if (*pom == '\n')
		{
			pocrad++;
			if (pocrad == 7)
				break;
		}
		pom--;
	}
	if (pocrad < 7)
		return;
	memmove(pole, pom, strlen(pom) + 1);
}

int main()
{
	strcpy(pole, "abc\n12345\nxy\n987\nwww\nrty\n897999\nuyyyy\nrrrrr\nfuuu\n");
	printf(pole);
	printf("\n");
	uprav();
	printf(pole);
	getchar();
	return 0;
}

Radek Chalupa
- individuální konzultace, školení programování, (C/C++, C#, WinAPI, .NET, COM, ATL, MFC...)
- vývoj software na zakázku
http://www.radekchalupa.cz

Nahlásit jako SPAM
IP: 89.177.51.–
CZIvo0
Newbie
7. 7. 2017   #20
-
0
-

#19 Radek Chalupa
http://programujte.com/forum/vlakno/32306-odstraneni-casti-char/#p216965

Děkuji :)

Nahlásit jako SPAM
IP: 77.48.132.–
Radek Chalupa
~ Redaktor
+1
Super člen
7. 7. 2017   #21
-
0
-

#18 CZIvo
v původní dotazu jsi psal, že " aby ten char prostě níkdy neměl víc jak 7 řádků..",takže dokud jich není 7, není třeba dělat nic.

Nahlásit jako SPAM
IP: 89.177.51.–
7. 7. 2017   #22
-
0
-

#19 Radek Chalupa
Ono to vypadá, že jich chce 8. Pokud by se z prohledávání odzadu vypustil poslední znak a prohledávalo se až od předposledního, tak to vrátí stejný počet řádků bez ohledu na to, zda jsou kompletní.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
CZIvo0
Newbie
7. 7. 2017   #23
-
0
-

Já jsem těch "7 řádků" použil jen obrazně, myslel jsem tim jakože "až to dosáhne určitého počtu řádků, tak je začít odpředu odmazávat" :) o tom čísle není rozhodnuto, to se uvidí až jak se to bude chovat na test serveru a v různých rozlišeních klientů :)

Ale děkuju, oba jste mi moc pomohli.

Nahlásit jako SPAM
IP: 77.48.132.–
7. 7. 2017   #24
-
0
-

#23 CZIvo
V tom případě si dej počet řádků jako makro pokud bude znám v době překladu nebo jako proměnnou pokud bude znám až za běhu programu.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
CZIvo0
Newbie
7. 7. 2017   #25
-
0
-

zatím to tam nechám natvrdo, na test server, a až uvidím jak se to bude chovat, tak to pak nadefinuju jako makro.

Nahlásit jako SPAM
IP: 77.48.132.–
7. 7. 2017   #26
-
0
-

Ještě se vrátím k postupu bez kopírování. Na jednočipu jsem musel hospodařit se strojovým časem a tak každé kopírování jsem musel pečlivě zvážit. Dá se postupovat tak, že mám buffer dejme tomu 512 byte. K němu mám dva ukazatele. Jeden ukazuje "dno" (= první znak ke čtení) a druhý "vrchol" (= poslední zapsaný znak) takto vytvořené FIFO. Do bufferu se zapisuje byte po byte v kruhu, tzn. že po zapsání 512 byte se začne zapisovat od začátku. Stejným způsobem se i čte. Pak by stačilo od ukazatele vrcholu směrem ke "dnu" odpočítat požadovaný počet zpráv a posunout ukazatel dna na první platnou zprávu.

Pro zpracování zpráv s RS 485 na 8051 jsem to dělal ještě v Assembleru, ušetřil jsem hromadu kopírování a tím i strojového času. Asi si všechny funkce budeš muset naprogramovat sám, to je nevýhoda tohoto přístupu. Důležité je si umět představit lineární kus paměti jako "kroužek".

hu

Nahlásit jako SPAM
IP: 195.178.67.–
CZIvo0
Newbie
7. 7. 2017   #27
-
0
-

Já to potom zkusím.. aktuálně mě strojový čas netrápí, ten server běží na strojích typu 8-procesorový server s 4 jádrovými xeony, 32GB ram, Windows Server 2012 r2 x64.. takže... :)

Nahlásit jako SPAM
IP: 77.48.132.–
MilanL+1
Grafoman
8. 7. 2017   #28
-
0
-

#27 CZIvo
verze FIFO (kruhový zásobník zpráv)

int maxRadek;
dword RadkyCount;

char Radky[maxRadek][32];   //délka 1. řádky odhadem (pozor na rezervu pro ukončovací znak z fce sprintf)

//vstup radky
sprintf(Radky[RadkyCount%maxRadek],"%s",Vstup);
RadkyCount++;

//výstup
for i=RadkyCount-maxRadek;i<RadkyCount;i++
 printf("%s",Radky[i%maxRadek]);
Nahlásit jako SPAM
IP: 193.165.115.–
MilanL+1
Grafoman
8. 7. 2017   #29
-
0
-

#28 MilanL
druhá možnpst co mě napadla, uchovávat si v poli délky jednotlivých řádek a pak místo hledání konce první řádky dělat rovnou posun o délku té první řákdy, po provedení délky bud posunout a na konec vložit novou, nebo k nim přistupovat opět přes modulo index.

Nahlásit jako SPAM
IP: 193.165.115.–
Řešení
MilanL+1
Grafoman
10. 7. 2017   #30
-
0
-
Vyřešeno Nejlepší odpověď

#29 MilanL
.. zatím testováno nové řešení - #29


#define KMRow = 8;
int KillMessagesLen[KMRow];DWORD KillMessagesCount;

void MultiplayerMgr::KillMessage(char szKiller[32], char szVictim[32], int Type)
{
	int nRandom = rand() % 4;

	if ((KillMessagesCount / KMRow) > 0)
	{
		char* pom = KillMessages + KillMessagesLen[KillMessagesCount % KMRow];
		memmove(KillMessages, pom, strlen(pom) + 1);
	}

	char Addme[96];
	memset(Addme, '/0', 96);

	if(Type==0)
	{
		if(nRandom==0)
			sprintf(Addme, "%s killed %s\n", szKiller, szVictim);
		if(nRandom==1)
			sprintf(Addme, "%s finished %s\n", szKiller, szVictim);
		if(nRandom==2)
			sprintf(Addme, "%s silenced %s\n", szKiller, szVictim);
		if(nRandom==3)
			sprintf(Addme, "%s terminated %s\n", szKiller, szVictim);
	}
	else if(Type==1){    .....    }
	else if(Type==2){    .....    }

	KillMessagesLen[KillMessagesCount % KMRow] = strlen(Addme);
	KillMessagesĆount++;

	strcat(KillMessages, Addme);

	PositionMessage(230,-50,SDD_FONT_SMALL,0.0f,997,SDD_JUSTIFY_RIGHT,SETRGB(148,148,148),0,KillMessages,NULL);
Nahlásit jako SPAM
IP: 185.112.167.–
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, 93 hostů

Podobná vlákna

Vypsání části char* — založil trackmaniak

Odstranění diakritiky — založil gengar

Odstranění obrázku — založil Noneus

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ý