I wrote this quick little program to see why the heck something else wasn't working. I thought that, if you mallocated something, it didn't matter if it went out of scope as long as there was something pointing to it. But here, when I try to access **u after mallocing it's direct reference in test(), the program has an access error. So what am I missing in the the way that malloc() works?
Well your use of "malloc" isn't wrong as far as it goes. You may be missing something with regard to "malloc" but we can't know that. You're missing plenty enough with regards to parameters.
The first line of "test" overrides the value you passed to the function. From that line whatever was passed is lost to that function. In other words, "main()::u" has an unknown probably random value--and your dereferencing it.
I'm unsure what all your missing but from the source I'd say a great deal.
It may be that you don't understand the difference between constant and non-constant data.
It may be that you don't understand pass by value.
It may be...
I could go on for several lines.
Take a good look at this source. Then go buy a new book or find at the very least reread whatever tutorials your using.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2006-03-30
C passed by copy, co the char** you pass is a copy of u. When you modify it by taking the return from malloc() yo are uselessly modifying teh independent copy, which immediatly goes out of scope and is lost when the function returns.
You could correct the code thus:
However you are making things unnecessarily complex, you are wasting the opportunity to simply return the pointer-pointer:
char test()
{
ret = malloc(3sizeof(char));
ret[0] = "Babies";
return ret ;
}
int main(void)
{
char** u = test();
printf("%s\n", u[0]);
system("pause");
}
There are still some insidious practices in this tiny piece of code:
1) The memory is allocated but never freed (why is is it dynamically allocated in the first instance?).
2) It is good practice to cast the return value of malloc() (which is otherwise a void*), this will allow the compiler to catch some coding errors that would otherwise be missed.
3) You have assigned a constant literal string to u[0], but u is not const. If you were to attempt to modify u[0], the compiler will let you, but it would probably cause a run-time error.
int main(void)
{
const char* u[3]
test( u );
printf("%s\n", u[0]);
system("pause");
}
Of course in this trivial piece of code, it is not possible to say which approach is most approriate for any real application you might envisage. Personally I would use C++ and the superior new operator over malloc().
Clifford
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Unfortunately none of the books or tutorials I have go quit this in depth about passing pointers.
I understand why your code works, but I'd like to make clear on a few things about parameters, and why -my- code does not work.
First, passing by value is to copy the variable, and therefor your original variable is not affected by anything
happening to the argument in the function, right?
So passing by reference is to pass the address over, so that changes made to the argument are also made to the
orginal variable. I would think this is what I want to do, since I want changes that happen with 'ret' to stay with
'u'.
So I don't understand your statement about 'u' getting overwritten by ret, since I figured I was passing u by reference to ret, therefor making them point to the same place, and so anything I did with ret I was doing with u (like allocating memory). As I said, I understand perfectly why your code works, but please explain the flaw in my logic (or in my syntax) with my own program.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2006-03-30
Remember pointers are variables too.
When you pass a pointer, you pass a copy of it. In this case it is the pointer itself that you want to modify - by malloc() - so you need to pass a pointer to the pointer. A pointer to a char is a char, you pass a char and dereference it once to access the char that it points to.
I omitted to mention that in my first example solution, the associated call in main() must be modified thus:
test(&u); / pass a pointer to u /
You also need to derefernce the assignment:
*ret[0] = "Babies"
Perhaps I should have posted the full solution, but it is a nasty solution in anycase. A C++ reference would be better, or either of the other solutions suggested.
Note also my habit of writing:
char** u ;
rather than your:
char **u ;
It serves to emphasize that u is a variable of type char**. It helps IMO to think of it in this way, as well as being more distinct from the dereference operator that happens to use the same symbol.
Clifford
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Whoops. Someone posted while I was writing that. In response to Clifford, some of the things you complain about (like the lack of freeing, and reason for dynamic allocating) are simply because I wanted the smallest amount of code to convey my problem, and I'm just tryin' to learn about pointers anyway.
Anyways, I see that you're saying that I was passing u by value, and not by reference at all, and that this is remedied with the extra pointer (*ret). The reason I was confused is that, if I malloc() 'u' before sending it into the function the way I've been doing it, and then changing ret, those changes seem to stick with 'u', which I can use afterwards. I'm not really sure why that is, if it's pass by value though.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2006-03-31
"I'm not really sure why that is, if it's pass by value though."
You are passing the pointer by value - that may be confusing, pass by 'copy' is a better way of referring to it -, this 'copy' still points to the same allocated data (becausae it is a copy). The pointer 'refers' to the data that you allocated previously. You can have any number of pointers to a single variable:
char a[] = "Cats" ;
char b = a ;
char c = b ;
c[0] = 'H' ;
printf( "%s, %s, %s\n", a, b, c ) ; / Output: "Hats, Hats, Hats" /
Here b and c are copies of eachother and point to the array a.
Clifford
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I wrote this quick little program to see why the heck something else wasn't working. I thought that, if you mallocated something, it didn't matter if it went out of scope as long as there was something pointing to it. But here, when I try to access **u after mallocing it's direct reference in test(), the program has an access error. So what am I missing in the the way that malloc() works?
include <stdio.h>
include <string.h>
void test(char ret)
{
ret = malloc(3sizeof(char));
ret[0] = "Babies";
}
int main(void)
{
char **u;
test(u);
printf("%s\n", u[0]);
system("pause");
}
I don't like the idea of you passing constant data around as non-constant.
"this 'copy' still points to the same allocated data (becausae it is a copy)."
That confused me and I know pointers.
Soma
Well your use of "malloc" isn't wrong as far as it goes. You may be missing something with regard to "malloc" but we can't know that. You're missing plenty enough with regards to parameters.
The first line of "test" overrides the value you passed to the function. From that line whatever was passed is lost to that function. In other words, "main()::u" has an unknown probably random value--and your dereferencing it.
I'm unsure what all your missing but from the source I'd say a great deal.
It may be that you don't understand the difference between constant and non-constant data.
It may be that you don't understand pass by value.
It may be...
I could go on for several lines.
Take a good look at this source. Then go buy a new book or find at the very least reread whatever tutorials your using.
Soma
include <stdio.h>
include <stdlib.h>
include <string.h>
const unsigned int WORDLISTSIZE = 10;
const char WordList[10][6] = {"Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"};
void AllocateWordList(char *** wordListPointer)
{
if(wordListPointer)
{
wordListPointer = (char )(malloc(WORDLISTSIZE * sizeof(char )));
for(unsigned int index = 0; WORDLISTSIZE > index; ++index)
{
(wordListPointer)[index] = (char )(malloc(strlen(WordList[index]) * sizeof(char)));
strcpy((wordListPointer)[index], WordList[index]);
}
}
}
void FreeWordList(char *** wordListPointer)
{
if(wordListPointer)
{
for(unsigned int index = 0; WORDLISTSIZE > index; ++index)
{
free((wordListPointer)[index]);
}
free(wordListPointer);
}
}
void PrintWordList(char ** wordList)
{
if(wordList)
{
for(unsigned int index = 0; WORDLISTSIZE > index; ++index)
{
printf("%s ", wordList[index]);
}
printf("\n");
}
}
int main()
{
char ** list;
AllocateWordList(&list);
PrintWordList(list);
FreeWordList(&list);
return(0);
}
C passed by copy, co the char** you pass is a copy of u. When you modify it by taking the return from malloc() yo are uselessly modifying teh independent copy, which immediatly goes out of scope and is lost when the function returns.
You could correct the code thus:
void test(char ret)
{
ret = (char)malloc(3sizeof(char));
ret[0] = "Babies";
}
However you are making things unnecessarily complex, you are wasting the opportunity to simply return the pointer-pointer:
char test()
{
ret = malloc(3sizeof(char));
ret[0] = "Babies";
return ret ;
}
int main(void)
{
char** u = test();
printf("%s\n", u[0]);
system("pause");
}
There are still some insidious practices in this tiny piece of code:
1) The memory is allocated but never freed (why is is it dynamically allocated in the first instance?).
2) It is good practice to cast the return value of malloc() (which is otherwise a void*), this will allow the compiler to catch some coding errors that would otherwise be missed.
3) You have assigned a constant literal string to u[0], but u is not const. If you were to attempt to modify u[0], the compiler will let you, but it would probably cause a run-time error.
All these issues can be trivially avoided thus:
void test( char** array )
{
array[0] = "Babies";
}
int main(void)
{
const char* u[3]
test( u );
printf("%s\n", u[0]);
system("pause");
}
Of course in this trivial piece of code, it is not possible to say which approach is most approriate for any real application you might envisage. Personally I would use C++ and the superior new operator over malloc().
Clifford
Unfortunately none of the books or tutorials I have go quit this in depth about passing pointers.
I understand why your code works, but I'd like to make clear on a few things about parameters, and why -my- code does not work.
First, passing by value is to copy the variable, and therefor your original variable is not affected by anything
happening to the argument in the function, right?
So passing by reference is to pass the address over, so that changes made to the argument are also made to the
orginal variable. I would think this is what I want to do, since I want changes that happen with 'ret' to stay with
'u'.
So I don't understand your statement about 'u' getting overwritten by ret, since I figured I was passing u by reference to ret, therefor making them point to the same place, and so anything I did with ret I was doing with u (like allocating memory). As I said, I understand perfectly why your code works, but please explain the flaw in my logic (or in my syntax) with my own program.
Remember pointers are variables too.
When you pass a pointer, you pass a copy of it. In this case it is the pointer itself that you want to modify - by malloc() - so you need to pass a pointer to the pointer. A pointer to a char is a char, you pass a char and dereference it once to access the char that it points to.
I omitted to mention that in my first example solution, the associated call in main() must be modified thus:
test(&u); / pass a pointer to u /
You also need to derefernce the assignment:
*ret[0] = "Babies"
Perhaps I should have posted the full solution, but it is a nasty solution in anycase. A C++ reference would be better, or either of the other solutions suggested.
Note also my habit of writing:
char** u ;
rather than your:
char **u ;
It serves to emphasize that u is a variable of type char**. It helps IMO to think of it in this way, as well as being more distinct from the dereference operator that happens to use the same symbol.
Clifford
Whoops. Someone posted while I was writing that. In response to Clifford, some of the things you complain about (like the lack of freeing, and reason for dynamic allocating) are simply because I wanted the smallest amount of code to convey my problem, and I'm just tryin' to learn about pointers anyway.
Anyways, I see that you're saying that I was passing u by value, and not by reference at all, and that this is remedied with the extra pointer (*ret). The reason I was confused is that, if I malloc() 'u' before sending it into the function the way I've been doing it, and then changing ret, those changes seem to stick with 'u', which I can use afterwards. I'm not really sure why that is, if it's pass by value though.
"I'm not really sure why that is, if it's pass by value though."
You are passing the pointer by value - that may be confusing, pass by 'copy' is a better way of referring to it -, this 'copy' still points to the same allocated data (becausae it is a copy). The pointer 'refers' to the data that you allocated previously. You can have any number of pointers to a single variable:
char a[] = "Cats" ;
char b = a ;
char c = b ;
c[0] = 'H' ;
printf( "%s, %s, %s\n", a, b, c ) ; / Output: "Hats, Hats, Hats" /
Here b and c are copies of eachother and point to the array a.
Clifford
I'm certain I understand now, it's just a matter of letting it resolve in my mind. Thanks for your help.