How to solve the c variable problem - string capacity, start to grow exponentially from the 3rd cycle

Asked

Viewed 39 times

-1

I’m having a problem, here with a program that aims to be a data entry routine, the problem in question, is the variable c that goes to the Cap function to ask the user the maximum capacity of the string, when it reaches the 3rd cycle of the for it starts to grow up who knows what pq, making mine for something unusable.

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


int func_carac(int *car) //funcao que pesca os caracters intrudozidos pelo user
{
  int caracter;

  printf("\nDigite o caracter que quiser: \n");
  caracter = getche();

  *car = caracter;
  return *car;
}

//________________________________________________________\\

int func_capac(int *cap) //funcao para pedir ao user a quantidade de caracteres
{
  int quant;

  printf("\nDetermine a capacidade m�xima de caracteres que quer escrever: ");
  scanf("%d",&quant);

  *cap = quant;

  return *cap;
}

int main()
{
  int car, pos, c, total;
  char vetor[] = {'\0'};

  func_capac(&c);

  total = c + 1;
  vetor[total];
  vetor[total] = '\0';
  printf("%i", c);

  for(pos = 0; pos < c; pos++)
   {
    func_carac(&car);
    if((car >= 97) && (car <= 122) || (car == 32))
     {
      printf("\n%c - Tabela ASCII, %d \n",car ,car);
      printf("%i", c);
    
      vetor[pos] = (char) car;
     }
    else if(car == 8)
     {
      printf("Removeu com sucesso o caracter anterior.");
      pos = pos-2;
     }
    else
     {
      pos--;
     }
   }
  printf("Frase: %s\n",vetor);
}```
Se alguem me pudesse ajudar ficava agradecido 

1 answer

1

Your program has a lot of problems. I think some things don’t work the way you think. I’ll try to rewrite the program and show you some examples, because I think it might help others.

I’ll try not to change the structure and leave everything as you wrote.

the headers and the first function

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

int func_carac(int *car) //funcao que pesca os caracters intrudozidos pelo user
{
  int caracter;

  printf("\nDigite o caracter que quiser: \n");
  caracter = getche();

  *car = caracter;
  return *car;
}

I don’t think he uses string.h or of stdlib.h. Avoid including unnecessary headers.

conio.h On the other hand, it’s something from the '80s and I think you should just forget about it. It’s not portable, there’s nothing important inside, it’s not part of the language and it’s over 40 years old. It comes from a Borland library used in the 1980s in a product called Turbo C, shortly after the Turbo Pascal that had something similar.

In relation to function:

    int func_carac(int *car) //funcao que pesca os caracteres introduzidos pelo user

What is the purpose of passing a parameter, a pointer, if the function will return a int? And why return a int if you’re going to read a letter?

Return only the letter:

char        func_carac() //funcao que pesca os caracteres introduzidos pelo user

and so can use in an expression, as in

    char car = func_carac();

instead of

func_carac(&car);
  • main() should be the first function of your program. Or left in a separate file. It is the most readable and the most practical: so you can write several tests for your functions and distribute to use in other programs. This is what they are written for. Use prototypes. And a file . h if possible.

func_capac()

Here is the same problem: the goal is only to return a number, a size. It can return a negative value, so it gives the guy a chance to give up, or return the maximum vector size. But you once again use a pointer. If you can, avoid using accents. It will only give problem and little adds. Prefer

    int func_capac(); //funcao para pedir ao user a quantidade de caracteres

and so instead of writing

  int capacicade = func_capac(&c);

can write something more readable, like

  int capacidade = func_capac();

the vector

  char vetor[] = {'\0'};
  • why write ' 0' for a zero? zero is zero. Write 0.
  • so that --- hypothetically --- initialize the vector if it will read the following elements?
  • in C it is necessary to give a fixed, constant dimension to the vector in the statement. And you set as [1] when declaring how you did. What you wrote is the equivalent of

char vetor[1] = 0;

But what you really want is to create a vector of the size specified by the user. The common way to do this is to use malloc() or calloc() and pass size. And the function came size func_capac().
The difference between calloc() and malloc() is that the second initializes the allocated area with zeros, which is what you tried to do. But it is not very useful in this case: as I said, you will read values on top of these so there is no reason to waste time getting everything started. You can just write

  int capacidade =  func_capac();
  char* vetor =     malloc(capacidade);

And then read the values.

  for(pos = 0; pos < c; pos++)
   {
    func_carac(&car);
    if((car >= 97) && (car <= 122) || (car == 32))
     {
  • Prefer the simple: 'a' to 97 and 'z' to 122. For the compiler it doesn’t matter. And for those who are reading the program the simple is better: the letter. No one will find your program better because you know the letter codes in the ASCII table. Until the program runs in an environment that does not eventually use ASCII :) and where your program will stop working.
  • NEVER leave the control variables of a loop outside of it unless the logic so asks. It took many years to correct this in C, but it was done in the 80’s. Write
    for(int pos = 0; pos < c; pos++)
    {   // preenche o vetor
        vetor[pos] = func_carac();
        if(
            ((vetor[pos] >= 'a') && (vetor[pos] <= 'z')) || 
            (vetor[pos] == ` `)
        )   printf("\nvetor[%d/%d] = `%c` - Tabela ASCII = %d \n",
                pos, capacidade, vetor[pos], vetor[pos]);
    };  // for()

About that part:

    else if(car == 8)
     {
      printf("Removeu com sucesso o caracter anterior.");
      pos = pos-2;
     }
    else
     {
      pos--;
     }
   }

Understand that this is very problematic: pos is a global variable. And it’s still the loop control variable! So you’re simply reconsidering the subtraction increment. And the else guarantees it. So it’s not right... The simple is

  • don’t use pos++ in the for
  • only increase pos if the value is not BACKSPACE. And again I recommend writing something like Backspace and not 8. No one will be impressed by you knowing the BACKSPACE code but many will not like to keep reading the program 8, 32, 97 and 122. It can be considered pedantic. But it’s less readable for sure... Here’s what you tried to write:
#define BACKSPACE 8
// ...
    for(int pos = 0; pos < capacidade;)
    {
        func_carac(&car);
        if((car >= 97) && (car <= 122) || (car == ` `))
        {
            // ...
        }
        if(car != BACKSPACE) ++pos;
     }

the issue of reading the Backspace

In general the terminal input is done in a mode called "cooked mode" in Unix and descendants or "line input" on Windows and since DOS. And that means, among other things, that the characters appear on the screen as you type, and the function only returns and always returns when reading a ENTER, the such newline, '\n'. And the user can use Backspace to erase what was typed.

Only a series of backspaces can go on erasing until there’s no more walking the line, and yet the guy can keep typing backspaces for all eternity. In your program this doesn’t work: it would only treat one Backspace at a time and would have to have a letter later.
getche() conio. h can return 8 to BACKSPACE but will not recreate the behavior of the system. It would be missing to return the cursor, delete the letter and such...
It doesn’t seem to be a good reason to use this ancestral function to be a part of what the system already does.
If you really want to recreate this behavior use the classic:

  • disconnect echo and line input, using ioctl() on Unix or SetConsoleMode() on Windows.
  • read the keys and edit the buffer as the data enters
  • this includes moving the cursor to the right place and erasing as they enter BACKSPACES

the program rewritten

Without the BACKSPACE part, because that’s not how it works and that’s not what I’m trying to show (how to recreate LINE INPUT). If that’s what you want to write back or post another question and show an example for Windows or Linux when the time comes.

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

int         func_capac();
char        func_carac();

int main(void)
{
    int capacidade =  func_capac();
    char* vetor =     malloc(capacidade);

    for(int pos = 0; pos < capacidade; pos++)
    {   // preenche o vetor
        vetor[pos] = func_carac();
        if(
            ((vetor[pos] >= 'a') && (vetor[pos] <= 'z')) || 
            (vetor[pos] == ` `)
        )   printf("\nvetor[%d/%d] = `%c` - Tabela ASCII = %d \n",
                pos, capacidade, vetor[pos], vetor[pos]);
    };  // for()
    printf("Frase: \"%s\"\n",vetor);
    free(vetor);
};  // main()


int func_capac() //funcao para pedir ao user a quantidade de caracteres
{
    int quant;
    printf("\nDetermine a capacidade maxima de caracteres que quer escrever: ");
    int res = scanf("%d", &quant);
    fgetc(stdin); // le o resto da linha
    if ( res != 1 ) return -1; // nao leu nada
    if ( quant < 1 ) return -2; // tem que ser positivo
    return quant;
}


char        func_carac() //funcao que pesca os caracters introduzidos pelo user
{
    printf("\nDigite o caracter que quiser: \n");
    char car = fgetc(stdin); // de stdio.h
    fgetc(stdin); // le o '\n'
    return car; // de stdio.h
};

an execution of that

tst$ gcc -Wall -o outro -O3 -Wall -std=c17 outro.c
tst$ ./outro

Determine a capacidade maxima de caracteres que quer escrever: 4

Digite o caracter que quiser: 
1

Digite o caracter que quiser: 
2

Digite o caracter que quiser: 
3

Digite o caracter que quiser: 
4
Frase: "1234"
  • I appreciate the response proposal, but this is the exercise I was asked for at the university, it is about ASCII table, so yes the professor will "find my program better because I know the codes of letters in the ASCII table", among other things I did purposely by being asked, I’m sorry if I find a code poorly done, but I already fixed my error that was the cycle did not work due to string. I hope you have a good day. And by the way study more, because we all need ;)

  • :) It’s a good thing you fixed everything. Surely using numbers instead of letters to designate letters was not really the problem. But I imagine you’ve revised your statement of vetor, memory allocation and function arguments. And note that at most one Backspace will be treated at a time in the loop the way you wrote it. Hug

Browser other questions tagged

You are not signed in. Login or sign up in order to post.