I have reviewed your code and here is what I've found. ## Break up the code into smaller functions Rather than having everything in one long `main` function, it would be easier to read and maintain if each discrete step were its own function. For example there could be separate add and print functions. ## Eliminate unused variables Unused variables are a sign of poor quality code, and you don't want to write poor quality code. In this code, `z` and `digi` are unused. Your compiler is smart enough to tell you about this if you ask it nicely. ## Free memory that you allocate This program leaks memory because you have allocated space using `malloc` but never released with `free`. That's bad practice. ## Add in place One way to make this both neater and probably faster would be to duplicate the larger number and add the shorter one to it. This would allow you to easily implement the following suggestion. ## Separate I/O from program logic Right the printing is done within the logic for addition. It's often better design to separate the two so that the program logic is independent of the I/O with the user. ## Take advantage of shortcuts During addition, if you've already used each of the digits of the shorter number, the program is done adding when the carry bit is clear. ## Fix the bug The code takes care to make sure that `num1_n > num2_n`, but then prints the wrong result if that test fails. Better would be to swap the operands to make sure that the code always knows which is the largest input. ## Use more whitespace to enhance readability of the code Instead of crowding things together like this: num3=(int*)malloc(sizeof(int)*(num1_n+1)); most people find it more easily readable if you use more space: num3 = (int *)malloc(sizeof(int) * (num1_n + 1)); ## Think of the user Rather than required the user to recompile the code to add two different numbers, it would be nice to read them dynamically during runtime. This would be a useful feature, but would require more code and careful "input sanitation" (that is, looking for and rejecting invalid inputs.) ## Omit `return 0` When a C or C++ program reaches the end of `main` the compiler will automatically generate code to return 0, so there is no need to put `return 0;` explicitly at the end of `main`. **Note:** when I make this suggestion, it's almost invariably followed by one of two kinds of comments: "I didn't know that." or "That's bad advice!" My rationale is that it's safe and useful to rely on compiler behavior explicitly supported by the standard. For C, since C99; see ISO/IEC 9899:1999 section 5.1.2.2.3: > [...] a return from the initial call to the `main` function is equivalent to calling the `exit` function with the value returned by the `main` function as its argument; reaching the `}` that terminates the `main` function returns a value of 0. For C++, since the first standard in 1998; see ISO/IEC 14882:1998 section 3.6.1: > If control reaches the end of main without encountering a return statement, the effect is that of executing return 0; All versions of both standards since then (C99 and C++98) have maintained the same idea. We rely on automatically generated member functions in C++, and few people write explicit `return;` statements at the end of a `void` function. Reasons against omitting seem to boil down to ["it looks weird"](https://stackoverflow.com/questions/2581993/what-the-reasons-for-against-returning-0-from-main-in-iso-c/2582015#2582015). If, like me, you're curious about the rationale for the change to the C standard [read this question](https://stackoverflow.com/questions/31394171/what-was-the-rationale-for-making-return-0-at-the-end-of-main-optional). Also note that in the early 1990s this was considered "sloppy practice" because it was undefined behavior (although widely supported) at the time. So I advocate omitting it; others disagree (often vehemently!) In any case, if you encounter code that omits it, you'll know that it's explicitly supported by the standard and you'll know what it means.