Search code examples
cstringpointersadditiondynamic-memory-allocation

Function giving desired output and then terminating abnormally


I have written following program:

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

char* reversenew(char*);
char* reverseold(char*);
char* add(char*,char*);
char* standard(char*);

int main()
{
    int i,n;
    char *num1, *num2;
    num1 = malloc(1000*sizeof(char));
    num2 = malloc(1000*sizeof(char));
    printf("Enter the numbers to be added\n");
    gets(num1);
    gets(num2);
    printf("\n%s\n",add(num1,num2));
    return 0;
}

char* reversenew(char* m)
{
    char *k;
    k = malloc(100*sizeof(char));
    strcpy(k,m);
    int i,n = strlen(k);
    for(i = 0;i<n;i++)
    k[i] = m[n-i-1];
    return(k);
}

char* reverseold(char* m)
{
    char temp;
    int i,n = strlen(m);
    for(i=0;i<n/2;i++)
    {
        temp = m[i];
        m[i] = m[n-i-1];
        m[n-i-1] = temp;
    }
    return m;
}

char* add(char* num1,char* num2)
{
    char *n1,*n2;
    int i,digit,carry = 0;
    n1 = reversenew(standard(num1));
    n2 = reverseold(standard(num2));
    int n = (strlen(n1)>strlen(n2))?strlen(n1)+1:strlen(n2)+1;
    while(strlen(n1)!=strlen(n2))
    (strlen(n1)>strlen(n2))?(n2 = strcat(n2,"0")):(n1 = strcat(n1,"0"));
    n1 = strcat(n1,"0");
    n2 = strcat(n2,"0");
    for(i=0;i<n;i++)
    {
        digit = (int)n1[i]+(int)n2[i]+carry-96;
        n1[i] = (char)(48+(digit%10));
        carry = digit/10;
    }
    n1 = reverseold(n1);
    n2 = reverseold(n2);
    if(n1[0] == 48)
    n1++;
    strcpy(n2,standard(n2));
    return(n1);
}

char* standard(char* m)
{
    int i = 0;
    while(i < strlen(m))
    {
        if(m[0] == 48)
        m+=1;
        else
        break;      
    }
    return m;
}

The add function adds two natural numbers in form of a string and returns the result in form of string. This function is giving the desired output and then exits with return value 0 for small inputs and exits with return value 3221226356 for large inputs (for input strings of length 140, say). I took 9 repeated 140 times, to be added to the same number.

Note that the reversenew function reverses a string and stores the result in a new string, keeping the original reusable, while reverseold function reverses the original string.

Also if I edit and enter printf("\n5"); just before return 0; after the previous line, then it is printed in the output window as expected and therefore, I conclude that the add function is working correctly.

Please help me in figuring out the problem.


Solution

  • When I run your program with valgrind and enter the following numbers

    123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
    123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
    

    I get these error messages

    ==5279== Invalid write of size 1
    ==5279==    at 0x483E0AC: strcpy (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==5279==    by 0x10929D: reversenew (add.c:27)
    ==5279==    by 0x1093B0: add (add.c:51)
    ==5279==    by 0x109251: main (add.c:19)
    ==5279==  Address 0x4a5b184 is 0 bytes after a block of size 100 alloc'd
    ==5279==    at 0x483A7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==5279==    by 0x109286: reversenew (add.c:26)
    ==5279==    by 0x1093B0: add (add.c:51)
    ==5279==    by 0x109251: main (add.c:19)
    ==5279== 
    
    valgrind: m_mallocfree.c:305 (get_bszB_as_is): Assertion 'bszB_lo == bszB_hi' failed.
    valgrind: Heap block lo/hi size mismatch: lo = 176, hi = 3761405300628338743.
    This is probably caused by your program erroneously writing past the
    end of a heap block and corrupting heap metadata.  If you fix any
    invalid writes reported by Memcheck, this assertion failure will
    probably go away.  Please try that before reporting this as a bug.
    

    In function reversenew you allocate a block of 100 bytes independently from the string length and write data in the size of the original string to it.

    This is undefined behavior.

    Your add function seems to work correct because this function and the subsequent printf don't care that you wrote past the end of the allocated memory area.

    When function main returns, the system will automatically clean up the resources, e.g. free all memory and close all files. In your case strange things happen at this point because you destroyed some internal data of the dynamic memory allocation. You see the strange return value as a result. It may also result in an access violation or nothing or other strange things as this is undefined.

    Allocate the correct size for the result string in reversenew.