I have a 2D character array, I want to swap two rows of this array.
I can think of this function.
char str[5][5];
swap(str[i],str[j]);
void swap(char * p, char *q) {
char *temp;
temp = p;
p = q;
q = temp;
}
This function does not work.
I also came up with this,
char ** temp1;
char ** temp2;
temp1 = &str[i];
temp2 = &str[j];
*temp1 = str[j];
*temp2 = str[i];
This does not work either, please suggest me a proper way to do this task.
Try the following approach
#include <stdio.h>
#include <string.h>
void swap( char *s1, char *s2, size_t n )
{
char t[n];
strcpy( t, s1 );
strcpy( s1, s2 );
strcpy( s2, t );
}
#define N 5
int main(void)
{
char s[N][N] =
{
"Cat",
"Dog",
"Cow",
"Bird",
"Goat"
};
for ( size_t i = 0; i < N; i++ ) puts( s[i] );
puts( "" );
swap( s[0], s[3], N );
for ( size_t i = 0; i < N; i++ ) puts( s[i] );
return 0;
}
The program output is
Cat
Dog
Cow
Bird
Goat
Bird
Dog
Cow
Cat
Goat
Take into account that you can use also standard function strncpy instead of strcpy.
The other approach is to use standard function memcpy that to copy exactly N characters.
void swap( char * ary, int idx1, int idx2, int rowlen )
{
for ( int x=0; x<rowlen; x++ )
{
temp = ary[idx1][x];
ary[idx1][x] = ary[idx2][x];
ary[idx2][x] = temp;
}
}
#define ROWLEN 5
void main( void )
{
char str[5][ROWLEN];
swap( str, 2, 4, ROWLEN ); // swap rows 2 and 4
}
I didn't compile this so there might be syntax errors, but this should convey the idea.
Use a loop to swap every elements of the two rows :
void swapRows(char* row1, char* row2, size_t rowlen)
{
for (size_t i=0; i<rowlen; ++i)
{
char tmp = row1[i];
row1[i] = row2[i];
row2[i] = tmp;
}
}
Here we have a function that takes a pointer to two rows of your array, the length of a row, and that runs a very simple loop to swap every elements of those rows. Here is how you would use it :
int main()
{
char str[2][2] = {{'1','2'},{'3','4'}};
swapRows(&str[0][0], &str[1][0], 2);
// str now contains {'3','4'},{'2','1'}
}
What you seem to have tried is to swap the pointers to the rows instead of physically moving the content of the rows. That can't work. Pointers only allow you to find your data, but moving them around doesn't actually modify that data. Now, if you had a char** array this idea would work, but in the case of a contiguous 2D char[][] array you have to move things physically.
Since this is a contiguous 2D array, not an array of pointers, one should use memcpy to copy five-element subarrays, like this:
void swap(char *p, char *q) {
char temp[5];
memcpy(temp, p, sizeof(temp));
memcpy(p, q, sizeof(temp));
memcpy(q, temp, sizeof(temp));
}
The idea is to make an array buffer sufficient to hold one "row", copy the first row into it, and then do the swap the usual way (i.e. with an assignment of a temporary variable).
Demo.
Related
I was trying to swap two arrays using pointers.
What I wanted was to swap using a call by reference.
This code I wrote is given below
#include <stdio.h>
#include <stdlib.h>
void swap(int **a, int **b) {
int *temp = (int*)malloc(5*sizeof(int));
temp = *a;
*a = *b;
*b = temp;
}
int main() {
int arr1[] = {1, 2, 3, 4, 5};
int arr2[] = {6, 7, 8, 9, 10};
swap((int**)&arr1, (int**)&arr2);
for(int i=0; i<5; i++) printf("%d\t", arr1[i]);
printf("\n");
for(int i=0; i<5; i++) printf("%d\t", arr2[i]);
printf("\n");
}
The output of the code is:
6 7 3 4 5
1 2 8 9 10
instead of:
6 7 8 9 10
1 2 3 4 5
What did I do wrong?
In this call
swap((int**)&arr1, (int**)&arr2);
the passed pointers point to first elements of the arrays arr1 and arr2.
So within the function swap
void swap(int **a, int **b) {
int *temp = (int*)malloc(5*sizeof(int));
temp = *a;
*a = *b;
*b = temp;
}
dereferencing the pointers like for example
*a
results in reading the first two elements of the array arr1 as a pointer because in your system sizeof( int * ) is equal to 2 * sizeof( int ).
That is values of first two elements of the arrays are interpreted as values of pointers.
And the obtained output confirms that
6 7 3 4 5
1 2 8 9 10
^^^^^
Moreover the function has a memory leak because at first memory was allocated dynamically and its address was assigned to the pointer temp and then the pointer was reassigned
int *temp = (int*)malloc(5*sizeof(int));
temp = *a;
So the address of the allocated memory was lost and the memory was not freed.
You can not swap arrays such a way. You need to swap each pair of elements of the arrays.
The function can look for example the following way
void swap( int *a, int *b, size_t n )
{
for ( int *p = a; p != a + n; ++p, ++b )
{
int temp = *p;
*p = *b;
*b = temp;
}
}
And the function is called like
swap( arr1, arr2, 5 );
A less flexible function can look the following way
void swap( int ( *a )[5], int ( *b )[5] )
{
for ( int *p1 = *a, *p2 = *b; p1 != *a + 5; ++p1, ++p2 )
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
}
And the function is called like
swap( &arr1, &arr2 );
First of all lets fix your swap function:
void swap(int **pparr1, int **pparr2)
{
int *temp = *pparr1;
*pparr1 = *pparr2;
*pparr2 = temp;
}
This function now swaps the two pointers that parr1 and parr2 are pointing to.
Then lest update the way to call this function:
int *parr1 = arr1; // Make parr1 point to the first element of arr1
int *parr2 = arr2; // Make parr2 point to the first element of arr2
// Swap the two pointers
swap(&parr1, &parr2);
And then we print using the pointers instead of the arrays:
printf("arr1 = [ ");
for (unsigned i = 0; i < 5; ++i)
{
printf("%d ", parr1[i]);
}
printf("]\n");
printf("arr2 = [ ");
for (unsigned i = 0; i < 5; ++i)
{
printf("%d ", parr2[i]);
}
printf("]\n");
This will print the arrays as if they were swapped, but in fact the arrays themselves are not swapped. You can verify by printing using the arrays arr1 and arr2 themselves.
If you want to swap the actual contents of the arrays, you need a loop to actually swap the elements themselves:
// Function to swap two integer values
void swap(int *p1, int *p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
// Function to swap two arrays
void swap_arrays(int *pa1, int *pa2, size_t size)
{
for (size_t i = 0; i < size; ++i)
{
// Swap each separate element of the arrays
swap(&pa1[i], &pa2[i]);
}
}
Call like
swap_arrays(arr1, arr2, 5);
After this the contents of the arrays themselves have been swapped.
swap((int**)&arr1, (int**)&arr2);
It looks like your idea is to have swap swap the address of arr1 with the address of arr2. Variables in C, including arrays, do not work this way, and this idea cannot possibly work.
arr1 is a name for the array. It is not the address of the array, nor is it a variable whose value is the address of the array. There is no pointer to the array that can be swapped with a pointer to the array arr2.
When the compiler processes int arr1[] = {1, 2, 3, 4, 5};, it creates an array of five int, and then it uses arr1 to refer to that array. Wherever arr1 is used, the compiler creates code that will refer to the array. It does not do this by storing the address of the array in some memory location you can swap with another address. It has ways to access the array using registers and processor instructions set up for that.
In swap((int**)&arr1, (int**)&arr2);, you take the addresses of arr1 and arr2 and convert them to int **. The address of arr1 is the address where its contents are. What is at that address in memory is the int elements, not a pointer. So the int ** type does not make sense for this; the address of arr1 is not the address of an int *.
The reason you get the output you do is that int objects are four bytes in your C implementation and int * objects are eight bytes. So when temp = *a; attempts to get the int * that a should be pointing to, it gets the first eight bytes in arr1. Then *a = *b; replaces those eight bytes with the first eight bytes in arr2. And *b = temp; replaces the first eight bytes in arr2 with the saved eight bytes from arr1.
Note that, in these three statements, temp is used to hold eight bytes from arr1. The value it was given in int *temp = (int*)malloc(5*sizeof(int)); is lost when temp is assigned another value in temp = *a;.
Also note that this behavior you observed in this instance is not specified by the C standard, and different behavior can result in other circumstances, including alignment errors and surprising transformations of the program by compiler optimization.
You cannot assign whole arrays to each other in a single operation using =; you must either use a library function like memcpy or assign each element individually.
Under most circumstances, expressions of type "N-element array of T" will be converted, or "decay", to expressions of type "pointer to T" and the value will be a pointer to the first element. If you called the function as
swap( arr1, arr2 );
it would be equivalent to writing
swap( &arr1[0], &arr2[0] );
So you're already passing the arrays "by reference", just not in the way you're probably thinking.
The easiest way to do what you want would be something like this:
void swap( int *a, int *b, size_t count )
{
for ( size_t i = 0; i < count; i++ )
{
int tmp = a[i];
a[i] = b[i];
b[i] = tmp;
}
}
Alternately, you could use memcpy with a temporary array:
void swap( int *a, int *b, size_t count )
{
int tmp[count]; // C99 or later
memcpy( tmp, a, count );
memcpy( a, b, count );
memcpy( b, tmp, count );
}
In this case tmp is a variable-length array, whose size is provided by a runtime value. VLAs are useful for things like this if the array size isn't too big, but they're only available for C99 and later, and are optional after C2011. If your arrays are very large or VLAs aren't available, then this would be a case for dynamic memory:
void swap( int *a, int *b, size_t count )
{
int *tmp = calloc( count, sizeof *tmp );
if ( tmp )
{
memcpy( tmp, a, count );
memcpy( a, b, count );
memcpy( b, tmp, count );
free( tmp );
}
}
The first method (swapping each element individually) would be my preference. It avoids any kind of dynamic memory management, it's straightforward, it's not making a bunch of library calls, etc.
In all three cases, you'd call it as
swap( arr1, arr2, 5 );
Beware explicit casts, especially pointer casts - they're usually a sign you're doing something wrong.
#include<stdio.h>
#define MAX_LEN 20
char *swap_elements(char **arr, int i)
{
char temp[5];
*temp = *arr;
*arr = *(arr+i);
*(arr+i) = *temp;
return arr;
}
void main()
{
char arr[][MAX_LEN]={"user1", "user2", "user3", "user4"};
int i, j;
printf("Enter the index with which you want to swap: ");
scanf("%d", &i);
arr = swap_elements(arr, i);
for(j=0;j<4;j++)
printf("%s", *(arr+i));
}
This is the code that I have written for swapping the first element with the user-entered index element. But it's showing an error as below
For starters according to the C Standard the function main without parameters shall be declared like
int main( void )
In this function call
arr = swap_elements(arr, i);
the array designator arr is implicitly converted to pointer to its first element that has the type char ( * )[MAX_LEN].
Also arrays do not have the assignment operator. So this statement
arr = swap_elements(arr, i);
is incorrect.
You need to declare the function like
void swap_elements( char ( *arr )[MAX_LEN], int i);
Within the function you are trying to assign a pointer to the object of the type char
char temp[5];
*temp = *arr;
that does not make a sense.
Instead you need to copy strings stored in character arrays.
The function can be defined the following way
#include <string.h>
void swap_elements( char ( *arr )[MAX_LEN], int i)
{
char temp[MAX_LEN];
strcpy( temp, *arr );
strcpy( *arr, *( arr + i );
strcpy( *( array + i ), temp );
}
Another approach is to declare an array of pointers instead of the multi-dimensional array.
For example
char * arr[] = {"user1", "user2", "user3", "user4"};
In this case the function will look like
void swap_elements( char **arr, int i)
{
char *temp;
temp = *arr;
*arr = *( arr + i );
*( array + i ) = temp;
}
Pay attention to that you need to check within the function that the passed index is not greater than the array size. Otherwise the function is unsafe. So you need to add one more parameter to the function that will specify the number of elements in the passed array.
Here is how to actually achieve what you are trying to do.
#include <stdio.h>
#include <string.h>
#define MAX_LEN 20
void swap_elements(char* arr, int i)
{
char temp[MAX_LEN];
strncpy(temp, arr, MAX_LEN);
strncpy(arr, arr+i*MAX_LEN, MAX_LEN);
strncpy(arr+i*MAX_LEN, temp, MAX_LEN);
}
void main()
{
char arr[][MAX_LEN]={"user1", "user2", "user3", "user4"};
int swapTarget;
printf("Enter the index with which you want to swap: ");
scanf("%d", &swapTarget);
swap_elements(arr, swapTarget);
for(int i=0;i<4;i++)
printf("%s", arr[i]);
}
To understand why I did it like this first you need to understand how multidimensional arrays are stored in C.
When you for example have this array:
int arr2d[5][2] = {{1,2},{3,4},{5,6},{7,8},{9,10}}
It will be stored like this:
| 1 | 2 | 4 | 5 | 7 | 8 | 9 | 10 |
And when you try to access the 2nd array 2nd element element with arr2d[1][1] C basically converts it to: *(arr2d + 1*2 + 1). 2 here representing the size of one of the subarrays(in your case MAX_LEN).
So when I write arr+i*MAX_LEN it is the same as writing arr[i] but you have to do it manually.
Also you can't move strings around like this *arr = *(arr+i). This would only move the i-th character of arr into the place of the first character of arr.
Which is why you have to use either strcpy or strncpy. The difference being that with strncpy you define the length of the string to be moved while with strcpy it copies until it gets to a null-byte.
Suppose I have two arrays:
char **words = (char**) malloc(MAX * sizeof(char*));
int *count = malloc(MAX * sizeof(int));
The first one stores the words in a given list:
words[0] = "myword0" / words[1] = "myword1" / words[2] = "myword3" ...
and the second one stores the number of occurences of each word in the list:
count[0] = 4 //means that "myword0" appears 4 times in the list
I want to print the most frequent word and its number of occurrences. If there are words that appear the same number of times, print the first one in alphabetical order.
To do that, I thought about alphabetically sorting words:
int sortWordsAlph(const void* a, const void* b)
{
char **x = (char**)a;
char **y = (char**)b;
return (strcmp(*x,*y));
}
and in int main():
qsort(words, MAX, sizeof(char*), sortWordsAlph);
Now, the problem is with count. It should still point to the occurrences of each word, thus meaning I have to sort it too. How can I do this?
Maybe I should use a swapping algorithm instead of qsort?
If you want to use qsort(), you should use an array of structs that contain both the word and the count. You can then pass your array to qsort() with a custom comparison function:
struct wc_s {
char *word;
int count;
};
int cmp_words (const void *p1, const void *p2)
{
const struct wc_s *s1 = p1;
const struct wc_s *s2 = p2;
return strcmp (s1->word, s2->word);
}
int cmp_counts (const void *p1, const void *p2)
{
const struct wc_s *s1 = p1;
const struct wc_s *s2 = p2;
return s2->count - s1->count;
}
...
struct wc_s *wc_list = malloc (MAX * sizeof *wc_list);
...
qsort (wc_list, MAX, sizeof *wc_list, cmp_counts);
If qsort() was guaranteed to perform a stable sort (i.e. two elements that compare the same retain their original order), you could solve your problem by first sorting by word, and then sorting by count. Unfortunately, the resulting order of two equal elements is unspecified.
What you could do is sort the array by count, and then go through the array to find sub-arrays with the same counts, and sort those individually:
int start = 0;
int length;
while (start < MAX) {
for (length = 1; start+length < MAX; length++) {
if (wc_list[start].count != wc_list[start+length].count)
break;
}
qsort (wc_list+start, length, sizeof *wc_list, cmp_words);
start += length;
}
Okay so I need to several quite long strings in C. So I say to myself "why, you'd better use that handy dandy qsort function! Better write yourself a string_comparator for it!"
So of course I do and here she is:
int string_comparator(const void* el1, const void* el2) {
char* x = (char*) el1;
char* y = (char*) el2;
int str_len = strlen(x);
int i = 0;
for (; i < str_len; i++) {
//when there are non-equal chars
if (x[i] != y[i]) {
break;
}
}
return x[i] - y[i];
}
So of course I pass my handy dandy string_comparator function to the C qsort function as such:
qsort(list.words, list.num_words, sizeof(char*), string_comparator);
list is a struct that holds a char** (words) and ints which refer to the number of words held by it (such as num_words)
Now I have the problem where my list is not getting sorted alphabetically like I had hoped! I put a bunch of printf statements in my comparator and it printed out garbage values for the strings every time so I'm fairly sure that is the problem. But why is that the problem?? I've used qsort before (never to sort words..just sorting characters) and from what I understand this should work...What's going wrong here?
I appreciate any suggestions!
This is a common mistake when using qsort(). Here are the corrections:
char *x = *(char **) el1;
char *y = *(char **) el2;
Because list.words has type char **, not type char *, right?
Another example of qsort()
Here's how you sort an array of int with qsort():
int int_comparator(const void *el1, const void *el2)
{
int x = *(int *) el1;
int y = *(int *) el2;
return x - y;
}
void sort_ints(int *a, size_t n)
{
// these two lines are both "correct"
// the second line is more "obviously correct"
// qsort(a, n, sizeof(int), int_comparator);
qsort(a, n, sizeof(*a), int_comparator);
}
Now, if you go through and replace int with char *, you have to replace int * with char **.
I've got about 12000 pre known values that I need to place in an array early in the program. Given certain circumstances, I will later need to resize this array with realloc. Is there any way to initialize an array with malloc/calloc with values, or fill an array with several other values?
You cannot initialize a malloced array this way, your best chance is to have it statically in your program, and copy it to a malloced array at the beginning of the run, e.g.:
static int arr[] = {1,2,3,4};
static int * malloced_arr;
// in the init function
malloced_arr = malloc(sizeof(arr));
if (malloced_arr)
{
memcpy(malloced_arr, arr, sizeof(arr));
}
This is the sort of thing that zero length arrays are useful for. For example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct values {
int x[4];
int y[0];
} V = { {1, 2, 3} };
int
main( int argc, char ** argv )
{
int *t;
int i;
struct values *Y;
(void) argc; (void) argv;
/* Allocate space for 100 more items */
Y = malloc( sizeof *Y + 100 * sizeof *Y->y );
t = Y->x;
memcpy( Y, &V, sizeof V );
t[3] = 4;
for( i = 0; i < 4; i++ )
printf( "%d: %d\n", i, t[ i ]);
return 0;
}
Of course, this is really just a parlor trick that gains you nothing over Binyamin's solution, and introduces a lot of totally unnecessary obfuscation.