0

I am attempting to minimize the memory allocation for the following program. The whole idea behind my attempt to dynamically allocate memory is

  1. Dynamically allocate memory for a user's string input with 30 bytes
  2. If the user's input is bigger than the allocated memory, call realloc() function to fit the string with 101 bytes
  3. If the user's input is bigger than 100 bytes, call exit() and terminate the program.

When I implemented realloc() function to check whether user input fits into dynamically allocated char array (line with calloc), my program fails with the following output:

realloc(): invalid next size
Aborted (core dumped)

I am not sure how to resolve it.

Code:

#include <stdio.h>  //gets() was removed from this library
#include <stdlib.h> //for calloc()
#include <string.h> //for strlen()
#include <unistd.h> //for sleep(2)
int len = 0;
struct item
{
    //i cant make sure pointer points to nothing because structures are only a templates.
    //i cant do operations here!!!!!!!
    char *itemName;
    int qty;
    float price;
    float amount;
};

int readItem(struct item *pProduct)

{
    printf("hey, what is the product name: ");
    gets(pProduct->itemName);

    //checking whether user's input fits into the allocated pointer size
    len = strlen(pProduct->itemName);
    printf("%d\n\n", len);

    if (len > 30)
    {
        //error here
        pProduct->itemName = (char *)realloc(pProduct->itemName, 101);

        printf("\nyour input is too big. re enter it\n");
        gets(pProduct->itemName);

        if (pProduct->itemName == NULL)
        {
            puts("memory is not avaible");
            exit(1);
        }
        len = strlen(pProduct->itemName);
        printf("%d\n\n", len);
        if (len > 100)
        {
            puts("memory is not avaible");
            exit(1);
        }
    }
    printf("\nEnter the product quantity: ");
    scanf("%d", &pProduct->qty);

    printf("\nEnter the product price: ");
    scanf("%f", &pProduct->price);

    //calculating the amount
    pProduct->amount = (float)pProduct->qty * pProduct->price;

    return 0;
}

void printItem(struct item *pProduct)
{
    puts("\n\nthe database:");
    sleep(1);

    printf("----------------------\n");
    printf("Name: \"%s\"\n", (*pProduct).itemName);
    printf("Price: %.2f\n", pProduct->price);
    printf("Quantity: %d\n", pProduct->qty);
    printf("Amount: %.2f\n", pProduct->amount);
    printf("----------------------\n");
}

int main()
{

    //assigning variable product and piinter pProduct to a tag name item,
    struct item product, *pProduct = NULL;
    //storing an address to a pointer pProduct
    //making a structure to a pointer
    pProduct = &product;

    //(char *) is casting char to a pointer type

    pProduct->itemName = (char *)calloc(30, sizeof(char));

    readItem(pProduct);
    printItem(pProduct);

    free(pProduct->itemName);
    pProduct->itemName = NULL;
    pProduct = NULL;

    return 0;
}

I know precisely REALLOC causes the trouble. To be more precise, if I enter 34 characters realloc seems to work, but if double it to 68, it throws the error despite the mentioned size in realloc

I have zero knowledge in call stack, but it might be useful for someone:


    libc.so.6!__GI_raise(int sig) (/build/glibc-YYA7BZ/glibc-2.31/sysdeps/unix/sysv/linux/raise.c:50)
     
    libc.so.6!__GI_abort() (/build/glibc-YYA7BZ/glibc-2.31/stdlib/abort.c:79)
     
    libc.so.6!__libc_message(enum __libc_message_action action, const char * fmt) (/build/glibc-YYA7BZ/glibc-2.31/sysdeps/posix/libc_fatal.c:155)
     
    libc.so.6!malloc_printerr(const char * str) (/build/glibc-YYA7BZ/glibc-2.31/malloc/malloc.c:5347)

    libc.so.6!_int_realloc(mstate av, mchunkptr oldp, size_t oldsize, size_t nb) (/build/glibc-YYA7BZ/glibc-2.31/malloc/malloc.c:4564)
     
    libc.so.6!__GI___libc_realloc(size_t bytes, void * oldmem) (/build/glibc-YYA7BZ/glibc-2.31/malloc/malloc.c:3226)
     
    libc.so.6!realloc_hook_ini(void * ptr, size_t sz, const void * caller) (/build/glibc-YYA7BZ/glibc-2.31/malloc/hooks.c:41)
     
    readItem(struct item * pProduct) (/home/max/My stuff/programming/Udemy/section 14, reading and wrinting files/test.c:22)
     
    main() (/home/max/My stuff/programming/Udemy/section 14, reading and wrinting files/test.c:72)
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
max
  • 166
  • 13
  • 1
    That error is one you typically get when you have written out of bounds of your allocated memory. If you can't find the problem through normal debugging techniques (like [rubber duck debugging](https://en.wikipedia.org/wiki/Rubber_duck_debugging) or stepping through the code statement by statement in a debugger) you could use tools such as [Valgrind](https://www.valgrind.org/) to help you. – Some programmer dude Sep 05 '20 at 11:29
  • 1
    One obvious problem: You have the comment `//gets() was removed from this library`, and yet you still use `gets`? Why? It's a [dangerous](https://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used) function and should never be used. This is probably the cause of the crash, because it *will* write out of bounds of the allocated memory *before* you check it. – Some programmer dude Sep 05 '20 at 11:32
  • 2
    Checking the length after reading it into `pProduct->itemName` is wrong. If the input is too long, it will have already overrun the buffer before you test it. Also, an allocation of 30 bytes can only hold strings of length up to 29 characters, since the terminating null character requires a byte but is not counted in the length. – Eric Postpischil Sep 05 '20 at 11:36
  • `if (len > 100)` is a problem. It cannot be true unless prior buffer overflowed - which is undefined behavior. Use `fgets()`. – chux - Reinstate Monica Sep 05 '20 at 14:13

1 Answers1

0

suggestions;

allocate a long buffer, much longer than possibly ever needed. Then obtain the data via a call to fgets()

char buffer[1024];
fgets( buffer, sizof( buffer ), stdin );

-OR-

use the getline() function to read the data

char *buffer = NULL;
size_t byteCount;
getline( &line, &byteCount, stdin );

Note: I left error checking out of the above to make the illustration simple.

user3629249
  • 16,402
  • 1
  • 16
  • 17