Problem with C pointers in 2d char arrays - c

Why does this work:
//split returns (char**)
char *temp2;
temp2=split(array[i],'=')[1];
and this doesn't:
char **temps;
temps[0]=temp2; //crashes
or this:
temps[0]=split(array[i],'=')[1]; //crashes

temps is just a pointer to a char*, but it has no initalized, sensible value! temps[0] is equivalent to *(temps + 0), but you cannot dereference a garbage value -- you first have to make temps points somewhere useful, e.g. by allocating memory for it.
If you want to store some char*s with automatic storage, then declare an array of char pointers instead:
char * temps[20];
temps[0] = /*... etc. ...*/

Split returns a pointer to a pointer to a char. So, what is returned from split(array[i],'=')[1] is a pointer to char which is what you declared on the stack and thus reserved space for it. That is why it works.
The other two don't work because the space pointed to is not allocated. You should use malloc().

If you simply declare a pointer variable:
char **temps;
It's not really pointing to somewhere. Well, it actually is, but that's probably garbage (anywhere in memory). You have to initialize it before using it. Try allocating space for it.

char **temps was never allocated any space. You're dereferencing bad memory with temps[0].

man malloc()
You have to allocate your memory to get space!

char **temps;
temps[0]=temp2; //crashes
The pointer, temps, is uninitialized. Dereferencing it is an undefined operation.

Because temps isn't initialized. It's a random value pointing to a random memory location.

Think of it this way:
char *temp2 = "foo";
char **temps;
temps[0] = temp2; // won't work
temps = &temp2; // ok
temp2 points at a C string. You can point temps at the address of temp2, (&temp2) but you can't dereference temps (that is, temps[0]) unless you first make it point at something valid. From your question it sounds like you want to malloc() an array of char* first.
In the second and third cases, you are dereferencing temps[0] without first making it refer to some valid memory location. As has been pointed out, temps is pointing at a garbage location.
Your first case works because you're dereferencing split(), so it's giving you a char*.

Related

How does malloc know which type the returned pointer is pointing at?

I'm learning pointers and memory allocation with C. I've used the snippet below to manually allocate some bunch of bytes to copy:
char *s = get_string("s: "); // this is included in cs50 library and it returns a char pointer
char *t = malloc(strlen(s) + 1); // +1 for "\0"
...
free(t);
My question is this, why do we declare t as it points to a char value? How does malloc know that the pointer t points at a char value, even if we did not enter any "clue" about using char?
It doesn't, and it doesn't need to. malloc allocates a block of exactly as many bytes as you tell it to, and returns a void* pointer to it. The pointer is then implicitly converted to char* when the assignment is made. See this for more insight.

pointers to arrays in c not working

char (*ptr)[10];
scanf("%s",ptr);//inputing a string
Why is this not working?
According to me this should work because ptr is a pointer to an array of characters.
A pointer to an array is NOT an array, you have nowhere to put your characters.
It's like having a doormat without a house, that doesn't mean you have somewhere to receive your guests.
To have the above working you should
char ptr[10]; // This is where you have space, specifically stack space
char (*this_is_a_pointer_to_array)[10]; // This only holds space to keep an address to an array
this_is_a_pointer_to_array = &ptr;
scanf("%s",ptr);
although you don't really need the pointer to array in the case above.
A pointer to an array only holds as much space as necessary to hold the address to an array, there's no space to store anything else than an address. If you horribly circumvent the typecasting mechanism you might use that space to store some characters instead of an address, but that is against every moral fiber of my body and probably against every typecasting rule as well.
ptr is not a pointer to char instead it is a pointer to an array of 10 chars.

Assigning a Pointer the value of another pointer

I am trying to assign the value of fileOrDir to the value of copyFileOrDir. I want copyFileOrDir to be equal to the value of fileOrDir, not point to the same address. I thought it would be copyFileOrDir = *filrOrDir but I get errors. below is my code:
(fileOrDir gets its value from a command line argument)
char *fileOrDir = (char *)malloc(25*sizeof(char));
char *copyFileOrDir = (char *)malloc(25*sizeof(char));
copyFileOrDir = *fileOrDir;
Pointers point to a block of memory. If you set one pointer equal to another, you end up pointing to the same block of memory. If you actually assigned two different blocks, you should never want to then set one pointer to the other - you will be unable to free the memory.
Most likely you intend to do a memcpy which allows you to copy the contents of one memory block to another:
memcpy(void* destination, const void* source, size_t numberofbytes);
I am trying to assign the value of fileOrDir to the value of
copyFileOrDir.
You don't assign the value of a variable to the value of another variable. That's wrong to say. You assign a value to a variable. Think of a variable as a memory location. Also don't cast the result of malloc. That's not useful and can lead to bugs. Now let's come to your code snippet.
// don't cast the result of malloc
char *fileOrDir = malloc(25 * sizeof(char));
char *copyFileOrDir = malloc(25 * sizeof(char));
The following statement
copyFileOrDir = *fileOrDir;
tries to assign the object pointed to by fileOrDir, which is of type char, to copyFileOrDir, which is of type char * - a different type. This is an error. Also, by assigning copyFileOrDir, you lose the handle on the memory allocated by malloc causing memory leak. If you want to copy the buffer pointed to by fileOrDir to the buffer pointed to by copyFileOrDir, you should use memcpy.
memcpy(copyFileOrDir, fileOrDir, 25);
I think you're confused about pointers and values. You said you want the "value of copyFileOrDir to be equal to the value of fileOrDir." But the value of fileOrDir is just a pointer to a block of dynamically allocated memory that happens to be 25 bytes (assuming sizeof(char) is one byte) in size.
What you really want is for copyFileOrDir to point to a block of memory that is an exact copy of the memory pointed to by the value of fileOrDir. You can do this with memcpy.
char *copyFileOrDir = malloc(25*sizeof(char));
memcpy(copyFileOrDir, fileOrDir, 25*sizeof(char));
Also, I should point out that copyFileOrDir = *fileOrDir; makes no sense. In that case you are dereferencing fileOrDir (i.e. getting the value at the address pointed to by fileOrDir, which is a char) and assigning it to copyOfFileOrDir which is a char *. In other words, you are assigning a char to a char *.

free up on malloc fails

I have some thing like this
char *temp, xyz;
temp = (char *)malloc(sizeof(somestring));
xyz = (char *) malloc(sizeof(temp));
xyz= strrchar(temp, "_"); // temp does not contain "_", but need to check for error validation
Now If I try to do
free(temp);
its crashing;
any idea, I am a beginer.
The first problem is that xyz is not being declared as a char *, only a single char.
Given the following variable declaration:
char *temp, xyz;
temp is a pointer to a char.
xyz is only a char.
The * doesn't apply to both variables. To make both variables pointers to char, use:
char *temp, *xyz;
Next: you're confusing the usage of sizeof with strlen. sizeof gives you the size occupied by a type or a variable of that type. So if temp is a char *, then sizeof(temp) will be the size of a pointer, not the length of a C string. To get C string lengths - e.g. to get the buffer size that you'll need to copy a given C string - use strlen.
Finally, unless you've omitted some significant code there's another problem: simply using malloc doesn't do anything with the newly allocated memory, so after:
temp = (char *)malloc(sizeof(somestring));
temp points to an uninitialized bit of memory (which is, as mentioned, probably smaller than you think it is due to using sizeof rather than strlen). Then you go on to use temp as if it's a valid C string, with strchr. This will likely access memory that doesn't belong to you, which invokes undefined behavior.
I figured it out, correct me if I am wrong,
xyz is just pointing to the location where it has the "_" in the string temp. As soon as I free up the temp, that location got freed up. but xyz is still pointing to that location, which is already freed. That is the reason I had crash on freeing xyz.

Get address of a multidimensional static array

How can I get the address of a multidimensional static array?
For example, this is my array
char array[2][10] = {"word1", "word2"};
Is it possible to get the address to make me reference this array using a pointer like this?
char** pointer;
I tried &array or directly pointer = (char**)array; but it crashes at startup.
char **pointer means that a pointer is pointing to a pointer.
So *pointer is expected to be a pointer (e.g. 4-byte value which can be interpreted as an address).
This is not the case with your array: it is a contiguous area in memory (20 bytes).
So when you try to convert the array to char ** your application crashes.
It's not possible to do this conversion, char ** must point at a pointer.
"array" is the address of the array in memory but it is not a char**. While you can cast it, the application will crash if you try
printf("%s", pointer[1]);
because in your case is probably the same as
printf("%s", (char *)(0x00000031));
since pointer[1] means "the second 4 byte pointer (assuming x86) starting from 'array'".
pointer[0] MAY not crash but won't show "word1" either for the same reason.
You probably want (this is hard to remeber so i had to check online, hope it is correct):
char (*pointer)[10] = array;
Which is a pointer to an array of 10 chars. And if you use pointer[1] it now means "the second 10 chars block starting from 'array'".

Resources