A C-declaration of functions
In C, function declarations do not work like in other languages: the C compiler itself does not search back and forth in the file to find the function declaration from the place you call it, and it does not scan the file several times to find out the relationship: the compiler only scans forward in the file exactly once, from top to bottom. Connecting function calls to function declarations is part of the linker job and only runs after the file has been compiled before the original build instructions.
This means that as the compiler looks ahead the file, the first time the compiler encounters a function name, there should be one of two things: it either sees the function declaration itself, in which case the compiler knows exactly what the function is and what it takes types as arguments, and what types it returns - or it is a function call, and the compiler must guess how the function will be declared.
(There is a third option where the name is used in the function prototype, but this time we will ignore it, because if you see this problem in the first place, you probably are not using prototypes.)
History lesson
In the earliest days of C, the fact that the compiler had to guess the types was not really a problem: all types were more or less the same - almost everything was either an int or a pointer, and they were the same size. (In fact, in B, the language that preceded C, there were no types at all, everything was just an int or a pointer, and its type was determined solely by how you used it!) Thus, the compiler could safely assume the behavior of any function, based only on the number of parameters passed: if you passed two parameters, the compiler would move two things to the call stack, and presumably the caller would have two arguments declared, and that would all align. If you passed only one parameter, but the function expected two, this will still work, and the second argument will just be ignored / garbage. If you pass three parameters and the function expected by two, it will also sort the work, and the third parameter will be ignored and replaced with local variables of the function. (Some old C code still expects these rules for inappropriate arguments to work as well.)
But having a compiler allows you to pass something on to something; this is not a very good way to program a programming language. It worked well in the early days because the early C programmers were mostly wizards, and they knew that they didn't pass the wrong type to functions, and even if they were really wrong, there were always tools like lint that could double check deeper your C code and a warning about such things.
Go quickly to today, and we're not all in the same boat. C has grown, and there are many programmers who are not wizards, and to accommodate them (and to accommodate everyone who regularly used lint ) in any case, the compilers took over many of the capabilities that were previously part of lint - especially part, where they check your code to ensure it's safe type. Early C compilers would let you write int foo = "hello"; , and it just blithely assigns a pointer to an integer, and it's up to you not to do anything stupid. Modern C compilers complain out loud when you're wrong, which is good.
Type Conflicts
So, what is all this connected with a mysterious conflict error in the function declaration line? As I said above, C compilers should either know or assume that the name means that the first time they see this name when scanning forward through the file: they can know what this means if it is the declaration of the function itself ( or the "prototype" function "is more about this briefly), but if it is just a function call, they should guess. And, unfortunately, the assumption is often erroneous.
When the compiler saw your call to do_something() , he looked at how it was called, and he concluded that do_something() would eventually be declared as follows:
int do_something(char arg1[], char arg2[]) { ... }
Why did he do this? Because, as you called it! (Some C compilers may conclude that it was int do_something(int arg1, int arg2) or just int do_something(...) , both of which are still far from what you want, but the important thing is that no matter as the compiler guesses types, he guesses about them differently what your actual function uses.)
Later, when the compiler scans ahead in the file, it sees your actual char *do_something(char *, char *) declaration. The declaration of this function is not even close to the declaration that the compiler suggested, which means that the line in which the compiler compiled the call was compiled incorrectly, and the program simply does not work. Therefore, it correctly displays an error message indicating that your code will not work as it is written.
You might be wondering: "Why am I assuming I am returning an int ?" Well, he assumes this type, because there is no information to the contrary: printf() can accept any types in its variable arguments, so without a better answer, int will guess as well as any other. (Many early C compilers always assumed an int for every undefined type, and suggested that you had in mind ... for arguments for each function declared, f() is not void - which is why many modern code standards recommend always putting void in for arguments, if they really shouldn't be.)
Correction
There are two common errors for function declaration errors.
The first solution, which is proposed by many other answers here, is to place the prototype in the source code above the place where the function is first called. The prototype looks just like a function declaration, but has a semicolon where the body should be:
char *do_something(char *dest, const char *src);
Having set the prototype first, the compiler will then find out what this function will look like, therefore it does not need to be guessed. By convention, programmers often place prototypes at the top of the file, simply under the #include statements, to ensure that they are always defined before their potential use.
Another solution that also appears in some kind of real code is to simply reorder your functions so that the function declarations are always before what they call! You can move the entire function char *do_something(char *dest, const char *src) { ... } above the first call to it, and then the compiler knows exactly what the function looks like, and there was no need to guess.
In practice, most people use function prototypes because you can also use function prototypes and move them to header files ( .h ) so that code in other .c files can call these functions. But any solution works, and many codebases use both.
C99 and C11
It is useful to note that the rules are slightly different in the newer versions of the C standard. In earlier versions (C89 and K & R), the compiler really guessed the types when the function was called (and the K & R compilers often didn’t even warn you if they were wrong ) C99 and C11 require that the function declaration / prototype must precede the first call, and this is an error if it is not. But many modern C compilers - mainly for backward compatibility with earlier code - will only warn about a missing prototype and not consider it a mistake.