void pointer to string pointer - c
The compareStrings is going to compare two strings. The code below works fine when the void pointer is cast to char pointer.
int compareStrings(void *value1, void *value2) {
const char *str1, *str2;
str1 = (char *)value1;
str2 = (char *)value2;
return strcmp(str1, str2);
}
However, when I cast the type to pointer to pointer to a char, the code dumps segmentation fault error which I think, reasonably, it should not.
int compareStrings(void *value1, void *value2) {
const char **str1, **str2;
str1 = (char **)value1;
str2 = (char **)value2;
return strcmp(*str1, *str2);
}
Can anyone explain the problem with the second function?
UPDATE:
The complete code is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int compare(void *value1, void *value2);
int binarySearch(void **array, int size, void *value,
int(*compareFunc)(void *, void *));
int compareStrings(void *value1, void *value2);
int binarySearch(void **array, int size, void *value,
int(*compareFunc)(void *, void *)) {
int low, mid, high, compareResult;
low = 0;
high = size;
while (low < high) {
mid = low + ((high - low) / 2);
compareResult = (*compareFunc)(array[mid], value);
if (compareResult < 0) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
}
int compareStrings(void *value1, void *value2) {
const char *str1, *str2;
str1 = (char *)value1;
str2 = (char *)value2;
return strcmp(str1, str2);
}
int main() {
int nElements, maxStringLen, index;
char **stringArray;
char *sToFind;
nElements = 10;
maxStringLen = 100;
sToFind = NULL;
stringArray = malloc(sizeof(char *) * nElements);
for (int i = 0; i < nElements; i++) {
stringArray[i] = malloc(sizeof(char) * maxStringLen);
sprintf(stringArray[i], "sample%d", i+1);
}
sToFind = "sample3";
index = binarySearch((void **)stringArray, nElements, sToFind, compareStrings);
if (index >= nElements) {
printf ("ERROR: value %s not found at index %d\n", sToFind, index);
}else{
printf("item found at index %d!\n", index);
}
for(int i = 0; i < nElements; i++) {
free(stringArray[i]);
}
free(stringArray);
return 0;
}
when I cast the type to pointer to pointer to a char, the code dumps
segmentation fault error which I think, reasonably, it should not.
When you cast the pointer to pointer that operation does not affect the casted pointer. It still points to same memory.
This is demonstrated by printout 3.
1. Original string addresses:
Address of str1= 0x55bc799fea65
Address of str2= 0x55bc799fea6a
3. The addresses after casting `(char **)` do not change:
Address of (char **)value1= 0x55bc799fea65
Address of (char **)value2= 0x55bc799fea6a
Casting is not & or * operation!
When you do dereferencing by * that operation dereferences the value of the original pointer.
The result is not what you want:
4.
Address of *(char **)value1= 0x343332 00 34 33 32 31
Address of *(char **)value2= 0x31 00 35 34 33 32
These are not the addresses as you expected but the values of the strings.
Those values are not the valid addresses!
When you try to use them as the string addresses you will get segmentation fault in the strcmp function.
Take a look at the demo program:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void print_addresses(char *nr, char *d1, void *a1, char *d2, void *a2)
{
printf("%s.\nAddress of %s= %p\nAddress of %s= %p\n\n",nr, d1, a1, d2, a2);
}
int compareStrings1 (void *value1, void *value2)
{
char *str1, *str2;
str1 = (char *) value1;
str2 = (char *) value2;
//2.
print_addresses("2", "str1", str1, "str2", str2);
return strcmp(str1, str2);
}
int compareStrings2(void *value1, void *value2) {
char **str1, **str2;
char **s1, **s2;
str1 = (char **)value1; // warning: assignment from incompatible pointer type
str2 = (char **)value2; // warning: assignment from incompatible pointer type
//3. Addresses after casting `(char **)` do not change:
print_addresses( "3", " (char **)value1", str1, " (char **)value2", str2); // str1,str2 are still pointing to the original strings!
//---------------------------------------------------------------------------------------------
print_addresses( "4", "*(char **)value1", *str1, "*(char **)value2", *str2); // '*' this dereferences the address to the value of the first character
printf("(*str1)= %c\n", *str1); //'*' this dereferences the address to the value of the first character
printf("(*str2)= %c\n\n", *str2); //'*' this dereferences the address to the value of the first character
// Now:
s1 = (char **) &value1; // '&'' gives us pointer to pointer
s2 = (char **) &value2; // '&'' gives us pointer to pointer
//5.
print_addresses( "5", " (char **) & value1" , s1, " (char **) & value2", s2); // pointer to pointer address
//6.
print_addresses( "6", "*(char **) & value1", *s1, "*(char **) & value2", *s2); // dereferencing pointer to pointer
return strcmp(*s1, *s2); // OK!
}
int main()
{
char *str1 = "1234";
char *str2 = "2345"; // 5 bytes
//1. Original string addresses:
print_addresses("1", "str1", str1, "str2", str2);
int res1 = compareStrings1(str1, str2);
int res2 = compareStrings2(str1, str2);
return 0;
}
Output:
1.
Address of str1= 0x55bc799fea65
Address of str2= 0x55bc799fea6a
2.
Address of str1= 0x55bc799fea65
Address of str2= 0x55bc799fea6a
3.
Address of (char **)value1= 0x55bc799fea65
Address of (char **)value2= 0x55bc799fea6a
4.
Address of *(char **)value1= 0x3433320034333231
Address of *(char **)value2= 0x310035343332
(*str1)= 1
(*str2)= 2
5.
Address of (char **) & value1= 0x7ffd061f56b8
Address of (char **) & value2= 0x7ffd061f56b0
6.
Address of *(char **) & value1= 0x55bc799fea65
Address of *(char **) & value2= 0x55bc799fea6a
I hope it helps.
The problem is that your are casting a pointer and not transforming it into a pointer to a pointer.
The cast (char **) just change the type of the following expression, it do not transform it. So the original and the resulting pointer are still the same pointer (they point the same place in memory), just the type is different. So both points to a string. But with your cast you lie to the compiler: you are telling him that you know what you are doing, and that the pointer point to a pointer to a string.
So you get a segmentation fault: the pointer point to a text and not to a pointer to a text: you are deferencing a string and oops.
You should have written:
str1 = (char **)&value1;
Note: your const char * is probably wrong. You are saying that the string is constant (and only the first one), not that the variable is constant (which should be written char * const).
Related
Basic malloc, array, pointer and assignment error
I have the following code. #include <stdio.h> #include <stdlib.h> int main() { char *buf = malloc(sizeof(char *) *3); char *p = "print"; char *q = "quit"; char *r = "reverse"; buf[0] = p; buf[1] = q; buf[2] = r; printf("%s", buf[0]); return 0; } I think buf will save the address of char variable. So, as p indicates the address of string, i think i can assign p to buf[0]. But compiler says "assignment makes integer from pointer without a cast". Why this happens?
first : you are trying to assign a char * to char instead you must use the following code char **buf = (char **)malloc(sizeof(char *) * 3); credit #chux
Where should I use a type char ** in some case as the input parameter?
There is some code piece right here below: main () { char in[8]; char out[255]; iconv_t cd; cd = iconv_open("gb18030", "utf-8"); ... char *p_in = in; char *p_out = out; size_t inlen = strlen(in); size_t outlen = sizeof(out); if (iconv(cd, &p_in, &inlen, &p_out, &outlen) < 0) { ... return -1 } ... return 0; } I can't totally understand the 2nd and 3rd parameters of the call to iconv. Why should that be ** pointer not the * pointer as the input? Can anyone explain the cases in C when the ** pointer should be used?
Pointer to pointer is used where the passed pointer is need to be modified in the called function and that modification need to be seen in the caller function. This is required because in C arguments are passed by value. So, when an argument is passed to a function then it simply copied to the function's parameter and created a local copy having block scope. Any change to that variable will not be seen in the argument that has been passed. void foo(in x){ x = 10; } int main(void){ int x = 5; foo(x) printf("%d\n", x); // x will be 5 } Same happens with pointers void bar(char *p){ p = "foobar"; } int main(void){ char *p = NULL; bar(p); if(p) printf("p is pointing to %s\n", p); else printf("p is NULL\n"); // This will } Using a pointer to pointer will do the desired job (pointing p to the string "foobar" void bar(char **p){ *p = "foobar"; } int main(void){ char *p = NULL; bar(&p); if(p) printf("p is pointing to %s\n", p); else printf("p is NULL\n"); // This will } Another use is when an array of string is need to passed to a function. Like int main(int argc, char **argv) or void print_fruits(char **fruits, size_t len){ for(int i = 0; i < len; i++) printf("%s\n", fruits[i]); } int main(void){ char *fruits[5] = {"Apple", "Banana", "Cherry", "Kiwi", "Orange"}; print_fruits(fruits, sizeof(fruits)/sizeof(fruits[0])); } Note that in function call print_fruits, fruits in the argument list will decay to pointer to its first element and the expression fruits will become of type char ** after the conversion.
Index of element pointed to by pointer
I have a 2D char array declared as char A[100][100] I also have a pointer that points to one element of that array char *ptr; ptr = A[5] This pointer gets passed to another function, which needs to be able to know the index of that pointer (in this case, 5) void func(void *ptr) { int index = ??? } How can I do this? Is this even possible?
Yes it is possible if you can see A in func (A is just a doubly-indexed 1D array, not a pointer on arrays, that's why it is possible). #include <stdio.h> char A[100][100]; void func(void *ptr) { char *ptrc = (char*)ptr; printf("index %d\n",int((ptrc-A[0])/sizeof(A[0]))); } int main() { char *ptr = A[5]; func(ptr); } result: index 5 of course, if you pass an unrelated pointer to func you'll have undefined results. Note: it is required to cast the incoming void * pointer to char * or the compiler won't let us diff pointers of incompatible types. EDIT: as I was challenged by chqrlie to compute both indexes, I tried it and it worked (also added safety to prevent the function being called with an unrelated pointer): #include <stdio.h> #include <assert.h> char A[100][100]; void func(void *ptr) { char *ptrc = (char*)ptr; ptrdiff_t diff = (ptrc-A[0]); assert(0 <= diff); assert(diff < sizeof(A)); printf("index %d %d\n",(int)(diff/sizeof(A[0])),(int)(diff % sizeof(A[0]))); } int main() { char *ptr = &(A[5][34]); func(ptr); } result: index 5 34
You can compute the offset of ptr from the beginning of the array and derive the coordinates: #include <stdio.h> #include <stdlib.h> char A[100][100]; void func(void *ptr) { if (ptr == NULL) { printf("ptr = NULL\n"); return; } ptrdiff_t pos = (char *)ptr - A[0]; if (pos < 0 || pos > (ptrdiff_t)sizeof(A)) { printf("ptr points outside A: ptr=%p, A=%p..%p\n", ptr, (void*)A, (void*)&A[100][100]); } else { printf("ptr = &A[%d][%d]\n", (int)((size_t)pos / sizeof(A[0])), // row number (int)((size_t)pos % sizeof(A[0]))) // column number } } int main(void) { char *ptr = &A[5][3]; func(ptr); return 0; }
Returning pointer to pointer parameter in C
I am wondering why the following two functions return different results: The result of GetPtr is always NULL, whereas GetPtr2 returns a pointer to the parameter, the intended behavior. #include <stdio.h> unsigned char ** GetPtr(unsigned char *ptr) { return &ptr; } unsigned char ** GetPtr2(unsigned char *ptr) { unsigned char **ptr2 = &ptr; return ptr2; } int main() { unsigned char *test = (unsigned char *) malloc(10 * sizeof(unsigned char)); printf("%p \n", GetPtr(test)); printf("%p \n", GetPtr2(test)); free(test); return 0; } Thanks in advance for any help!
unsigned char ** GetPtr(unsigned char *ptr) { return &ptr; } // <-- scope of ptr ends here You are using the address of an out-of-scope variable. As the Monty Python skit had it, It's an ex-parrot. This function returns the address of a local variable. When that address is received by the caller, the variable whose address it is will no longer be in scope.
Swapping two string pointers
i have to char[] in C and i wanted to swap between them, by only swaping the pointer to the array and not one char at a time so i wrote this code: #include <stdio.h> void fastSwap (char **i, char **d) { char *t = *d; *d = *i; *i = t; } int main () { char num1[] = "012345678910"; char num2[] = "abcdefghujk"; fastSwap ((char**)&num1,(char**)&num2); printf ("%s\n",num1); printf ("%s\n",num2); return 0; } I get this output (note the last 4 characters) abcdefgh8910 01234567ujk When I expect: abcdefghujk 012345678910 NOTE: I am working on a 64 bit Linux System.
You can't modify the addresses of num1 and num2, your code should work if your test was instead: int main () { char num1[] = "012345678910"; char num2[] = "abcdefghujk"; char *test1 = num1; char *test2 = num2; fastSwap (&test1,&test2); printf ("%s\n",test1); printf ("%s\n",test2); return 0; }
Arrays are not pointers. While they decay to pointers when you call your fastSwap(), these pointers are not the actual arrays. The fact that you need a cast should give you a hint that something is wrong. This would work: void fastSwap (const char **i, const char **d) { const char *t = *d; *d = *i; *i = t; } const char* num1 = "012345678910"; const char* num2 = "abcdefghujk"; fastSwap (&num1,&num2); printf ("%s\n",num1); printf ("%s\n",num2);
This will work: int main () { char *num1 = "012345678910"; char *num2 = "abcdefghujk"; fastSwap (&num1,&num2); printf ("%s\n",num1); printf ("%s\n",num2); return 0; }
num1 is an array, and &num1 is the address of the array itself - it is not an address of a pointer. The address of an array itself is the same location in memory as the address of the first element of the array, but it has a different type. When you cast that address to char **, you are claiming that it points at a char * value - but it does not. It points at a block of 13 chars. Your swap function then accesses that array of 13 chars as if it were a char * - since the latter is the same size as 8 chars on your platform, you end up swapping the first 8 chars of each array.
Your fastSwap only seems to work. You're invoking undefined behavior by casting '&num1' and '&num2' (which are pointers to the characters of num1 and num2) to pointers to pointers of characters (char**). char *t = *d t will point to whatever d's contents are pointing to, however d is pointing to the actually characters of num2 ("abcdefghujk" or 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x75 0x6B 0x00). This means that '*d' is actually copying the contents of 'num2' and not the pointer to num2 as you probably expected. 't' then is a bad pointer however since it is never dereferenced you avoid a crash/segment fault. Because you're on a 64 bit machine/OS pointers are 8 bytes the value of 't' is now the first 8 bytes of 'num2' and this is what gets put into num1 after *i = t If you intend to swap pointers you must first create pointer variables as Mark did char *test1 = num1; char *test2 = num2; fastSwap (&test1,&test2); Or change num1 and num2 into pointers (char *) rather than arrays (char[]) as sb1/Karl did char *num1 = "012345678910"; char *num2 = "abcdefghujk"; fastSwap (&num1,&num2);
I've had the same situation and solved it with the following trick: p.s. windows platform, vs-2012 void FastSwap (void **var1, void **var2) { void *pTmp = *var1; *var1 = *var2; *var2 = pTmp; } int main () { char *s1 = "1234567890123456"; char *s2 = "abcdefghij"; printf ("s1 before swap: \"%s\"\n", s1); printf ("s2 before swap: \"%s\"\n", s2); // if you change arguments in the FastSwap definition as (char **) // then you can erase the (void **) part on the line below. FastSwap ((void **) &s1, (void **) &s2); printf ("s1 after swap : \"%s\"\n", s1); printf ("s2 after swap : \"%s\"\n", s2); return (0); }
Change fastSwap to: void fastSwap (char *i, char *d) { while ((*i) && (*d)) { char t = *d; *d = *i; *i = t; i ++; d ++; } } then call fastSwap (num1, num2);
int swap(char *a, char *b){ char *temp = (char *)malloc((strlen(a) + 1)*sizeof(char)); strcpy(temp, a); strcpy(a, b); strcpy(b, temp); } int main(){ char a[10] = "stack"; char b[10] = "overflow"; swap(a, b); printf("%s %s", a, b); }
While given answers already showed how to do it right (and hinted to undefined behaviour), you still might be interested in the details... At very first, you have to character arrays. Applying the addressof operator to won't give you a pointer to pointer, but a pointer to array: int(*ptr1)[10] = &num1; Syntax might look strange, but that's C. The important thing here now is: You have a pointer with one level of indirection. But you cast it to a pointer with two levels of indirection (char**). What now happens in fastSwap is: char* t = *d; This will copy as many bytes of *d into t as pointers on your system have size. Solely: In reality, you do not have a pointer to pointer, but a pointer to array which only has been casted. So the first sizeof(void*) bytes of the array will be copied into t. Similarly for the other assignments, explaining the results you get. If now your arrays were shorter than the size of pointers, then memory after the arrays would have been read: int a[] = "123"; int b[] = "456"; int c[] = "789"; fastSwap ((char**)&a, char**(&b)); printf("%s %s %s", a, b, c); would have printed on your system (as pointer size is 8 bytes): 456 789 456 Explanation: char *t = *d; // copied the four bytes of b into t - AND the next four bytes (those of c!!!) *d = *i; // copied the eight bytes of a AND b int b AND c // b contains "123", c "456" *i = t; // copied the eight bytes that were copied from b and c into a and b // the "123" in b now got overwritten, that's why you never see them... Be aware that you don't have guarantee for such result, it is just the most likely one. You invoked undefined behaviour, anything might happen instead, you even might switch off the sun by accident (if your compiler happened to produce the appropriate code...).