Swapping two string pointers - c

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...).

Related

void pointer to string pointer

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).

Pointer to a pointer to an array (?)

Please forgive me if the title is not 100% correct. I have a function which takes two inputs - a pointer to a string, and a pointer to a pointer to an array (?). The function I am writing is
int string_parser(char *inp, char **array_of_words[])
What I want to be doing is taking these two arguments and the function should return
the amount of words in the string array (string array is char *inp)
a pointer to an array of pointers char **array_of_words[] - each element in the array pointing to the address of the first character in each word (I apologise if that is wordy)
I have created the pointer to an array of pointers, and allocated space to this array
char **startOfWords_ptr = (char **) malloc(amountOfWords * sizeof(char*));
and have been manipulating the contents just fine. I now want to pass the array at *start_of_words back to array_of_words - but I don't understand how to do it
With *array_of_words = *(startOfWords_ptr); am I saying: a pointer to point at the starting address of the array of pointers?
Surely I am not because I don't get the same values when printing...
printf("%p\n", (void *) *array_of_words); // 0x401f2c, o
printf("%p\n", (void *) *startOfWords_ptr); // 0x401f2c, o
printf("%p\n", (void *) array_of_words[1]); // 0x401f2c, o
printf("%p\n", (void *) startOfWords_ptr[1]); // 0x401f30, t
Suggestions with comments as output
*array_of_words = (startOfWords_ptr); // This currently does not work
printf("%p, %c\n", (void *) array_of_words[0], *array_of_words[0]); // 0xcbbdd0, ;
printf("%p, %c\n", (void *) startOfWords_ptr[0], *startOfWords_ptr[0]); // 0x401f3b, o
printf("%p, %c\n", (void *) array_of_words[1], *array_of_words[1]); // 0x401f2c, o
printf("%p, %c\n", (void *) startOfWords_ptr[1], *startOfWords_ptr[1]); // 0x401f3f, t
Okay, so let's look at this from the perspective of the caller of this function:
int main( void )
{
char my_input[] = "This is a test";
char **my_output = NULL;
int count = string_parser( my_input, &my_output );
for ( int i = 0; i < count; i++ )
printf( "pointer #%d: %p\n", i, (void *) my_output[i] );
}
We know that after calling string_parser, my_output will point to the first of a sequence of pointers to char. Since we need to modify the value of my_output, we must pass a pointer to it in the call (&my_output).
This means that the prototype for string_parser needs to be
int string_parser( const char *inp, char ***array_of_words )
{
...
}
In the context of a function parameter declaration, T a[N] and T a[] are both treated as T *a, so char ***array_of_words is the same as char **array_of_words[] - both are ultimately char ***.
So given
I have created the pointer to an array of pointers, and allocated space to this array
char **startOfWords_ptr = (char **) malloc(amountOfWords * sizeof(char*));
and have been manipulating the contents just fine. I now want to pass the array at *start_of_words back to array_of_words - but I don't understand how to do it
you have it backwards - you'd assign the startOfWords_ptr to *array_of_words:
*array_of_words = startOfWords_ptr; // char ** = char **
array_of_words has one more level of indirection than startOfWords_ptr, so we need to dereference it to get the types to match. After this assignment,
*array_of_words[i] == startOfWords_ptr[i] // char * == char *
this parameter in the function signature:
char **array_of_words[]
can be re-written as:
char ***array_of_words
I.E. either write it as:
char **array_of_words
or as:
char *array_of_words[]
This is very similar to the different ways the second parameter to main() can be written.

Assigning returned cstring to variable

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

Problem with C char[] swapping

I have this short code:
#include <stdio.h>
void fastSwap (char **i, char **d)
{
char *t = *d;
*d = *i;
*i = t;
}
int main ()
{
char num1[] = "hello";
char num2[] = "class";
fastSwap ((char**)&num1,(char**)&num2);
printf ("%s\n",num1);
printf ("%s\n",num2);
return 0;
}
The output of this short program is:
claso
hells
and I just don't understand why the last letters of each char[] are swapped.
Any ideas?
fastSwap ((char**)&num1,(char**)&num2);
This is undefined behavior. You can't cast a pointer to array of char to a pointer to pointer to char. What you need is:
const char* num1 = "hello";
const char* num2 = "class";
fastSwap (&num1,&num2);
Also, you'll need to change the declaration of fastSwap and add inner-level const to arguments
void fastSwap (const char **i, const char **d)
I'm assuming you're trying to swap the contents of the num1 and num2 arrays by just manipulating pointers, so that after calling fastswap the contents of num1 will be "class" and num2 will be "hello".
If that's the case, then this won't work for a number of reasons. Arrays are not pointers, even though array expressions are often converted to pointer types. Secondly, you cannot modify the value of an array expression.
If you want to keep num1 and num2 as arrays (as opposed to pointers to string literals) and be able to swap their contents, you'll need to something more along these lines:
void fastswap(char *i, char *d)
{
while (*i && *d)
{
char t = *i;
*d++ = *i;
*i++ = t;
}
}
which will be called as
fastswap(num1, num2);
You are passing pointers to pointers to chars. You probably just want to pass pointers to chars like this:
#include <stdio.h>
void fastSwap (char *i, char *d)
{
char t = *d;
*d = *i;
*i = t;
}
int main ()
{
char num1[] = "hello";
char num2[] = "class";
fastSwap (num1,num2);
printf ("%s\n",num1);
printf ("%s\n",num2);
return 0;
}
This swaps the first character of the 2 char arrays.

How do I iterate over a pointer to a pointer?

Lets say I have the following variables:
char c[] = "ABC";
char *ptr = &c;
char **ptr2 = &ptr;
I know I can iterate over a pointer to an array of char, this way:
int i;
for(i=0; i<3; i++){
printf("TEST******************, %c\n", ptr[i]);
}
How do I iterate over a pointer to a pointer?
Suppose:
6 char c[] = "ABC";
7
8 char *ptr = &c;
9 char *ptr2 = ptr;
10 char **ptr3 = &ptr;
In this scenario:
ptr represents an address of c
ptr2 represents an address of ptr. A pointer to a pointer
ptr3 is a value stored in ptr, which is an address of c.
**ptr3=&ptr means - Take address of ptr, look inside and assign its value (not address) to ptr3
If I understood your question correctly, you need to use pointers to pointers: ptr2 in my example instead of ptr3
If so, you can access elements like :
ptr2[0] = A
ptr2[1] = B
ptr2[2] = C
For the record the following will yeld the same results. Try it.
12 printf ("===>>> %x\n", ptr2);
13 printf ("===>>> %x\n", *ptr3);
Good discussion for your reference is here
For your example:
int i;
for(i=0; i<3; i++){
printf("TEST******************, %c\n", (*ptr2)[i]);
}
If I did not misunderstand your question, this code should make a job
printf("TEST******************, %c\n", (*ptr2)[i]);
let me give an example,
char **str; // double pointer declaration
str = (char **)malloc(sizeof(char *)*2);
str[0]=(char *)"abcdefgh"; // or *str is also fine instead of str[0]
str[1]=(char *)"lmnopqrs";
while(*str!=NULL)
{
cout<<*str<<endl; // prints the string
str++;
}
free(str[0]);
free(str[1]);
free(str);
or one more best example which you can understand.
here i have used 2 for loops because i am iterating over each character of the array of strings.
char **str = (char **)malloc(sizeof(char *)*3); // it allocates 8*3=24 Bytes
str[0]=(char *)"hello"; // 5 bytes
str[1]=(char *)"world"; // 5 bytes
// totally 10 bytes used out of 24 bytes allocated
while(*str!=NULL) // this while loop is for iterating over strings
{
while(**str!=NULL) // this loop is for iterating characters of each string
{
cout<<**str;
}
cout<<endl;
str++;
}
free(str[0]);
free(str[1]);
free(str);

Resources