Problem ze stabilnością programu obliczającego dane statystyczne z długości wyrazów z pliku txt.

0

Witam!
Mój problem polega na tym, że po uruchomieniu poniższego kodu z parametrem startowym raz na pare uruchomień zmienia się jakaś obliczona dana oraz wyskakuje komunikat, że program przestał działać. Prosił bym o zweryfikowanie kodu i podanie przyczyny. Mógłbym zostawić tak ten program, ale zależy mi na tym aby poprawnie nauczyć się programować i w przyszłości nie popełniać podobnych błędów. Ogólnie w programie chodzi o to aby obliczył średnią dł. wyrazów, wariacje itd. z długości wyrazów w 2 wariantach:
1- z wszystkich wyrazów,
2- powtarzający wyraz jest brany pod uwagę jednokrotnie.

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

int DlWyrazu = 0;
float srdl = 0;
float wariacja = 0;
float mediana = 0;

void analiza(char* wyraz)
{

	for (unsigned int i = 0; i < (unsigned int)strlen(wyraz);i++)
	{
		if (wyraz[i] == 'q' || wyraz[i] == 'w' || wyraz[i] == 'e' || wyraz[i] == 'r' || wyraz[i] == 't' || wyraz[i] == 'y' || wyraz[i] == 'u' || wyraz[i] == 'i' || wyraz[i] == 'o' || wyraz[i] == 'p' || wyraz[i] == 'a' || wyraz[i] == 's' || wyraz[i] == 'd' || wyraz[i] == 'f' || wyraz[i] == 'g' || wyraz[i] == 'h' || wyraz[i] == 'j' || wyraz[i] == 'k' || wyraz[i] == 'l' || wyraz[i] == 'z' || wyraz[i] == 'x' || wyraz[i] == 'c' || wyraz[i] == 'v' || wyraz[i] == 'b' || wyraz[i] == 'n' || wyraz[i] == 'm' ||
			wyraz[i] == 'Q' || wyraz[i] == 'W' || wyraz[i] == 'E' || wyraz[i] == 'R' || wyraz[i] == 'T' || wyraz[i] == 'Y' || wyraz[i] == 'U' || wyraz[i] == 'I' || wyraz[i] == 'O' || wyraz[i] == 'P' || wyraz[i] == 'A' || wyraz[i] == 'S' || wyraz[i] == 'D' || wyraz[i] == 'F' || wyraz[i] == 'G' || wyraz[i] == 'H' || wyraz[i] == 'J' || wyraz[i] == 'K' || wyraz[i] == 'L' || wyraz[i] == 'Z' || wyraz[i] == 'X' || wyraz[i] == 'C' || wyraz[i] == 'V' || wyraz[i] == 'B' || wyraz[i] == 'N' || wyraz[i] == 'M')
		{
			DlWyrazu++;
		}
		else { wyraz[i] = '\0'; }
	}
}

void obliczanieParam(int* string,int wyr) {

	int wy = wyr;
	// srednia wyrazow
	int dl = 0;
	for (int i = 0;i < wy;i++) {
		dl = dl + string[i];
	}
	srdl =(float) dl / wy;

	// wariacja
	float mian = 0;
	for (int i = 0; i < wy ;i++) {
		mian = mian + (((float)string[i] - srdl)*((float)string[i] - srdl));
	}
	wariacja = mian / wy;

	// uporzadkowanie
	int t = 0;
	for (int j = 0; j < wy; j++) {
		for (int i = 0; i < wy; i++) {
			if (string[i] > string[i + 1]) {
				t = string[i];
				string[i] = string[i + 1];
				string[i + 1] = t;
			}
		}
	}

	int aa = (wy / 2) - 1;
	int bb = (wy / 2);
	if (wy % 2 == 0) {
		mediana = ((float)string[aa] + (float)string[bb]) / 2;
	}
	else mediana = string[bb];
}

int main(int argc, char *argv[])
{
	// zmienne:
	FILE * plik;
	FILE * plik1;
	char nazwa[15];
	char bufor[80];
	char bufor2[80];
	char bufor3[80];
	int licz = 0;
	int cmp = 0;

	int rozmiar1 = 0;
	int * StringWyr1 = malloc(rozmiar1 * sizeof(int));

	int rozmiar2 = 0;
	int * StringWyr2 = malloc(rozmiar2 * sizeof(int));

	// otwieranie pliku:
	if ((plik = fopen(*++argv, "r+")) == NULL)
	{
		printf("\n\t Nie ma takiego pliku!\n");
		printf("\n\t Podaj nazwe pliku:\t");
		scanf("%s", &nazwa);
		if ((plik = fopen(nazwa, "r+")) == NULL)
		{
			printf("\n\t Nie ma takiego pliku!\n");
			return(1);
		}
	}

	//stworzenie pliku pomocniczego:
	plik1 = fopen("pomoc.txt", "w+");
	fclose(plik1);
	
	//czesc glowna programu:
	while (fscanf(plik, "%s", bufor) != EOF)
	{
		analiza(bufor);
		StringWyr1[rozmiar1] = DlWyrazu;
		DlWyrazu = 0;
		rozmiar1++;

		//tworzenie pliku z wyrazami bez powtorzen
		plik1 = fopen("pomoc.txt", "r+");
		while (fscanf(plik1, "%s", bufor2) != EOF)
		{
			cmp = stricmp(bufor, bufor2);
			if (cmp == 0) { licz++; }
		}
		if (licz == 0) { fprintf(plik1, "%s ", bufor); }

		fclose(plik1);
		licz = 0;
	}

	DlWyrazu = 0;

	plik1 = fopen("pomoc.txt", "r+");
	while (fscanf(plik1, "%s", bufor3) != EOF)
	{
		analiza(bufor3);
		StringWyr2[rozmiar2] = DlWyrazu;
		DlWyrazu = 0;
		rozmiar2++;
	}
	
	printf("\n\t ---------- Z powt ------------");
	obliczanieParam(StringWyr1,rozmiar1);
	printf("\n\t ilosc wyrazow = %d", rozmiar1);
	printf("\n\t srednia dlugosc = %f", srdl);
	printf("\n\t wariacja = %f", wariacja);
	printf("\n\t mediana = %f", mediana);

	printf("\n\t --------- BEZ powt ----------");
	obliczanieParam(StringWyr2, rozmiar2);
	printf("\n\t ilosc wyrazow = %d", rozmiar2);
	printf("\n\t srednia dlugosc = %f", srdl);
	printf("\n\t wariacja = %f", wariacja);
	printf("\n\t mediana = %f", mediana);

	fclose(plik1);
	fclose(plik);
	remove("pomoc.txt");
	return 0;
}
1

Najlepiej jakbyś podał przykładowy plik, w którym Ci się to sypie.

  • Nie korzystasz z conio.h
  • Po to ktoś wymyślił pętle i tablice, aby nie trzeba było pisać takich długich, nieczytelnych i trudnych w poprawie ifów. Może że chodzi o wydajność, ale nie wiadomo jak to kompilator sobie tam zrobi.
  • Dla przykładowych danych wprowadzonych przez mojego kota z klawiatury, program wysypał się na linijkach :
 mediana = ((float)string[aa] + (float)string[bb]) / 2;

Ogólnie cała funkcja jest dziwna i możliwe, że mało bezpieczna.

  • Powinieneś zrobić rzutowanie z malloca do typu lvalua:
int * StringWyr1 = (int *)malloc(rozmiar1 * sizeof(int));
  • Wczytywanie do nazwa[15], scanfem to proszenie się o kłopoty. Należy to jakoś mądrze przemyśleć, lub użyć bezpiecznych funkcji wczytujących.
  • Argumentem scanfa jest adres. Tutaj podałeś adres [nazwy tablicy(adres)]. Czyli adres adresu. Zwyczajnie wpisz bez tego znaczka &.
scanf("%s", &nazwa);
  • Nie masz tutaj sprawdzania czy parametr istnieje
if ((plik = fopen(*++argv, "r+")) == NULL)
0

Problem leży w dynamicznych tablicach, ponieważ jeśli stworzę zwykłą tablicę program się nie wysypuje. Mógłby ktoś mi pomóc, wysłać link do jakiejś strony gdzie mógłbym się dowiedzieć jak stworzyć tablicę, której rozmiar będzie się zwiększał w trakcie działania programu ?

0

Problem rozwiązany przy pomocy funkcji realloc()

0
  1. isalpha
  2. Funkcje są za długie
  3. Przekazywanie wyników funkcji przez zmienne globalne
  4. Do wersji drugiej musisz napisać kontener typu set (zbiór) na napisy
  5. Nazwy funkcji nic nie mówią o funkcjonalności. Przykładowo analiza powinna się nazywać np znajdzNastepnyWyraz
  6. Do statystyk podszedł bym tak, w ten sposób będziesz miał jedną funkcję dla wersji 1 i 2.
/**
 * @param srednia         miejsce zapisu sredniej
 * @param wariacja        miejsce zapisu wariacji
 * @param mediana         miejsce zapisu mediany
 * @param generujNastepna adres funkcji dostarczajacej dane, zwraca 1 jesli dana 
 *                        zostala zwrocona przez parametr nowaDana, zwraca
 *                        0 jesli brak dalszych danych
 */
void statystykiDlaDanychGenerowanych(double *srednia, double *wariacja, double *mediana,
                                         int(*generujNastepna)(int *nowaDana));
  1. malloc o rozmiarze 0 jest bezsensu
1

int rozmiar1 = 0;
int * StringWyr1 = malloc(rozmiar1 * sizeof(int));

czyli alokujesz 0 bajtów
2)
```c
StringWyr1[rozmiar1] = DlWyrazu;

odwolujesz sie poza tablice
3) obawiam się, że nie rozumiesz tablic dynamicznych

0

Tak z ciekawości jak duże masz te pliki testowe? Czy używają znaków z poza zakresu ASCII (np polskie znaki)?

2

Mam dobry humor , więc daję prawie gotowca. BinaryTreeStringIntAddValue jest ciut za długa, ale w granicach rozsądku.

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

typedef struct BinaryTreeStringInt
{
    struct BinaryTreeStringInt *left;
    struct BinaryTreeStringInt *rigth;
    char *value;
    int count;
} BinaryTreeStringInt;

BinaryTreeStringInt *BinaryTreeStringIntCreateItem(const char *value)
{
    BinaryTreeStringInt *result = (BinaryTreeStringInt *)malloc(sizeof(BinaryTreeStringInt));

    result->value = strdup(value);
    result->left = NULL;
    result->rigth = NULL;
    result->count = 1;
    return result;
}

void BinaryTreeStringIntAddValue(BinaryTreeStringInt **root, const char *value)
{
    BinaryTreeStringInt *item = *root;
    if (!item)
    {
        *root = BinaryTreeStringIntCreateItem(value);
    }
    else
    {
        int cmp = strcmp(value, item->value);
        if (cmp == 0)
        {
            item->count++;
        }
        else if (cmp < 0)
        {
            BinaryTreeStringIntAddValue(&item->left, value);
        }
        else
        {
            BinaryTreeStringIntAddValue(&item->rigth, value);
        }
    }
}

void BinaryTreeStringIntDestroy(BinaryTreeStringInt **root)
{
    BinaryTreeStringInt *item = *root;
    if (item)
    {
        BinaryTreeStringIntDestroy(&item->left);
        BinaryTreeStringIntDestroy(&item->rigth);
        free(item->value);
        free(item);
        *root = NULL;
    }
}

void BinaryTreeStringIntLoadFrom(BinaryTreeStringInt **root, FILE *f)
{
    char s[256];
    while (fscanf(f, "%*[^a-zA-Z]%255[a-zA-Z]", s) == 1)
    {
        BinaryTreeStringIntAddValue(root, s);
    }
}

typedef void (*IterateFunction)(BinaryTreeStringInt *, void *);
void BinaryTreeStringIntIterate(BinaryTreeStringInt *tree, void *context, IterateFunction f)
{
    if (tree->left)
    {
        BinaryTreeStringIntIterate(tree->left, context, f);
    }
    f(tree, context);
    if (tree->rigth)
    {
        BinaryTreeStringIntIterate(tree->rigth, context, f);
    }
}

void BinaryTreeStringIntPrint(BinaryTreeStringInt *item, FILE *out)
{
    fprintf(out, "W: %s c:%d\n", item->value, item->count);
}

struct Statistics
{
    int count;
    double sum;
    double sumOfSquers;
};

void StatisticsUpdateWithItem(BinaryTreeStringInt *item, struct Statistics *stat)
{
    int len = strlen(item->value);
    stat->count++;
    stat->sum += len;
    stat->sumOfSquers += len * len;
}

int main(void)
{
    BinaryTreeStringInt *tree = NULL;

    struct Statistics stats = {};

    BinaryTreeStringIntLoadFrom(&tree, stdin);
    BinaryTreeStringIntIterate(tree, stdout, (IterateFunction)BinaryTreeStringIntPrint);
    BinaryTreeStringIntIterate(tree, &stats, (IterateFunction)StatisticsUpdateWithItem);

    printf("%d %lf\n", stats.count, stats.sum/stats.count);

    BinaryTreeStringIntDestroy(&tree);

    return 0;
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1