0

as said on the title, my function is not calculating the correct amount os characters in a given string.

The function is this one:

   void contar(char **texto, int *quantidade, int N)
 {
    int i, j, aux;

    for(i=0;i<N;i++)
    {
        for(j=0;texto[i][j]!='\0';j++)
        {
            aux = (int) texto[i][j];            
            /* If upper case */
            if(64 < aux && aux < 91)
            {
                aux = aux - 65;
                quantidade[aux]++;
            }
            /* If lower case */
            else if(96 < aux && aux < 123)
            {
                aux = aux - 71;
                quantidade[aux]++;
            }
        }
    }
    for(i=0;i<52;i++)
    {
        printf("\n i-%d  %d\n", i, quantidade[i]);
    }
 }

My objective is: take the character, check his number according to the ASCII table. If the number represents an Upper Case Character, I subtract it by 65 and use it as the index of my vector and increment the vector in that position. If it is a Lower Case Character, I subtract it by 71, because the last Upper Case Character is Z, which corresponds to 90. And the 'a' corresponds 97. So 90 - 65 = 25 and 97 - 65 = 32, as I dont wanna leave this gap in the vector, I do 97 - 65 - 6.

What is happening is that, for certain characters, the function is counting 1 character less. For example, on the text below, the function counts only 5 'A', when there is actually 6.

Duvidas Frequentes E um grau do ensino superior obtido em cursos de Graduacao, ministrados pela Universidade, destinados a alunos que tenham concluido o ensino medio ou equivalente. A Unicamp oferece cursos de Graduacao em diferentes areas do conhecimento. A estrutura de ensino e pesquisa da Unicamp esta, em sua maior parte, no campus de Barao Geraldo, em Campinas. Em Piracicaba funciona a Faculdade de Odontologia de Piracicaba (FOP); em Limeira, a Faculdade de Tecnologia (FT) e Faculdade de Ciencias Aplicadas (FCA); em Paulinia, o Centro de Pesquisas Quimicas, Biologicas e Agricolas (CPQBA); em Sumare, o Hospital Estadual; e, em Hortolandia, o Hospital Mario Covas.

The rest of the code is the following one:

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

 void encriptar(char **texto, int **ascii, int *quantidade, int *prioridade, int N);
 void matriz_ascii(char **texto, int **ascii, int N);
 void ordenar(int *quantidade, int *prioridade);
 void contar(char **texto, int *quantidade, int N);
 int checarMaior(int *quantidade, int i);
 void troca(int **ascii, int *prioridade, int N);

 int main()
 {
    int N, i, j, quantidade[52], prioridade[26], **ascii;
    char **texto;

    for(i=0;i<52;i++)
    {
        quantidade[i] = 0;
    }

    for(i=0;i<26;i++)
    {
        prioridade[i] = 0;
    }
    scanf("%d", &N);

    setbuf(stdin, 0);

    texto = malloc(N * sizeof(char *));
    ascii = malloc(N * sizeof(char *));

    for(i=0;i<N;i++)
    {
        texto[i] = malloc(501 * sizeof(char));
        ascii[i] = malloc(501 * sizeof(char));
    }

    for(i=0;i<N;i++)
    {
        fgets(texto[i], 501, stdin);
    }

    encriptar(texto, ascii, quantidade, prioridade, N);

    for(i=0;i<N;i++)
    {
        for(j=0;texto[i][j];j++)
        {
            texto[i][j] = (char) ascii[i][j];
        }
    }

    printf("\n");

    for(i=0;i<N;i++)
    {
        printf("%s", texto[i]);
    }

    printf("\n");

    for(i=0;i<26;i++)
    {
        printf("%d ", prioridade[i]);
    }

    printf("\n");       

    return 0;
 }

 void encriptar(char **texto, int **ascii, int *quantidade, int *prioridade, int N)
 {
    matriz_ascii(texto, ascii, N);

    contar(texto, quantidade, N);

    ordenar(quantidade, prioridade);

    troca(ascii, prioridade, N);
 }

 void matriz_ascii(char **texto, int **ascii, int N)
 {
    int i, j;

    for(i=0;i<N;i++)
    {
        for(j=0;texto[i][j]!='\0';j++)
        {
            ascii[i][j] = (int) texto[i][j];
        }
    }
 }

 void contar(char **texto, int *quantidade, int N)
 {
    int i, j, aux;

    for(i=0;i<N;i++)
    {
        for(j=0;texto[i][j]!=0;j++)
        {
            /*aux = (int) texto[i][j];
            printf("%d ", aux); */      
            /* Se for maiusculo */
            if(65 <= texto[i][j] && texto[i][j] <= 90)
            {
                aux = texto[i][j] - 65;
                quantidade[aux]++;
            }
            /* Se for minusculo */
            else if(97 <= texto[i][j] && texto[i][j] <= 122)
            {
                aux = texto[i][j] - 71;
                quantidade[aux]++;
            }
        }
        printf("\n");
    }
    /*for(i=0;i<52;i++)
    {
        printf("\n i-%d  %d\n", i, quantidade[i]);
    }*/
 }

 void ordenar(int *quantidade, int *prioridade)
 {
    int i, i_maior;
    for(i=0;i<26;i++)
    {
        quantidade[i] += quantidade[i+26];
    }

    for(i=0;i<26;i++)
    {
        i_maior = checarMaior(quantidade, 0);
        quantidade[i_maior] = -1;
        prioridade[i] = i_maior;
    }

 }

 int checarMaior(int *quantidade, int i)
 {
    int i_maior = i, maior = quantidade[i];

    for(i=i+1;i<26;i++)
    {
        if(quantidade[i] > maior)
        {
            maior = quantidade[i];
            i_maior = i;
        }
        else if(quantidade[i] == maior)
        {
            if(i < i_maior)
            {
                i_maior = i;
            }
        }
    }

    return i_maior;
 }

 void troca(int **ascii, int *prioridade, int N)
 {
    int i, j, i_aux, i_num, aux, valor = -1;
    for(i=0;i<N;i++)
    {
        for(j=0;ascii[i][j];j++)
        {   
            aux = ascii[i][j];
            /* Se for maiusculo */
            if(64 < aux && aux < 91)
            {
                aux = aux - 65;
                valor = 1;
            }
            /* Se for minusculo */
            else if(96 < aux && aux < 123)
            {
                aux = aux - 97;
                valor = 0;
            }
            else
            {
                valor = -1;
            }

            if(valor != -1)
            {
                for(i_aux=0;i_aux<26;i_aux++)
                {
                    if(prioridade[i_aux] == aux)
                    {
                        i_num = i_aux;
                    }
                }
                if(i_num % 2 == 0)
                    aux = prioridade[i_num+1];
                else
                    aux = prioridade[i_num-1];

                if(valor == 1)
                    ascii[i][j] = aux + 65;
                else if(valor == 0)
                    ascii[i][j] = aux +97;
            }
        }   
    }
 }

Any ideas of what I am doing wrong?

Thanks in advance!

Falcon
  • 89
  • 7
  • 1
    So you are posting a wall of code and want us to debug it for you? – OldProgrammer May 13 '14 at 00:33
  • Not at all! I have tried alredy to find the error, but I just can't. I tested the code and it just keep giving the wrong output. I am posting here because I really don't know where is my mistake. I have also alredy asked friends and they couldn't find the error as well. Also, there is actually no need to read all the code, since the content of "texto" is correct! I did a printf and it has the correct text, so it looks like the problem is in the function, but I can't find it. – Falcon May 13 '14 at 00:37
  • I did some more testing and I also changed the malloc of ascii to int! With GDB I found that there is a segmentation fault at line 49, which is this -> texto[i] = malloc(501 * sizeof(char)); – Falcon May 13 '14 at 00:50
  • 1
    You should refactor your code into smaller pieces, that would make them easy to test separately to narrow down the problem. If you are sure the error is in `contar` you should make a simple program, that feeds it some fixed data, and tell the input, expected and actual results and present the small simple `main` that calls the function and reproduces the problem. Then it would be much more approachable. Currently too much people started to post debug questions with kilobytes of code. Solving them take quite much effort and is not really useful for others. So people often ignore them. – luk32 May 13 '14 at 01:06

1 Answers1

0

The quantidade function seems OK. But this loop in matriz_ascii has a problem:

for(i=0;i<N;i++)
    {
        for(j=0;texto[i][j]!='\0';j++)
        {
            ascii[i][j] = (int) texto[i][j];
        }
    }

This does not copy the null-terminator. But later on, in troca you have a loop that runs until ascii[i][j] == 0;. That loops will run off the end of the copied values until they happen to come across a 0 in other memory, which is bad.

As you point out in comments, you malloc the wrong amount of space also (on two different lines). You could have avoided that by using this idiom:

texto = malloc(N * sizeof *texto);
ascii = malloc(N * sizeof *ascii);

for(i=0;i<N;i++)
{
    texto[i] = calloc(501, sizeof *texto[i]);
    ascii[i] = calloc(501, sizeof *ascii[i]);
}

The reason I use calloc is so that if your fgets lines fail (e.g. due to end of input) then your array contains blank strings, which your code handles correctly. Without that, a short input file would cause your code to operate on uninitialized memory.

Other things you can do to make your code more readable and robust:

  • replace magic numbers like 65 with 'A',
  • replace loops that set things to 0 with initialization to = { 0 };, or calloc
  • Check that malloc does not return NULL.

Also you should make more of an effort to debug before posting on here. If something is not working, then change your code to add extra debugging output (or use a debugger) until you find out exactly which little piece is causing the program to go from good to bad. Also you can try valgrind.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • Thank you! I am just starting to learn about C! I had never heard about calloc and valgrind until now, but i will take a look ate them! I am also starting to learn how to use GDB! Thanks a lot! I will apply those changes to my code and sorry for anything I did that didn't follow the site rules! – Falcon May 13 '14 at 01:18