I've been staring at this problem for a while and I can't seem to find an obvious solution nor the vocabulary to describe the specific issue. I'll try my best:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
char** findWords(char** words, int wordsSize, int* returnSize) {
*returnSize = 15; //<- wordsSize and returnSize have the same memory address????
printf("wordsSize is %d\n", wordsSize);
for(int i=0; i<wordsSize; i++)
{
printf("i: %d first word: %s, len: %d\n", i, words[i], strlen(words[i]));
}
}
int main(void){
char **test; // this should be const char but func decl is predefined
test[0] = "Hello";
test[1] = "Alaska";
test[2] = "Dad";
test[3] = "Peace";
int *foo;
findWords(test, 4, foo);
printf("%d", *foo);
}
When findWords() gets called, I see that &wordsSize and *returnSize are the same (i.e. they have the same memory address)
[New Thread 3492.0x9d0]
Breakpoint 1, findWords (words=0x7efde000, wordsSize=4, returnSize=0x28ff24) at keyboardrow.c:15
15 printf("wordsSize is %d\n", wordsSize);
(gdb) print &wordsSize
$1 = (int *) 0x28ff24
(gdb) print returnSize
$2 = (int *) 0x28ff24
(gdb)
Am I missing something obvious? It seems to me that &wordsSize and returnSize should have different memory addresses since they are two separate variables.
char **test; // this should be const char but func decl is predefined
test[0] = "Hello";
test[1] = "Alaska";
test[2] = "Dad";
test[3] = "Peace";
You can't do what you are doing above. test doesn't point to any "meaningful" place.
The problem is
test[0] = "Hello";
test[1] = "Alaska";
test[2] = "Dad";
test[3] = "Peace";
all of these invoke undefined behavior, as test, on it's own does not point to a valid memory.
Before you can dereference test to obtain test[n], you need to make sure that test is pointed to a valid memory which is having enough size to make the test[n] access a valid one.
Instead of the above snippet, you can simple write
char * test[] = { "Hello", "Alaska", "Dad", "Peace" };
and get done with it.
Since you are invoking undefined behavior by calling a pointer that doesn't point to anywhere, various variables/ pointers may point to same memory address, just like in situations where different variables may contain the same garbage value!
Related
Okay so as you can see I have a problem. I am trying to create an array of string in C with a function called tab_string. If you try to run the following code you will see that I have a segfault with the test number two and I don't know why because the first test work. Thanks in advance
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NB_STRING 2
void create_tab_string(char chaine[], char*** p_tab_string) {
char test[] = "Hey";
char test2[] = "blabla";
// Allocation
*p_tab_string = (char **)(malloc(NB_STRING*sizeof(char*)));
// Test
*p_tab_string[0] = test;
printf("%s \n", *p_tab_string[0]);
// Test 2 ERROR ?????
*p_tab_string[1] = test2;
printf("I have the second string \n");
printf("%s \n", *p_tab_string[1]);
}
int main() {
int i;
char string_test[] = "I am a test";
char **tab_string;
create_tab_string(string_test, &tab_string);
for(i = 0; i < NB_STRING; i++)
printf("%s \n", tab_string[i]);
return 0;
}
You have a problem of operator precedence.
You need to use:
(*p_tab_string)[1]
and not *p_tab_string[1].
Also, as written in the comments your test strings are local into function, not available outside the function scope. You need to either duplicate them or use pointers.
Your function should be
void create_tab_string(char chaine[], char*** p_tab_string) {
char *test = "Hey";
char *test2= "blabla";
// Allocation
*p_tab_string = malloc(NB_STRING*sizeof(char*));
// Test
(*p_tab_string)[0] = test;
printf("%s \n", (*p_tab_string)[0]);
(*p_tab_string)[1] = test2;
printf("I have the second string \n");
printf("%s \n", (*p_tab_string)[1]);
}
First of all address of your test c-strings (arrays) are local to function and not accessible outside.
As you can see I changed them to simple pointers to string literals, so the strings literals are accessible outside the function.
Second thing are the way you are dereferencing your pointers.
Using *p_tab_string[1] you are dereferencing the second item of p_tab_string that does not exists.
Using (*p_tab_string)[1] you can dereference the second item of thing pointed by *p_tab_string, that is tab_string declare into main
I have a function to update an unsigned char* and cannot find where my bug is. I'm not sure if I need to allocate memory, or if I am pointing to the wrong memory space somewhere. I tried to follow a similar structure as posted here, but have not had success with an unsigned char.
My code so far:
#include <stdio.h>
void changeArray(unsigned char **arr)
{
unsigned char ptr[3] = {100, 101, 102};
*arr = ptr;
printf("%d\n", **(arr+0)); // This prints out the correct value of 100
}
int main(int argc, const char* argv[])
{
int i = 0;
unsigned char *blah;
unsigned char ptr2[3] = {103, 104, 105};
blah = ptr2;
printf("Blah is: \n");
for (i = 0; i < 3; i++) {
printf("%d,",*(blah+i)); //This prints out 103,104,105
}
changeArray(&blah);
printf("Blah is now: \n");
for (i = 0; i < 3; i++) {
printf("%d,", *(blah +i)); //This prints out 0,0,0
}
return 0;
}
Any help in determining how to properly access the values set in the changeArray() function would be greatly appreciated.
With this *arr = ptr; you are storing a pointer to a variable with automatic storage duration. The behaviour undefined.
You can dynamically allocate and return a pointer that way:
void changeArray(unsigned char **arr)
{
unsigned char ptr[3] = {100, 101, 102};
unsigned char *p = malloc(sizeof ptr);
memcpy(p, ptr, sizeof ptr);
*arr = p;
printf("%d\n", **(arr+0)); // This prints out the correct value of 100
}
You should also do error checking if malloc failed and remember to free the allocated memory after use in main.
The problem here is, ptr is local to changeArray() function. So once the function finishes execution, there is no existance of ptr. Hence, once you assign ptr to *arr
*arr = ptr;
and changeArray() execution gets over, accessing blah in main() now will invoke undefined behaviour.
FWIW, you don't need to pass the address of blah, you don't need a pointer-to-pointer at all. blah is already a pointer, which you can pass to changeArray() to alter the contents of the memory area it points to. You can do something like
void changeArray(unsigned char *arr)
{
for (int i = 0; i < 3; i ++)
arr[i] = 100+i;
}
and call it like
changeArray(blah);
I'm writing a function that reverses a cstring not in place but returns the reversed cstring. What exactly should the return type be?
#include <stdio.h>
#include <string.h>
const char* reverStr(const char *str)
{
char revStr[strlen(str)];
int i;
for(i = strlen(str)-1; i >= 0; i--)
revStr[strlen(str)-1-i] = str[i];
printf("returned value should be %s\n", revStr);
return revStr;
}
int main()
{
char aStr[] = "hello";
char aStr2[] = "goodbye";
printf("%s %s", aStr, aStr2);
char* tmp = reverStr(aStr);//tmp now has garbage
printf("\n%s", tmp);
printf(" %s", aStr);
return 0;
}
Gives
warning: function returns address of local variable [enabled by default]|
warning: initialization discards 'const' qualifier from pointer target type [enabled by default]|
I tried changing char* tmp to char tmp[] but it wouldn't compile. It confuses me when I should use an array and when I should use a pointer.
revStr is an array and ceases to exist after reverStr function exits. For more please read:
Where is the memory allocated when I create this array? (C)
const char* reverStr(const char *str)
{
char revStr[strlen(str)];
return revStr; /* Problem - revStr is a local variable trying to access this address from another function will be erroneous*/
}
const char* reverStr(const char *str)
{
const char * revStr = str;
return revStr; //ok
}
A modifiable l-value cannot have an array type. An l-value is an expression which can come on the left side of an assignment. You use an array when you want to declare lots of variables of the same type and you can index it easily since its layout will be in a sense contiguous.
You use pointers when you want to keep changing the values of the address where you variable points to.
You can do this:
char * p = "test";
p = "new";
But you cannot do this:
char p[] = "test";
char *p1 ="test1";
p = p1; //error
Because their (arrays and pointers) types are not the same and the array p is a non-modifiable l-value.
Here is your fixed code. I tried to make less modifications.
char revStr[strlen(str)]; allocates a local variable(an array) and when you are out of the scope of the reverStr function, its memory is released, which will lead any further usage of its pointer to be UB(segfault in most cases).
A correct way is to allocate the string on the heap and return its pointer like this
char* x = (char*)malloc(strlen(str));
...
return x;
This requires user to be responsible to free the memory. Or you could pass another parameter to your function for the result string.
I think you should use malloc to allocate a new string.
const char* reverStr(const char *str)
{
char *revStr;//using pointer
int i;
revStr = (char*)malloc(strlen(str));//dynamic allocation
for(i = strlen(str)-1; i >= 0; i--)
revStr[strlen(str)-1-i] = str[i];
printf("returned value should be %s\n", revStr);
return revStr;
}
An array is a pointer point to the head of continuous memory.
for example:
int a[] = {1,2,3};
The address in memory maybe:
--1000
|1|
--1004
|2|
--1008
|3|
--1012
1000, 1004, and 1012 are the value of address in memory.
Thus, the value of array a should be 1000.
printf("%d",a);// Yes, you can do it and you may get the value of 1000.
Also, you can use the following code.
int a[] = {1,2,3};
int *b;
b= a;
printf("%d",b[1]);// you will get "2".
You can consider that pointer is a set and array is in the set.
Therefore, you can NOT do this;
int a[] = {1,2,3};
int c = 0;
int *b = &c;
a = b;//error
I read tons of tutos and snippets, but I still don't understand why I get a segfault with this:
int fun(char **p) {
int i;
*p = malloc(2);
*p[0]=10;
*p[1]=20; // segfault NULL pointer
printf("fun()/n");
for (i=0; i<2; i++)
printf("%d ",*p[i]);
}
int main(int argc, const char *argv[])
{
char* buffer;
int i;
fun(&buffer);
printf("main()\n");
for (i=0; i<2; i++)
printf("%d ",buffer[i]);
return 0;
}
In gdb, it gives:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000000
0x0000000100000dea in fun (p=0x7fff5fbffab0) at test.c:10
10 *p[1]=20;
(gdb) p *p[0]
$1 = 10 '\n'
(gdb) p *p[1]
Cannot access memory at address 0x0
(gdb)
I have seen a lot of similar snippets, but there is surely something I am deeply misunderstanding.
You mean (*p)[1]. What you said is *(p[1]).
try returning the address of the same data type of the variable at the LHS.
malloc() by default returns a void value.
p = (char) malloc(2);
this way compiler knows how many bytes it has to move the pointer to fetch new variable.
I have a small piece of code. I compiled it with -lmcheck as I am trying to debug a code where I have the same similar error.
I get this error when I run this code:
memory clobbered before allocated block
Can someone explain the reason why free(ptr) will throw me this error?
How else can I free the pointer?
Thanks.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define LEN 5
int main(int argc, char *argv[]){
char *ptr = NULL;
ptr = (char *) malloc(LEN+1);// +1 for string
strcpy(ptr, "hello");
int i = 0;
for(i = 0; i<LEN; i++)
{
printf("ptr[%d] = %c\n", i, ptr[i]);
ptr++;
}
free(ptr);
return 0;
}
You are incrementing ptr, therefore changing the address that it points to. You can't do that.
In your case, have a separate pointer, let's say char * p = ptr and do your operations with p leaving ptr intact so you can free(ptr) later.
EDIT Taking a second look at your code, I found that you are doing ptr++ when you shouldn't. You are accessing the characters in the array like ptr[i], if you mess with the ptr pointer, you are changing the base address and accessing the characters with ptr[i] can lead (and will lead) to unexpected results.
If you simply remove that line (ptr++) your code will magically work.
If you want to explore the pointer concept and try another solution, your code could look something like this:
int main(int argc, char *argv[]){
char *ptr = NULL;
char * p;
ptr = (char *) malloc(LEN+1);// +1 for string (please check for NULL)
p = ptr;
strcpy(ptr, "hello");
int i = 0;
while (*p) // note how I changed it to a while loop, C strings are NULL terminated, so this will break once we get to the end of the string. What we gain is that this will work for ANY string size.
{
printf("ptr[%d] = %c\n", i++, *p); // here i dereference the pointer, accessing its individual char
p++;
}
free(ptr);
return 0;
}
Because ptr no longer points to the base of the memory you allocated.
Also, after you increment ptr, the expression ptr[i] does not return what you might expect; and that is why the output starts with "hlo".
Find the answer in comments.
When you allocate some memory, typically, the memory management framework keep tracks of it by adding some more info (you can say Header and Footer) to the allocated memory area. When you free this memory, the same info is matched so as to detect any unwanted/invalid memory access.
int main(int argc, char *argv[]){
char *ptr = NULL;
char* temp = NULL; // Have a temp pointer.
ptr = (char *) malloc(LEN+1);// +1 for string
strcpy(ptr, "hello");
temp = ptr; // manipulate temp pointer instead of ptr itself
int i = 0;
for(i = 0; i<LEN; i++)
{
printf("ptr[%d] = %c\n", i, temp[i]);
temp++; // Why you are incrementing this? Just to print, there is no need of this.
}
free(ptr);
return 0;
}