The solution using malloc()
has the disadvantage that memory is allocated but the responsibility for freeing that memory is not clear. The caller need not even know the memory is dynamically allocated (why should it?), and fail to free it resulting in a memory leak. Normally the responsibility for freeing an allocation should be clear. It is not a good solution in this case.
A simple (but still imperfect) solution is to statically allocate the string being returned:
const char* calcul( const char* octet, const char* masque )
{
static char reseau[33] = "" ;
...
return reseau;
}
This has a problem however of not being reentrant (an issue in multi-threading or recursive code) and caller still needs to understand restrictions and issues related to use of a static buffer. The pointer returned is the same for all callers, such that the string will be modified if the function is called subsequently. A caller may copy the string, or ensure that it has completed all processing on it before calling the function again. It is probably better that dynamic memory allocation, but still requires the caller to have knowledge of the internal memory management to uses it appropriately.
Another disadvantage of the solution is returning a const
no write access can be performed outside the function, so if that is necessary the caller would have to copy the string to a local buffer. Returning a non-const would be a really bad idea - you would be modifying the "hidden" buffer inside the function.
The more usual and more flexible idiom is for the caller to "own" the buffer and pass it to the function for it to be filled. That way the memory may be an array, or dynamically allocated according to the needs of the caller. In this case you would also pass the length of the array, so that the function can avoid overrunning the caller's buffer:
const char* calcul( const char* octet, const char* masque,
char* reseau, size_t reseau_len )
{
...
for( i = 0;
octet[i] != 0 && masque[i] != 0 && i < reseau_len;
i++)
{
...
}
return reseau;
}
So then the function might be called thus:
char reseau_buf[sizeof(octetB)] ;
printf( "Adresse réseau : %s\n",
calcul( octetB, masqueB,
reseau_buf, sizeof(reseau_buf) ) ) ;
Note that this last version also makes no assumptions about the length of either masque
or octet
- the loop stops at the shorter of all the inputs. If they differ that is a bug at the caller, the function implementation will fail "gracefully" and deterministically and thus be easier to debug.
Aside on interpretation of the assignment
None of the above seems to correctly address the assignment, which you appear to have misunderstood. I would expect a solution to look something like:
#include <stdio.h>
#include <stdint.h>
uint32_t subnet( uint32_t ip, uint32_t mask, char* subnet_str ) ;
int main()
{
uint32_t ip = 0xC0A80001 ; // 192.168.0.1
uint32_t netmask = 0xFFFFFF00 ; // 255.255.255.0
char ipstring[] = "000.000.000.000" ;
printf( "0x%08X : ", subnet(ip, netmask, ipstring) ) ;
printf( "%s\n", ipstring ) ;
}
uint32_t subnet( uint32_t ip, uint32_t mask, char* subnet_str )
{
// Step 1 : apply mask to get subnet
uint32_t network = ...
// Step to: convert network to "xxx.xxx.xxx.xxx" string form
// in subnet_str
...
// Step 3
return network ;
}
With output:
0xC0A80000 : 192.168.1.0
Clearly help with any of that warrants a new question. But is is far simpler that the work you have already put in. Both step 1 and 2 can be implemented each as a single line of code.