As has been noted, there are two schools of thought on this.
1) Declare everything at the top of functions because the year is 1987.
2) Declare closest to first use and in the smallest scope possible.
My answer to this is DO BOTH! Let me explain:
For long functions, 1) makes refactoring very hard. If you work in a codebase where the developers are against the idea of subroutines, then you'll have 50 variable declarations at the start of the function and some of them might just be an "i" for a for-loop that's at the very bottom of the function.
I therefore developed declaration-at-the-top-PTSD from this and tried to do option 2) religiously.
I came back around to option one because of one thing: short functions. If your functions are short enough, then you will have few local variables and since the function is short, if you put them at the top of the function, they will still be close to the first use.
Also, the anti-pattern of "declare and set to NULL" when you want to declare at the top but you haven't made some calculations necessary for initialization is resolved because the things you need to initialize will likely be received as arguments.
So now my thinking is that you should declare at the top of functions and as close as possible to first use. So BOTH! And the way to do that is with well divided subroutines.
But if you're working on a long function, then put things closest to first use because that way it will be easier to extract methods.
My recipe is this. For all local variables, take the variable and move it's declaration to the bottom, compile, then move the declaration to just before the compilation error. That's the first use. Do this for all local variables.
int foo = 0;
<code that uses foo>
int bar = 1;
<code that uses bar>
<code that uses foo>
Now, define a scope block that starts before the declaration and move the end until the program compiles
{
int foo = 0;
<code that uses foo>
}
int bar = 1;
<code that uses bar>
>>> First compilation error here
<code that uses foo>
This doesn't compile because there is some more code that uses foo. We can notice that the compiler was able to go through the code that uses bar because it doesn't use foo. At this point, there are two choices. The mechanical one is to just move the "}" downwards until it compiles, and the other choice is to inspect the code and determine if the order can be changed to:
{
int foo = 0;
<code that uses foo>
}
<code that uses foo>
int bar = 1;
<code that uses bar>
If the order can be switched, that's probably what you want because it shortens the lifespan of temporary values.
Another thing to note, does the value of foo need to be preserved between the blocks of code that use it, or could it just be a different foo in both. For example
int i;
for(i = 0; i < 8; ++i){
...
}
<some stuff>
for(i = 3; i < 32; ++i){
...
}
These situations need more than my procedure. The developer will have to analyse the code to determine what to do.
But the first step is finding the first use. You can do it visually but sometimes, it's just easier to delete the declaration, try to compile and just put it back above the first use. If that first use is inside an if statement, put it there and check if it compiles. The compiler will then identify other uses. Try to make a scope block that encompasses both uses.
After this mechanical part is done, then it becomes easier to analyse where the data is. If a variable is used in a big scope block, analyse the situation and see if you're just using the same variable for two different things (like an "i" that gets used for two for loops). If the uses are unrelated, create new variables for each of these unrelated uses.