Reputation: 41
I have a problem with the first line of my table
char **M = malloc(dim->lignes*sizeof(char));
for(i=0;i<dim->lignes;i++)
{
M[i]=malloc(dim->colonnes*sizeof(char));
for(j=0;j<dim->colonnes;j++)
{
M[i][j] = fgetc(F);
printf(" ");
printf("%c",M[i][j]);
}
printf("\n");
fgetc(F);
}
for(i=0;i<dim->lignes;i++)
{
for(j=0;j<dim->colonnes;j++)
{
printf(" ");
printf("%c",M[i][j]);
}
printf("\n");
}
The output :
# # # # # # # # #
# # # # # # # # #
# # #
# # # #
# #
# #
# #
# # #
# # # #
# # # # # # # # #
P Õ h Õ Ç
# # # # # # # # #
# # #
# # # #
# #
# #
# #
# # #
# # # #
# # # # # # # # #
I don't understand why the first print is correct and not the second.
Upvotes: 2
Views: 84
Reputation: 41676
Your code allocates not enough memory for M
. Luckily, you can see the effects immediately in this special case.
The memory layout is:
M: 00 00 00 00 00 00 00 00 00
M[0]: 00 00 00 00 00 00 00 00
I'm assuming a 32 bit machine in the following. Then M
is only 9 bytes large but should be 36. So when you read in line 4, the assignment to M[3]
will be translated to memory[M + 4*3 .. M + 4*3 + 3] = …
. The index expression is larger than the allowed 9, but the C runtime doesn't care about that. Instead it will write to the memory after the allocated M
array, which happens to be M[0]
your first line of characters.
Upvotes: 0
Reputation: 21367
You are running into problems because you allocate space for char
s, which are 1 byte, when you need to allocate space for pointers to char
, which are larger (8 bytes on my system):
char **M = malloc(dim->lignes*sizeof(char));
You can fix this by changing the above line to:
char **M = malloc(dim->lignes*sizeof(char *));
But, there are some common C idioms that help you avoid such mistakes. M
is a pointer to a pointer to char
, so you want to allocate storage for pointers to char
. But *M
is of type (char *)
, so you can write:
char **M = malloc(dim->lignes*sizeof(*M));
You can always use this pattern, which frees you from explicitly specifying the type in the right-hand side of the statement. As an added bonus, if you ever change the type of M
(to (int **)
, for example), then the right hand side is still valid, so this idiom is more robust than the explicit statement of the type.
Further in your code, you have:
M[i]=malloc(dim->colonnes*sizeof(char));
But, in C a char
is guaranteed to be 1 byte, so sizeof(char)
is always 1. That makes the use of the sizeof
operator redundant here. It is considered good practice to dispense with sizeof
in such situations:
M[i]=malloc(dim->colonnes);
This reduces clutter in the code. You may instead consider using the first idiom, which will remain valid even if the type of M
changes:
M[i]=malloc(dim->colonnes*sizeof(*M[i]));
or perhaps:
M[i]=malloc(dim->colonnes*sizeof(**M));
Upvotes: 0
Reputation: 154305
As well stated in this answer, the following is incorrect.
char **M = malloc(dim->lignes*sizeof(char)); // wrong with `sizeof(char)`
Rather than sizeof(char*)
, use sizeof *the_pointer_variable
. This is less like to code wrong, It is easier to review and maintain. No need to change the code used in the malloc()
argument as the type changes.
// OK
char **M = malloc(dim->lignes*sizeof(char*));
// Better
char **M = malloc(dim->lignes * sizeof *M);
// Best
char **M = malloc(sizeof *M * dim->lignes);
The last, using sizeof
first, has the advantage with more complex calculations. The first one below's math is done with at least size_t
math. The 2nd begins it's math with whatever type rows * columns
are. Should that be int * int
, overflow is possible that might not occur with size_t
math.
M = malloc(sizeof *M * rows * columns);
M = malloc(rows * columns * sizeof *M); // Overflow with rows * columns?
Upvotes: 3
Reputation: 34592
char **M = malloc(dim->lignes*sizeof(char));
That should read as
char **M = malloc(dim->lignes*sizeof(char *));
It would have been valid if it was like this, this is hypothetical example,
char *M = malloc(dim->lignes*sizeof(char));
Notice the difference there, with the sizeof
.
For a single pointer, use sizeof
type
For a double pointer, use sizeof
* type and so on.
Upvotes: 5