Array de Strings dinâmico com Strings de tamanho fixo - C - Portugal-a-Programar
Array de Strings dinâmico com Strings de tamanho fixo
By Rorsch, March 11, 2010 in C
Estou aqui às voltas com um código que preciso escrever em C. Tenho um ciclo que vai gerando strings de tamanho fixo (em char tagId[15]), e preciso ir adicionando-as a um Array de strings. Não sei à partida quantas strings vão ser geradas.
// Reads the Tag from the RFID Reader
if (nfc_initiator_select_tag(pdi,IM_ISO14443A_106,NULL,0,&ti)) {
// Converts the Tag ID from hex to String
strcpy(tagId,"");
for (uiPos=0; uiPos < ti.tia.uiUidLen; uiPos++) {
sprintf(temp,"%02x",ti.tia.abtUid[uiPos]);
strcat(tagId,temp);
Este bloco que código é executado inúmeras vezes (nunca sei quantas à partida), e após este for preciso ir adicionando o tagId a um Array de strings.
I would rather be a ghost drifting by your side as a condemned soul than enter heaven without you... Because of your love, I will never be a lonely spirit.
Tem mesmo de ser um array de strings ? ou poderias utilizar uma lista de strings ? Se utilizares uma lista de strings o problema fica facilitado. Se realmente necessitares de um array de strings (array de array de caracteres) penso que deverias criar um apontador de apontador de strings, em que depois poderias ir chamando o realloc (quando necessitasses) ou então criares uma estrutura de dados que te permita tirar partido de algumas propriedades do teu problema sem perderes assim tanto performance.
Uma lista de Strings em C é implementada de que forma falk0n? Posso acede-la por indexação (i)?
Por podes, mas é caro, se quiseres aceder ao 10 elemento (e que não seja o ultimo) tens de atravessar a lista até ao 10 elemento (ou seja passar por todos os outros anteriores).
A lista é implementada utilizando uma estrutura com a cabeça da lista, e o numero de elementos que essa lista tem.
A cabeça da lista é um nó em que esse nó tem o elemento (neste caso uma string) e um apontador para o próximo elemento.
Mas uma vez que perguntaste se poderias aceder por indexação é porque provavelmente necessitas desse tipo de acesso, e neste tipo de estruturas esse acesso é caro, por isso o que talvez te sirva será mesmo fazer um criar um "char ** array_de_chars" , e possívelmente utilizares o realloc sempre que necessitares de aumentares o numero de elementos para que apontas.
No caso de mais alguém precisar, fiz desta maneira:
typedef char Word[5+1];
Word *words = malloc(N * sizeof *words);
strcpy (words[0], "word1");
strcpy (words[5], "word6");
Ao que parece este código não está a funcionar como deve ser (estou a usá-lo através do JNI, é um diabo para debug). O meu código é este:
typedef char Tag[14];
Tag *tagsTmp = malloc(N * sizeof *tagsTmp);
strcpy(tagsTmp[tag_count], tagId);
A segunda parte do código está dentro de um ciclo que gera strings em tagId durante um período de tempo. O problema é que o array tagsTmp apresenta as strings erroneamente, e por vezes o código crasha simplesmente.
Correndo o mesmo código, mas definindo o tagsTmp como char *tagsTmp[2][14]; é o suficiente para evitar todos estes problemas, mas o ideal seria aceitar mais que duas tagId.
Estás a chamar o malloc com N=0? E a função sizeof está a ser chamada assim como mostras, sem parêntesis? Parece que funciona, mas não me parece uma sintaxe muito bonita...
Limitas muito o código que mostras. O que é que acontece ali no (...)? De onde vem o tagId? Como é que limitas o valor máximo de tag_count, de forma a não ultrapassar o tamanho actual do array?
A string tagId vem da conversão de um hexadecimal em string (como mostro no primeiro post). Basicamente tenho um código que guarda a identificação das tags RFID presentes no leitor. Enquanto houverem tags que ainda não foram identificadas vou gerando tagIds que guardo em tagsTmp.
Estou a chamar o malloc com N = 0, mas estou a ver que não é assim que se faz Também não limito o valor máximo de tag_count. Como posso declarar o tagsTmp correctamente?
O malloc recebe como parâmetro o número de bytes que queres alocar. Se o chamas com N * sizeof(Tag), sendo N = 0, estás a pedir para alocar 0 bytes. Não tenho a certeza, mas se estiver errado alguém me corrija: o comportamento da função malloc quando é chamada com 0 não está definido.
Tens que colocar em N o número de arrays que pretendes alocar inicialmente.
E depois como vou alocando mais memória à medida que vou precisando?
Sim, sem nunca esquecer que não podes perder o endereço (ponteiros)
Depois, se chegares ao limite de strings que alocaste, tens que realocar o array, e copiar as strings existentes do antigo para o novo, libertando em seguida o antigo.
Essa seria a vantagem das listas sugeridas pelo falk0n: de cada vez que precisasses de adicionar uma string, só tinhas que alocar essa string e adicioná-la ao fim da lista. Com um array de strings, tens que alocar espaço para mais strings e copiar as antigas.
A melhor solução será baseada na tua utilização da colecção: será que vais fazer acessos sequenciais (aceder a várias strings seguidas) e adicionar strings muitas vezes (implicando realocação frequente do array de strings e subsequente cópia, no caso do array), favorecendo a lista? Ou será que até nem vais precisar de criar novas strings assim tantas vezes, e acedes às strings aleatoriamente, favorecendo o array?
Pois, a ideia de listas parece ser o que mais se adequa à minha situação, vou gerar e aceder às strings sequencialmente. Sabem onde posso encontrar um exemplo para C? Tudo o que encontro é para C++ :/
Procurando no Google por C list implementation, encontram-se várias implementações. Esta:
http://www.niksula.hut.fi/~tik76122/arkisto/dsaa_c2e/list.h
http://www.niksula.hut.fi/~tik76122/arkisto/dsaa_c2e/list.c
assim rapidamente, pareceu-me interessante, embora precise de algumas alterações para funcionar com strings.