Retornando vetor de strings em C

Iniciado por mhkgalvez, 04 de Junho de 2010, 15:22

tópico anterior - próximo tópico

mhkgalvez

Olá pessoal, tenho uma função que desejo que retorne um vetor de Strings em C.

Estou usando char *hasError(char *stream), mas não dá certo.

Minha função main:

int main (int argc,char *argv[])
{
   char *text;
   text = takeEptSpc("5 5 ");
   char *ret;
   
   ret = hasError("5 5 ");

   int i = 0;

   for (i = 0; i < 5; i++)
       printf("%s", ret[i]);
   return 0;
}


Na execução, ele retorna erro de segmentação.

O que posso fazer para retornar corretamente um vetor de strings?
"A quem vencer, eu o farei coluna no templo do meu Deus, e dele nunca sairá; e escreverei sobre ele o nome do meu Deus, e o nome da cidade do meu Deus, a nova Jerusalém, que desce do céu, do meu Deus, e também o meu novo nome."

rudregues

mhkgalvez poste o código completo, senão num tem como saber onde tá a falha  :P
Gentoo — Controle total sobre o sistema.

mhkgalvez

Função hasError:

char *hasError(char *stream, char mode)
{
    int i = 0, htmlCodeLenght = 1;
    int *listGt, *listLt;
    int countLt = 0, countGt = 0;
    char *htmlCode = stream;
    char *out[5];

    stream = takeEptSpc(stream);

    //Initializing out array   
    for (i = 0; i < 5; i++)
    {
        out[i] = "";
    }
    //End initializing out array

    //Looking at '<' and '>' chars
    htmlCodeLenght = countString(htmlCode);
    for (i = 0; i < htmlCodeLenght; i++)
    {
        if (htmlCode[i] == '<')
        {
            countLt++;
        }
        if (htmlCode[i] == '>')
        {
            countGt++;
        }
    }

    if (countGt != countLt)
    {
        printf("Error 1 of HTML Tag. The tags weren't opened or closed correctly.");
        out[0] = "Error 1 of HTML Tag. The tags weren't opened or closed correctly.";
        if (mode == 'o')
            return out;
    }

    listLt = (int *) malloc(countGt * sizeof(int));
    listGt = (int *) malloc(countGt * sizeof(int));

    for (i = 0; i < countGt; i++)
    {
        if (htmlCode[i] == '<')
        {
            listLt[i] = i;
        }
        if (htmlCode[i] == '>')
        {
            listGt[i] = i;
        }
    }

    for (i = 0; i < countGt; i++)
    {
        if (listGt[i] < listLt[i])
        {
            printf("Error 2 of HTML Tag. The tags weren't opened or closed correctly.");
            out[1] = "Error 2 of HTML Tag. The tags weren't opened or closed correctly.";
            if (mode == 'o')
                return out;
        }
    }
    //End looking at '<' and '>' chars

    //Looking at order of '<' and '>' chars
    int ind = 0;

    for (i = 0; i < countGt; i++)
    {
        while (htmlCode[ind] != '<' && htmlCode[ind] != '>')
            ind++;

        if (htmlCode[ind] == '>')
        {
            printf("Error 3 of HTML Tag. The tags weren't opened or closed correctly.");
            out[2] = "Error 3 of HTML Tag. The tags weren't opened or closed correctly.";
            if (mode == 'o')
                return out;
        }
        if (htmlCode[ind] == '<')
        {
            while (htmlCode[ind] != '>')
            {
                if (htmlCode[ind] == '<')
                {
                    printf("Error 4 of HTML Tag. The tags weren't opened or closed correctly.");
                    out[3] = "Error 4 of HTML Tag. The tags weren't opened or closed correctly.";
                    if (mode == 'o')
                        return out;
                }
                ind++;
            }
        }
    }
    //End looking at order of '<' and '>' chars

    printf("Código HTML sem nenhuma falha");
    return out;
}


Considero que não tem erro nela, pois os vetores são iniciados com vazio no início. Por isso, creio que o erro esteja no tipo de retorno da função.
"A quem vencer, eu o farei coluna no templo do meu Deus, e dele nunca sairá; e escreverei sobre ele o nome do meu Deus, e o nome da cidade do meu Deus, a nova Jerusalém, que desce do céu, do meu Deus, e também o meu novo nome."

rudregues

Realmente...parece que tá certo...

Você colocou todas as bibliotecas? Tá usando o gcc como compilador?
Gentoo — Controle total sobre o sistema.

RonaldoRG

Não seria porque você tá retornando "out" que está declarado como "char *out[5]" que é um vetor de ponteiros? Na função main você tá atribuindo o retorno da função para um ponteiro.

Eu fiz um teste simples aqui sobre esse retorno e deu erro.
Ubuntu 12.04

mhkgalvez

Pessoal, o que acontece é que fazia algum tempo que eu programava em C, e essa questão de trabalhar com strings em C sempre me confundiu, então, vejam bem:

-> Para eu criar um texto simples eu faria char *texto e atribuiria o valor da string, por exemplo:

texto = "olá";

No caso de um vetor de strings, eu faria char *text[10] onde 10 seria o número de strings. E, na função hasError este tipo de uso está funcionando.
O problema é quando retorno isso. Eu tentei usar, como assinatura da função hasError um retorno char[], ou char hasError(...)[], ou ainda char[10], etc. Mas antes mesmo de compilar no NetBeans 6.8 acusa erro se sintaxe.

O problema de fazer sem ser uma variável de ponteiros é que, eu acho [me corrijam se eu estiver errado] que não dará para eu colocar as strings do tamanho que eu quiser. Desta maneira, ficarei limitado.

Volto a dizer que estou enferrujado. Haveria, então, alguma forma de contornar este problema?
"A quem vencer, eu o farei coluna no templo do meu Deus, e dele nunca sairá; e escreverei sobre ele o nome do meu Deus, e o nome da cidade do meu Deus, a nova Jerusalém, que desce do céu, do meu Deus, e também o meu novo nome."

RonaldoRG

CitarNo caso de um vetor de strings, eu faria char *text[10]
Ai você tá declarando um vetor de ponteiros com 10 posições, é como se fosse um ponteiro para ponteiro. Com isso você pode criar uma matriz de strings.
Para um vetor de strings basta "char text[10]", ai você tem um vetor de strings com 10 posições, ou usando ponteiros "char *text = (char*)maloc(10*sizeof(char));".
Ubuntu 12.04

rudregues

Citação de: RonaldoRG online 04 de Junho de 2010, 23:30
CitarNo caso de um vetor de strings, eu faria char *text[10]
Ai você tá declarando um vetor de ponteiros com 10 posições, é como se fosse um ponteiro para ponteiro. Com isso você pode criar uma matriz de strings.
Para um vetor de strings basta "char text[10]", ai você tem um vetor de strings com 10 posições, ou usando ponteiros "char *text = (char*)maloc(10*sizeof(char));".
pra deixar mais simples ainda você pode inicializar o valor do vetor na declaração mesmo:
  char text[10]="olá";
Gentoo — Controle total sobre o sistema.

mhkgalvez

Tah mas e o problema do retorno!??? ???
"A quem vencer, eu o farei coluna no templo do meu Deus, e dele nunca sairá; e escreverei sobre ele o nome do meu Deus, e o nome da cidade do meu Deus, a nova Jerusalém, que desce do céu, do meu Deus, e também o meu novo nome."

rudregues

Citação de: mhkgalvez online 05 de Junho de 2010, 20:26
Tah mas e o problema do retorno!??? ???
ainda não sei...

mas na sua função main você passou um parâmetro errado em 'hasError()', ou melhor dizendo, você só passou um parâmetro, mas a 'hasError()' tava definida para receber dois.
Gentoo — Controle total sobre o sistema.

Darcamo

O problema é que em C puro você não tem realmente um tipo de variável para strings. O que é feito então em C é utilizar um vetor caracteres "como se fosse uma string", mas você não pode esquecer que isso na verdade é apenas um vetor de caracteres. Lembre-se também que um vetor nada mais é do que um ponteiro para o primeiro elemento do vetor.

Isso quer dizer que você deve sim dizer qual o tamanho do vetor quando declarar uma variável usada para guardar uma "string".
Quando você escreve algo como
hello = "hello";
o que acontece é que o "hello" é um array de char e a variável 'hello' recebe o endereço desse array de char então está tudo bem nesse caso.

Se você quiser copiar strings de uma variável para outra você deve usar a função strcpy. Se você simplesmente usar "=" você estará na verdade copiando o endereço de uma variável para a outra e ambas vão apontar para a mesma região de memória. Compile e rode o programa abaixo para ver esse efeito.

int main(int argc, char *argv[])
{
    char* hello = "Hello Cruel World";
    char hello2[20];
    char* hello3;

    /* Vamos copiar usando strcpy */
    strcpy(hello2,hello);
    hello3 = hello;

    /* Vamos imprimir o conteudo de cada variável */
    printf("%s\n",hello);
    printf("%s\n",hello2);
    printf("%s\n",hello2);
   
    /* Vamos imprimir o valor dos ponteiros para cada variável */
    printf("%p\n",hello);
    printf("%p\n",hello2);
    printf("%p\n",hello3);

    /* Note que hello e hello3 possuem o mesmo ponteiro */
   
    return 0;
}


Da mesma forma, se você tentar comparar strings com
stringA == stringB
você estará comparando apenas se os ponteiros são iguais e não se o conteúdo das variáveis corresponde a mesma string. A maneira correta é utilizar a função strcmp. No exemplo acima se você fizer se você fizer o teste "hello==hello2" vai dar falso, mesmo que ambas as variáveis tenham o mesmo conteúdo.

Esse site
http://www.cplusplus.com/reference/clibrary/cstring/
é uma boa referência.

Ps: Na verdade não tenho muita experiência com C puro, já que quase sempre programo em C++ (std::string é de fato um tipo para strings e é bem melhor de se trabalhar que um vetor de char puro), então se eu disse alguma besteira deem um desconto, mas em geral trabalhar com "strings" em C é bem chato.

farinha

Já experimentou usar o gdb e correr o programa passo a passo a ver onde é que quebra? Ou usar printscreens para ir vendo onde quebra?

fpissarra

Darcamo está correto na interpretação sobre "strings" em C.
Eis uma possível solução para o seu problema:

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

static const char STR1[] = "String 1";
static const char STR2[] = "String 2";

/* Um macrozinho só para facilitar a vida... */
#define COPY_CONS_STRING(a, i, s) \
  (a)[(i)] = (char *)malloc(sizeof(char)*strlen((s))+1); \
  strcpy((a)[(i)], (s));

/*
  Como o array de strings pode ser definido como um "char **",
  precisamos passar um "char ***" para podermos alocar o vetor e retorná-lo.
*/
int GetStringArray(char ***strArray)
{
  char **out;

#define NUM_ITEMS 2

  out = (char **)malloc(sizeof(char *) * NUM_ITEMS);
 
  COPY_CONST_STRING(out, 0, STR1);
  COPY_CONST_STRING(out, 1, STR2);

  *strArray = out;

  /* Retorna o número de strings no array de strings */
  return NUM_ITEMS;
}

/* Libera strings alocadas */
void FreeStringArray(char **strArray, int count)
{
  int i;

  for (i = 0; i < count; i++)
  {
    free(strArray[i]);
    strArray[i] = NULL;
  }

  free(strArray);
}

int main(int argc, char **argv)
{
  int strCount, i;
  char **strings;

  /* Pega array de strings */
  strCount = GetStringArray(&strings);

  for (i = 0; i < strCount; i++)
    printf("%s\n", strings[i]);

  /* Libera array de strings */
  FreeStringArray(strings, strCount);

  return 0;
}


Mas, você pode achar mais fácil mexer com a STL, em C++, usando os templates/classes "vector" e "string".

[]s
Fred