cstringfgetsstrncpy

Implementing a custom input function


I tried 2 different approaches to build a function that accepts string input from user and stores it in a variable.

Implementation A

char* input(size_t size)
{
    char buffer[size];

    char* str = (char*)malloc(sizeof(char) * sizeof(buffer));

    if (fgets(buffer, size, stdin) != NULL)
    {
        buffer[strcspn(buffer, "\n")] = '\0';

        printf("Buffer says: %s\n", buffer);

        strncpy(str, buffer, sizeof(buffer));

        str[sizeof(buffer) - 1] = '\0';
        
        printf("str inside function says: %s\n", str);

        return str;
    }  

    return NULL;
}

Implementation B

int input2(char* str, size_t size)
{
    char buffer[size];
    
    str = (char*)malloc(sizeof(char) * sizeof(buffer));

    if (fgets(buffer, size, stdin) != NULL)
    {
        buffer[strcspn(buffer, "\n")] = '\0';

        printf("Buffer says: %s\n", buffer);

        strncpy(str, buffer, sizeof(buffer));

        str[sizeof(buffer) - 1] = '\0';
        
        printf("str inside function says: %s\n", str);

        return 0;
    }  

    return -1;
}

main.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libs/custom/myio.h"

int main(int argc, char const *argv[])
{
    char *ip1;
    
    ip1 = input(1000);
    printf("ip1 inside main says %s\n", ip1);
    free(ip1);

    char* ip2;

    input2(ip2, 1000);
    printf("ip2 inside main says %s\n", ip2);
    free(p2);

    return 0;
}

When running the program:

Hi                             # user input
Buffer says: Hi
str inside function says: Hi
ip1 inside main says Hi
Hi                             # user input
Buffer says: Hi
str inside function says: Hi
ip2 inside main says (null)

A works perfectly but B doesn't. A is not the approach that I want to use, I prefer to use B instead.

When I tried debugging with valgrind along with gdb, it seems that it is detecting errors in the printf function (??).

==177193== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
==177193== 
==177193== 1 errors in context 1 of 2:
==177193== Conditional jump or move depends on uninitialised value(s)
==177193==    at 0x48D71C2: __vfprintf_internal (vfprintf-internal.c:1688)
==177193==    by 0x48C1EBE: printf (printf.c:33)
==177193==    by 0x109276: main (main.c:19)
==177193==  Uninitialised value was created by a stack allocation
==177193==    at 0x109209: main (main.c:7)
==177193== 
==177193== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

I have done a lot of research but I am still getting no where on why B is not working.


Solution

  • The problem in the function input2 ("Implementation B") is that the line

    str = (char*)malloc(sizeof(char) * sizeof(buffer));
    

    will only modify the pointer variable str in the function input2, which contains a copy of the value of the variable ip2 in the function main. It will not set the value of the original variable ip2 in the function main.

    If you want the variable ip2 to be affected by this line of code, then, instead of passing the value of the variable ip2 to the function input2, you should instead pass a pointer to this variable, by changing the parameters of the function to the following:

    int input2( char** str, size_t size )
    

    and by changing the line

    str = (char*)malloc(sizeof(char) * sizeof(buffer));
    

    to:

    *str = (char*)malloc(sizeof(char) * sizeof(buffer));
    

    Now, when calling the function input2 in main, instead of passing the value of ip2, you should instead pass the address of that variable, like this:

    input2( &ip2, 1000 );
    

    Now, this variable should also be affected by the changes in the function input2.

    Also, it is worth noting that in C (in contrast to C++), it is not necessary to cast the result of malloc. See this question for further information: Do I cast the result of malloc?