Tablica dynamiczna w liście

0

Cześć. Mam problem w swoim mini programie związany z przekazywaniem tablicy dynamicznej do kolejnych funkcji.
Zaczynając od początku, chodzi o to, że do listy dodaje sobie jakiś element, a jego wartość x inicjalizuje wartością ściśle określoną (przechowywaną w tablicy wskaźników). Co więcej, mogę dodać swoją wartość, która powinna zostać zapisana w ww. tablicy wskaźników do momentu zamknięcia programu.
Problem dotyczy tablicy wskaźników t. Za drugim wywołaniem opcji Dodaj element kompilator sugeruje, że nie dostał tablicy wskaźników z poprzednimi wartościami (tak mi się wydaje). Nie mam pojęcia, jak obejść ten problem. Wydaje mi się, że jeśli zadeklaruje tablicę w main to mogę ją w następnych funkcjach zmieniać. Proszę o pomoc, na dole umieszczam kod programu:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 64
//-------------------------------------------------------------------------------------------------------------------------------------------------//
typedef struct elem
{
	char * x;
}elem;

typedef struct node
{
	struct node *next, *prev;
	elem data;
}node;

typedef struct list
{
	node *head, *tail;
}list;

void push_back(list *L, char ** t);
char* add_x(char **t, int r);
elem make_x(char **t, elem a, int r);
elem new_x(char** t);

int n = 3;
//-------------------------------------------------------------------------------------------------------------------------------------------------//
int main()
{
	char tab[MAX];
	char **t = (char**)malloc(sizeof(char*)* 3);
	int i = 0, x = 0;
	char pos = '\0';
	node *ptr = NULL;
	list L;
	L.head = NULL, L.tail = NULL;
	
	t[0] = (char*)malloc(sizeof(char)*strlen("aaa")); strcpy(t[0], "aaa");
	t[1] = (char*)malloc(sizeof(char)*strlen("bbb")); strcpy(t[1], "bbb");
	t[2] = (char*)malloc(sizeof(char)*strlen("ccc")); strcpy(t[2], "ccc");
	do
	{
		printf("1. Dodaj element\n");
		printf("2. Wyjscie z programu\n");
		printf(" \nWybierz opcje:\n");

		while (1)
		{
			scanf("%s", tab);
			if (tab[0] == '1' && strlen(tab) == 1)
			{
				system("cls");
				push_back(&L, t);
				break;
			}
			else if (tab[0] == '2' && strlen(tab) == 1)
			{
				system("cls");
				break;
			}
			else  printf("Taka opcja nie istnieje\n");
		}
	} while (tab[0] != '2');
	system("pause");
	return 0;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------//
void push_back(list *L, char ** t) // dodaje element na koniec listy
{
	if (L->tail == NULL)
	{
		L->tail = (node*)malloc(sizeof(node));
		L->head = L->tail;
		L->tail->prev = NULL;
	}
	else
	{
		L->tail->next = (node*)malloc(sizeof(node));
		L->tail->next->prev = L->tail;
		L->tail = L->tail->next;
	}
	L->tail->data = new_x(t);
	L->tail->next = NULL;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------//
char* add_x(char **t, int r) // dodaje nowe pole do tablicy t
{
	char p[MAX];
	int i;
	printf("Wpisz pole, ktore nalezy dodac\n");
	while (fgets(p, sizeof p, stdin))
	{
		if (strlen(p) > 1 && ((p[0] >= 'a' && p[0] <= 'z') || (p[0] >= 'A' && p[0] <= 'Z')))
		{
			p[strlen(p) - 1] = '\0';
			break;
		}
		else printf("Wprowadz prawidlowe dane!\n");
	}

	t = (char**)realloc(t, r*sizeof(char*)); // powiekszanie tablicy o 1
	t[r - 1] = malloc(strlen(p) + 1);
	strcpy(t[r - 1], p);
	for (i = 0; i < (r); i++)
	{
		printf("%s\n", t[i]);
	}
	return t;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------//
elem make_x(char **t, int r) // inicjalizuje wartoscia pole x w liscie
{
	int i = 0, m = 0;
	elem pom;
	char p[MAX];
	printf("Wpisz wartosc x sposrod wyswietlonych ponizej:\n");
	for (i = 0; i < (r); i++)
	{
		printf("%s\n", t[i]);
	}
	while (fgets(p, MAX, stdin))
	{
		if (strlen(p) > 1)
		{
			p[strlen(p) - 1] = '\0';
			for (i = 0; i < r; i++)
			{
				if (strcmp(p, t[i]) == 0)
				{
					pom.x = (char*)malloc(sizeof(char)* strlen(p));
					strcpy(pom.x, t[i]);
					m = 1;
					break;
				}
			}
		}
		if (m == 1) break;
		else printf("Wprowadz prawidlowe dane!\n");
	}
	return pom;
}
elem new_x(char** t)
{
	int i;
	char h[MAX];
	elem a;
	fflush(stdin);
	printf("\nLista mozliwych wariantow wyboru:\n");
	for (i = 0; i < n; i++) printf("- %s\n", t[i]);

	printf("\nDodaj nowy <+>\nPrzejdz dalej <t>\n\n");
	while (fgets(h, MAX, stdin))
	{
		if (h[0] == '+' && strlen(h) == 2)
		{
			n++;
			t = add_x(t, n);
			printf("\nDodaj nowy <+>\nPrzejdz dalej <t>\n\n");
		}
		else if (h[0] == 't' && strlen(h) == 2) break;
		else if (h[0] != 't' && h[0] != '+') printf("Wprowadz prawidlowe dane!\n");
	}
	a.x = (make_x(t, n)).x;
	return a;
} 
0

Błędów trochę jest w tym kodzie, najpierw proponowałbym je zredukować:

 t[0] = (char*)malloc(sizeof(char)*strlen("aaa")); strcpy(t[0], "aaa");

powinno być:

 t[0] = (char*)malloc(sizeof(char)*strlen("aaa") + 1); strcpy(t[0], "aaa"); 

(pozostałe analogicznie)

gubisz tu wskaźnik:

 t = (char**)realloc(t, r*sizeof(char*));

tu masz wątpliwej jakości alokacje:

 L->tail->data = new_x(t);

Tu masz niepoprawną operację:

fflush(stdin); 

fflush na stdin ma prawo nie działać i w wielu konsolach nie działa...

Więcej zapewne błedów też jest, ale po tych błędach sądzę, że powinieneś przemyśleć raz jeszcze strukturę programu i to co chcesz uzyskać, gdyż new_x i add_x obawiam się, ze będą działały inaczej niz sobie wyobrażasz...

0

Dzięki za szybką odpowiedź. Problemem była utrata wskaźnika w reallocu, tak jak napisałeś. To co napisałem działa, jednak mimo wszystko postaram się zmienić kilka rzeczy w kodzie, by był on bardziej czytelny.
Co miałeś na myśli w przypadku wątpliwej jakości alokacji w liście? Nie mam pojęcia, jak to inaczej wykonać :(

Edit: wiem, że fflush jest błędnym zapisem w przypadku stdin. Jednak czy jest jakaś funkcja w C, która czyści bufor rejestru pamięci?

0

Cóż - alokujesz jeden typ innym typem, to że adresy w tym przypadku będą podobne, nie oznacza, że jest to właściwe i może powodować błędy w przyszłości, jak będziesz chciał coś zmienić.

Jeśli chodzi o bufor: http://pl.comp.os.linux.programowanie.narkive.com/sU5AgbtQ/jak-wyczysci-bufor-stdin-w-c i http://www.matematyka.pl/258249.htm
fflush na stdin na 2 z 3 używanych przeze mnie konsol nie zadziała.

0

Może zastanów się nad:

typedef struct node
{
    struct node *next, *prev;
    char text[1];
}node;

void push_back(list *L,const char *text) // dodaje element na koniec listy
{
    size_t len=strlen(text);
    node *tmp=(node*)malloc(sizeof(node)+len);
    tmp->next=NULL;
    tmp->prev=L->tail;
    memcpy(tmp->text,text,len+1);
    if(L->tail) L->tail->next=tmp;
    else L->head=tmp;
    L->tail=tmp;
}

Trochę nie doczytałem pytania.
Więc powyższa propozycja tu nie pasuje.
Zastanów się nad:

typedef struct strlist
{
    struct strlist *next;
    char text[1]; // obsługa jak wyżej
}strlist;
typedef struct node
{
    struct node *next, *prev;
    strlist *head;
}node;

lub:

typedef struct strtable
{
    unsigned count; // ile masz już wierszy
    const char **text;
}strtable;
typedef struct node
{
    struct node *next, *prev;
    strtable head;
}node;

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