I am trying to swap 2 entries in an array of strings, but my swap function doesn't swap when called.
swap(char*, char*);
int main() {
char *ptsr[2] = { "x", "y" };
swap(ptsr[0], ptsr[1]);
}
swap(char *t1, char *t2) {
char *t;
t = t1;
t1 = t2;
t2 = t;
}
Can someone identify and explain my mistake?
C is strictly pass by value. You pass the values of ptsr[0] and pstr[1] to swap. It swaps where it keeps those two values, but that has no effect on the calling function. Consider:
swap (int v1, int v2)
{
int t;
t = v1;
v1 = v2;
v2 = t;
}
This is the same as your swap function, just using int instead. It should be pretty clear that if you call swap(1,2);, the swap function just puts the 2 where it was storing the 1 and vice versa, but that has no effect on anything in the caller.
Same if you do this:
int i = 2;
int j = 3;
swap(i,j);
Since all you passed to swap is the values 2 and 3, it cannot affect the values of i and j by any means.
And same with your swap function if you do this:
char* j = "hello";
char* k = "world";
swap(j,k);
The function receives "hello" and "world" and swaps where it stores those two pointers. This has no effect on j or k in the caller.
C is strictly pass by value. Whatever parameters you pass to a function, the function only receives the values of.
The function in the question only swaps the values of its argument. The arguments are copies of the array elements, so the swap function has no effect.
To swap the pointers in the array, you must pass their addresses and change the prototype of the swap function:
#include <stdio.h>
void swap(char **t1, char **t2) {
char *t;
t = *t1;
*t1 = *t2;
*t2 = t;
}
int main() {
char *ptsr[2] = { "x", "y" };
swap(&ptsr[0], &ptsr[1]);
printf("pstr: { \"%s\", \"%s\" }\n", pstr[0], pstr[1]);
return 0;
}
Functions accept their arguments by value.
That is the function swap (for which you forgot to specify the return type void)
void swap(char *t1, char *t2) {
char *t;
t = t1;
t1 = t2;
t2 = t;
}
deals with copies of values of the expressions ptsr[0] and ptsr[1]. Chamging the copies does not influence on the original pointers.
You may imagine the function definition and its call the following way
swap(ptsr[0], ptsr[1]);
//...
void swap( /*char *t1, char *t2*/) {
char *t1 = ptsr[0], *t2 = ptsr[1];
char *t;
t = t1;
t1 = t2;
t2 = t;
}
As you can see the variables and ptsr[0] and ptsr[1] were not be changed.
To change an object (that in particularly can have a pointer type) in a function you need to pass it to the function by reference.
In C passing by reference means passing an object indirectly through a pointer to it.
So the function swap will look like
void swap(char **t1, char **t2) {
char *t;
t = *t1;
*t1 = *t2;
*t2 = t;
}
and the function must be called .like
swap( &ptsr[0], &ptsr[1] );
Or as the same
swap(ptsr, ptsr + 1);
Dereferencing the pointers to pointers t1 and t2 the function gets a direct access to the original pointer ptsr[0] and ptsr[1] swapping their values.
Related
I am doing an exercise where the task is to fix swap_pointer().
Two string should be swapped.
s1 = "I should print second.";
s2 = "I should print first.";
My work so far:
#include <stdio.h>
void swap_nums(int *, int *);
void swap_pointers(char *x, char *y);
int main(void) {
int a = 3, b = 4;
char *s1, *s2;
swap_nums(&a, &b);
printf("a is %d\n", a);
printf("b is %d\n", b);
s1 = "I should be printed second.";
s2 = "I should be printed first.";
/* swap_pointers(s1, s2); */
printf("s1 is %s\n", s1);
printf("s2 is %s\n", s2);
return 0;
}
void swap_nums(int *x, int *y) {
int tmp;
tmp = *x;
*x = *y;
*y = tmp;
}
void swap_pointers(char *x, char *y) {
char tmp;
tmp = *x;
*x = *y;
*y = tmp;
}
I think that not appending & to s1 and s2 before I pass them to the function for swap_pointers is the error?
If anyone can fix my issue here, please don't give the whole solution! I want to use what you give me as a tool to fix it by my own. If I really can't fix it by my own I will adress this later.
Ty in advance!
Let's at first consider this code snippet
int a = 3, b = 4;
swap_nums(&a, &b);
To swap the objects a and b you need to pass then to the function swap_nums by reference through pointers to them. Thus within the function dereferencing the pointers we can get a direct access to original objects and change their values.
void swap_nums(int *x, int *y) {
int tmp;
tmp = *x;
*x = *y;
*y = tmp;
}
The same we need to do with the variables s1 and s2. That is we need to pass them to the function swap_pointers by reference through pointers to them.
So you need to write
swap_ponters( &s1, &s2 );
and the function will be declared and defined like
void swap_ponters(char **x, char **y)
{
char *tmp = *x;
*x = *y;
*y = tmp;
}
In general if you have two objects like
T a;
T b;
where T is some type specifier then to change the objects in a function you need to pass them to the function by reference through pointers to them. So the declaration of the function swap will look like
void swap( T *a, T *b );
and the function will be called like
swap( &a, &b );
In your program a and b has the type int, that is T is an alias for the type int.
typedef int T;
T a = 3, b = 4;
so the function declaration will look like
void swap_nums( T *x, T *y );
For the variables s1 and s2 you can write
typedef char *T;
T s1, s2;
and again the function declaration will look like
void swap_pointers( T *x, T *y );
and the function will be called like
swap_pointers( &s1, &s2 );
As in this case T is an alias for the type char * then the function declaration can be rewritten like
void swap_pointers( char * *x, char * *y );
Your pass the pointers to the first characters of two null-terminated strings to the swap_pointers function.
Inside the function, when you use e.g. *x it's the same as x[0].
So you're swapping the first character of x with the first character of y.
If you want to switch pointers, you need to emulate pass-by-reference like you do with swap_nums, and pass pointers to the pointers, i.e. char **. And use the pointer-to operator & in the call.
So it should be
void swap_ponters(char **x, char **y);
and
swap_pointers(&s1, &s2);
The reason for the question is that there seems to be no reason to use a double indirection like "struct **pointer".
To understand the functioning of pointers to structures as arguments of a function I have prepared an example. The aim is to see if the changes made by a function on a structure remain outside the scope of the function, or if they only cause effect inside the function. This is a common problem of passing arguments by value or by reference.
#include <stdio.h>
/* A simple structure is defined to see the effect that the functions
* have on it. */
typedef struct est
{
int val1;
int val2;
} est_t;
/* These three functions simply assign the values val1 and val2 to the
* structure. Each of these functions uses a different way of passing
* the parameter to the function referring to the structure. There are
* more comments below, in the definition of each function. */
void foo(int, int, est_t);
void bar(int, int, est_t*);
void baz(int, int, est_t**);
/* This is a function to print the values of a structure and make the
* code cleaner. It also contains a parameter about a structure! */
void print_est(est_t*);
int main (int argc, char *argv[])
{
est_t a;
foo(10, 11, a);
print_est(&a);
bar(20, 21, &a);
print_est(&a);
est_t *p = &a;
baz(30, 31, &p);
print_est(&a);
return 0;
}
void foo(int v1, int v2, est_t ve)
{
/* In this case the structure is "directly put" into the function.
* As the structure already is inside the function, the values of each
* element are assigned with the ". " */
ve.val1 = v1;
ve.val2 = v2;
/* With these printf you can see what is happening within the
* function. */
printf("[foo] val1 = %d\n", ve.val1);
printf("[foo] val2 = %d\n", ve.val2);
}
void bar(int v1, int v2, est_t *ve)
{
/* In this case the structure is passed into the function using a
* pointer. */
ve->val1 = v1;
ve->val2 = v2;
printf("\n[bar] val1 = %d\n", ve->val1);
printf("[bar] val2 = %d\n", ve->val2);
}
void baz(int v1, int v2, est_t **pp)
{
/* In this case the structure is passed into the function using a
* pointer to a pointer to a struct. */
(*pp)->val1 = v1;
(*pp)->val2 = v2;
printf("\n[baz] val1 = %d\n", (*pp)->val1);
printf("[baz] val2 = %d\n", (*pp)->val2);
}
void print_est(est_t *addr)
{
printf("[main] val1 = %d\n", addr->val1);
printf("[main] val2 = %d\n", addr->val2);
}
And this is the output when you run the program.
foo(10, 11, a);
[foo] val1 = 10
[foo] val2 = 11
[main] val1 = -1238356256
[main] val2 = 32764
You can see that the values that were assigned within the function, are not kept outside
And let's see the output for bar and baz.
bar(20, 21, &a);
[bar] val1 = 20
[bar] val2 = 21
[main] val1 = 20
[main] val2 = 21
est_t *p = &a;
baz(30, 31, &p);
[baz] val1 = 30
[baz] val2 = 31
[main] val1 = 30
[main] val2 = 31
It seems that they do the same. I mean in both cases the values are kept outside the function.
Foo and bar are typical cases of by-value and by-reference, and even if the changes are not intended to be permanent, the idea of passing a structure by-reference can be interesting from the point of view of saving resources. See advantage of passing pointer to a struct as argument?
But as bar and baz do the same ¿is there any reason to use a double pointer to pass arguments to a function?
is there any reason to use a double pointer to pass arguments to a function
Yes. You use a pointer whenever you want to change the argument you're passing. So if you want to change a pointer, then you need a pointer to pointer.
Simple example:
void foo(struct bar **ptr)
{
*ptr = malloc(10 * sizeof **ptr);
for(int i=0; i<10; i++)
(**ptr)->x = i;
}
There are generally two reasons for a function to accept an argument of type T ** (for any type T):
the argument corresponds to an array of pointers;
the function is meant to update the pointer value.
As an example of the first, suppose we have code like
int main( void )
{
char *strs[] = { "foo", "bar", "bletch", "blurga", NULL };
func( strs );
...
}
strs is an array of pointers, but thanks to the usual decay rule, what func receives is a pointer to a pointer:
void func( char **s )
{
...
}
Alternately, your function is meant to update a pointer value. Suppose we’ve dynamically allocated an array of struct type that we need to extend with realloc and initialize the extended memory. To make that a little cleaner, we’ve put that in a separate function:
void extend( struct s **ptr, size_t *size )
{
struct s *tmp = realloc( *ptr, *size * 2 );
if ( tmp )
{
for ( size_t i = *size; i < *size * 2; i++ )
init ( &tmp[i] );
*ptr = tmp;
*size *= 2;
}
}
I'm learning the basics and principles of C.
I came now to pointers, strings and structs.
Now I'm working on this code to pass arrays' content to functions.
I have this code to pass content of different arrays to function.
What I succeeded to accomplish is:
How to pass one complete string because it's considered as one element of the array.
How to pass array of char and ints.
The issues I have now:
How to pass arrays of multiple strings to functions.
How to assign a pointer to the arrays to pass them also to functions.
This is my code so far:
void print_array(char *arr,int8_t cnt);
void print_array(char *arr,int8_t cnt)
{
int i;
printf("Number of elements is: %d\n",cnt);
for (i=0;i<cnt;i++)
{
printf("Elements of array: %s\n",arr);
}
}
void print_len (char *arr,int8_t cnt);
void print_len (char *arr,int8_t cnt)
{
char i,l;
for (i=0;i<cnt;i++)
{
printf ("%d\n",strlen(arr));
}
}
int main(){
char array_1 [] = {1,2,3,4,5,6,7,8};
char array_2 [] = {'1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G'};
char *array_3 [] = {"1st","2nd","3rd","4th","5th","6th"};
char *array_4 [] = {"Many of the designations used by manufacturers"};
char *array_5 [] = {"mm","End of Multiple Strings Array","simple bluetooth connection",
"datalogging purposes and accessing recorded data","THE OPERATING ENVIRONMENT"};
//int8_t *array_pointer[3]=(char*){&array_1,&array_2,&array_3};
int8_t cnt1 = sizeof(array_1)/sizeof(array_1[0]);
int8_t cnt2 = sizeof(array_2)/sizeof(array_2[0]);
int8_t cnt3 = sizeof(array_3)/sizeof(array_3[0]);
int8_t cnt4 = sizeof(array_4)/sizeof(array_4[0]);
int8_t cnt5 = sizeof(array_5)/sizeof(array_5[0]);
int8_t len1,len2,len3,len4,len5,i,t=0,x=0;
//print_len(*array_3,cnt3);
print_len(*array_5,cnt5);
//printf("Number of chars int the string#%d is: %d\n",i,t);
// this for testing strlen inside main
// I want to process this function outside main
/*for (i=0;i<cnt5;i++)
{
printf ("%d\n",strlen(array_5[i]));
}*/
//print_array(array_pointer[0],cnt1);
//print_array(array_1,cnt1);
//print_array(array_2,cnt2);
//print_array(*array_3,cnt3);
//print_array(*array_4,cnt4);
print_array(*array_5,cnt5);
return 0;
}
How to pass arrays of multiple strings to functions.
You need another function. Declare it as:
void print_array_2(char *arr[], int cnt);
Then, you can use:
print_array_2(array_3, cnt3);
How to assign a pointer to the arrays to pass them also to functions.
You can use:
char* string_array[2] = {};
string_array[0] = array_1;
string_array[2] = array_2;
print_array_2(string_array, 2);
I am trying to sort array of structs using qsort() but frustratingly, it's not working. I have read the manpage for qsort() and I think I have the comparator function that syntactically looks okay, but when I print the "sorted" array after calling qsort(), nothing is sorted in my array.
The code:
#include <stdlib.h>
#include <stdio.h>
#define ARRAY_SZ 5
typedef struct SingleChar
{
unsigned char Character;
unsigned int Weight;
} *SingleCharPtr;
int CompareWeights(const void *a, const void *b)
{
const SingleCharPtr p1 = (SingleCharPtr)a;
const SingleCharPtr p2 = (SingleCharPtr)b;
// printf("Weight1: %u\tWeight2: %u\n", p1->Weight, p2->Weight);
// return (p1->Weight - p2->Weight);
if (p1->Weight < p2->Weight)
return -1;
else if (p1->Weight > p2->Weight)
return 1;
else
return 0;
}
SingleCharPtr MakeChar(unsigned char c, unsigned int w)
{
SingleCharPtr scptr = malloc(sizeof(struct SingleChar));
if (!scptr)
{
fprintf(stderr, "[Error] Out of memory\n");
exit(1);
}
scptr->Character = c;
scptr->Weight = w;
return scptr;
}
int main(void)
{
SingleCharPtr *chars = malloc(ARRAY_SZ * sizeof(SingleCharPtr));
chars[0] = MakeChar('B', 3);
chars[1] = MakeChar('E', 7);
chars[2] = MakeChar('A', 4);
chars[3] = MakeChar('D', 6);
chars[4] = MakeChar('C', 2);
qsort(chars, ARRAY_SZ, sizeof(SingleCharPtr), &CompareWeights);
int i;
for (i = 0; i < ARRAY_SZ; i++)
{
printf("Character: %c\tWeight: %u\n", chars[i]->Character, chars[i]->Weight);
free(chars[i]);
}
free(chars);
return 0;
}
Also, in the comparator function (CompareWeights()), I found out that when I print the weight of the structs pointed by SingleCharPtr, I get 0s for all of them.
Any pointer to right direction would be highly appreciated.
The problem: qsort() passes in pointers to the elements to be compared to the comparator function, and not the elements themselves. So, the arguments to your CompareWeights() function are actually const SingleCharPtr *, disguised as const void *. What you should do in that function is:
const SingleCharPtr p1 = *(const SingleCharPtr *)a;
etc.
Sidenotes:
I. If your assumption had been valid, then you wouldn't have needed the cast:
const SingleCharPtr p1 = a;
is preferred over
const SingleCharPtr p1 = (SingleCharPtr)a;
because of this.
II. The comparison function need not return -1, 0 or 1. It should return an integer less than 0, 0 or greater than 0. Thus, all the huge if in CompareWeight() is completely superfluous, write
return p1->Weight - p2->Weight;
instead.
III. SingleCharPtr *chars = malloc(ARRAY_SZ * sizeof(SingleCharPtr)); - Why? You only use the chars array locally in the main() function, you don't need dynamic allocation for that. Why not write
SingleCharPtr chars[ARRAY_SZ];
instead?
If you see the example in e.g. this manual page, you will see that the when qsort is passed an array of pointer (just like you have) then the arguments to the sorting function are actually pointers to pointers. This is because qsort passes pointers to the elements, not the elements themselves.
To accomodate for that, change accordingly:
int CompareWeights(const void *a, const void *b)
{
const SingleCharPtr p1 = *(SingleCharPtr*)a;
const SingleCharPtr p2 = *(SingleCharPtr*)b;
return (p1->Weight - p2->Weight);
}
I have written code to swap strings, but I am not able to swap. What is the problem and how can I solve it by using a function, swap?
#include <stdio.h>
void swap( char*,char*);
int main()
{
char *ptr[2] = {"hello", "morning"};
swap(ptr[0], ptr[1]);
printf("%s %s", ptr[0], ptr[1]);
return 0;
}
void swap(char *t1, char*t2)
{
char *t;
t = t1;
t1 = t2;
t2 = t;
}
I also tried to pass (&ptr[0], &ptr[1]), but here it shows a segmentation fault. Also I made a char, *p1 = ptr[0], char *p1 = ptr[1], and then passes &p1, and &p2 to swap, but still I get a segmentation fault.
C function arguments are pass-by-value. You're passing the value of addresses to your swap function, and expecting those values, the addresses, to change. But only the copies of the addresses in your swap function change.
To change the actual passed-in addressed, you'll need an aditional level of reference:
void swap(char **t1, char **t2)
{
char *t;
t = *t1;
*t1= *t2;
*t2 = t;
}
And call this swap like so: swap(&ptr[0], &ptr[1]);
You need to pass in pointers to the pointers of the char arrays in order to switch them. By doing that you can swap the values of those pointers instead. (Which are the actual arrays.)
#include<stdio.h>
void swap( char**,char**);
int main()
{
char *ptr[2] = {"hello","mornig"};
swap(&ptr[0], &ptr[1]);
printf("%s %s",ptr[0], ptr[1]);
return 0;
}
void swap( char **t1,char **t2)
{
char *t;
t = *t1;
*t1 = *t2;
*t2 =t;
}
You need to pass pointers to your strings to swap them (char**). Otherwise the changes you do will be local to the swap function.
void swap( char **t1,char **t2)
{
char *t;
t = *t1;
*t1 = *t2;
*t2 =t;
}
int main()
{
char *ptr[2] = {"hello","mornig"};
swap(&ptr[0], &ptr[1]);
printf("%s %s",ptr[0],ptr[1]);
return 0;
}
char *ptr[2] = {"hello","mornig"}; - This statement means you are allocating an array of size 2 which is going to store a address of two strings(ie char *). Now the two strings you are giving will be in text segment which is a read only data. If we tries to modify it, which will leads to crash(sgmentation fault).
So if you call swap(&ptr[0], &ptr[1]) leads to a crash. because you are trying to write the charcter m in the first read only string h. Write is not possible to the string which is in text segment.
If you want to simply swap a string you can call the function as swap(&ptr[0], &ptr[1]), which is equivalent to swap((ptr + 0),(ptr + 1));.
And change the swap function as below
void swap( char **t1,char **t2)
{
char *t;
t = *t1;
*t1 = *t2;
*t2 =t;
}
Here we are just swapping the address of the string stored in the array pointer ptr.