Generic swap function using pointer to char in C - c

I don't understand so well how this code works:
#include <stdio.h>
void gswap(void* ptra, void* ptrb, int size)
{
char temp;
char *pa = (char*)ptra;
char *pb = (char*)ptrb;
for (int i = 0 ; i < size ; i++) {
temp = pa[i];
pa[i] = pb[i];
pb[i] = temp;
}
}
int main()
{
int a=1, b=5;
gswap(&a, &b, sizeof(int));
printf("%d , %d", a, b)
}
What I understand is that char has 1 byte(size) in memory and we are using pointers to swap each byte of the int value(4 bytes).
But in the end, how it is possible to dereference a char pointer to int value?

Let's try and figure this out, step by step, with code comments
#include <stdio.h>
//gswap() takes two pointers, prta and ptrb, and the size of the data they point to
void gswap(void* ptra, void* ptrb, int size)
{
// temp will be our temporary variable for exchanging the values
char temp;
// We reinterpret the pointers as char* (byte) pointers
char *pa = (char*)ptra;
char *pb = (char*)ptrb;
// We loop over each byte of the type/structure ptra/b point too, i.e. we loop over size
for (int i = 0 ; i < size ; i++) {
temp = pa[i]; //store a in temp
pa[i] = pb[i]; // replace a with b
pb[i] = temp; // replace b with temp = old(a)
}
}
int main()
{
// Two integers
int a=1, b=5;
// Swap them
gswap(&a, &b, sizeof(int));
// See they've been swapped!
printf("%d , %d", a, b);
}
So, basically, it works by going over any given datatype, reinterpreting as bytes, and swapping the bytes.

Related

Problem with storing value in pointer address

I managed to put the value in the pointer while in the function, However when i come back to the main i just dont get the values. Where am i wrong? sending parameters wrong? wrong allocation? Here's the code:
bool wc(int* nlines, int* nwords, int* nchars)
{
int lines=5,chars=6,words=7;
nchars = (int *) malloc(chars*sizeof(int));
*nchars = chars;
nlines = (int *) malloc(lines*sizeof(int));
*nlines = lines;
nwords = (int *) malloc(words*sizeof(int));
*nwords = words;
}
int main() {
int* chars; int* words; int* lines;
int res = wc(&lines,&words,&chars);
printf("%d %d %d\n",chars,lines,words);
return 0;
}
If all you want to do is be able to set 3 int values inside a function then this is how I would so it.
#include <stdio.h>
#include <stdbool.h>
bool wc(int* nlines, int* nwords, int* nchars)
{
int lines=5,chars=6,words=7;
*nchars = chars;
*nlines = lines;
*nwords = words;
return true;
}
int main() {
int lines = 0;
int words = 0;
int chars = 0;
int res = wc(&lines,&words,&chars);
printf("%d %d %d\n",chars,lines,words);
return 0;
}
If for some reason you must use pointers as shown in your example then this will do what you want.
#include <stdio.h>
#include <stdbool.h>
bool wc(int** nlines, int** nwords, int** nchars)
{
int lines=5,chars=6,words=7;
*nchars = malloc(sizeof(int));
**nchars = chars;
*nlines = malloc(sizeof(int));
**nlines = lines;
*nwords = malloc(sizeof(int));
**nwords = words;
return true;
}
int main() {
int* chars; int* words; int* lines;
int res = wc(&lines,&words,&chars);
printf("%d %d %d\n",*chars,*lines,*words);
free(chars);
free(words);
free(lines);
return 0;
}
As you can see this just means you need to add a bunch more * all over the place.
In C function input variables are passed by value, not reference. So when you assign them locally, the value in the caller scope is unaffected. E.g.
void foo(int a) {
a = 5;
}
int main() {
int b = 3;
foo(b);
// here, b is still 3
}
This is exactly what you are doing in your example, though your variables are not int, but int*.
If your input variable is a pointer though, you can change the memory that the variable points to, and this will obviously reflect in the calling scope. E.g.
void foo(int *a) {
*a = 5;
}
int main() {
int b = 3;
foo(&b);
// here, b is 5
}
In your case, you want to allocate pointers, so you want your function signature to be a pointer to a pointer. E.g.
void foo(int **a) {
*a = malloc(sizeof(int));
}
int main() {
int* b = NULL;
foo(&b);
// here, b is allocated to a valid heap area
free(b);
}

how to make a qsort function and sort array of pointers to structs

i'm trying to make a qsort function from scratch that sorts an array of pointers to structs
this is the code i have right now
static void swap(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
void _qsort(void* list, int list_len, int left, int right,
int(*comp)(const struct shpg_item *a, const struct shpg_item *b)) {
void *vt, *v3;
int i, last, mid = (left + right) / 2;
if (left >= right)
return;
void* vl = (char*)(list + (left * list_len));
void* vr = (char*)(list + (mid * list_len));
swap(vl, vr);
last = left;
for (i = left + 1; i <= right; i++) {
// vl and vt will have the starting address
// of the elements which will be passed to
// comp function.
vt = (char*)(list + (i * list_len));
if ((*comp)(vl, vt) > 0) {
++last;
v3 = (char*)(list + (last * list_len));
swap(vt, v3);
}
}
v3 = (char*)(list + (last * list_len));
swap(vl, v3);
_qsort(list,list_len, left, last - 1, comp);
trace_int(1);
_qsort(list, list_len, last + 1, right, comp);
}
void list_sort(struct shpg_item **list, int list_len,
int(*comp)(const struct shpg_item *a, const struct shpg_item *b)) {
_qsort(*list,list_len,0,(list_len-1),comp);
}
but this gives a segmentation fault error , can any one tell me why and help me ?
void * pointer addition
void * pointer addition is undefined behavior. But since the usual UB is OK, this may or may not be OP's trouble.
void _qsort(void* list, int list_len, int left, ...
...
(list + (left * list_len)) // UB
Instead recommend casting before addition.
// void* vl = (char*)(list + (left * list_len));
void* vl = ((char*) list) + (left * list_len);
Other issues may exist
I haven't check the entire code but your swap function seems wrong. Depending on the comment lines in your code;
// vl and vt will have the starting address
// of the elements which will be passed to
// comp function.
if (list + (left * list_len)) and (list + (last * list_len)) are pointers to be swapped (pointers to a string or a struct, for example), your swap function decoration & your caller line should read as:
Swapping two integers, floats, doubles, etc (in general swapping values only):
void swap(int *a, int *b) {
int t = *a;
*a = *b;
*b = t;
}
...
int x = 5;
int y = 3;
swap(&x, &y);
If you need to swap two pointers (a char * string or another type of pointer pointing to a struct), you can just swap pointer values without swapping the content pointed in the actual memory:
void swap(void **a, void **b) {
void *t = *a;
*a = *b;
*b = t;
}
...
char *x = "some string";
char *y = "some other string";
swap(&x, &y);
I've included a working example in the middle part of this answer, and also added an example using qsort.
Taking a quick look at the code I see problem here:
void _qsort(void* list, ...
Since list is an array of pointers it should be:
void _qsort(void** list, ...
or
void _qsort(void* list[], ...
With this declaration, pointer arithmetic will not be an issue, for example, list+3 == &list[3] == pointer to the 3rd pointer in the array. There's no need to cast list, as void** list will work fine in the main part of the code. The only code that will do any casting is the caller's compare function.
You can choose to emulate qsort's compare function parameters using type void **: compare(list+i, list+j), but it would be simpler to use type void *: compare(list[i], list[j]).
Swap should use void** as parameters. The call would be
swap(list+i, list+j)
/* ... */
void swap(void **i, void **j){
void * t;
t = *i;
*i = *j;
*j = t;
}
There are some comments about a void pointer possibly having a different size than a struct pointer or any type of data pointer, and that this could cause an issue. If this was true, then the C library function qsort() would not work because the first parameter for qsort is a void pointer, which will result in the caller's pointer being cast to a void pointer. In the caller's compare function, both parameters are const void pointers which the caller's compare function has to cast to the actual pointer types. With qsort() and the caller's compare function, parameters are being cast both to and from void pointers without issue.
C guarantees that a void pointer can be used to hold any type of data pointer, so in essence a void pointer is a generic data pointer (in 16 bit segment or selector environments, a generic "near" data pointer).
This is a working example, using typical Lomuto partition scheme (pivot = a[hi]):
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int data;
char name[32];
}XMPL;
int cmpr(void * pi, void *pj)
{
if(((XMPL *)pi)->data < ((XMPL *)pj)->data)
return -1;
if(((XMPL *)pi)->data > ((XMPL *)pj)->data)
return 1;
return 0;
}
void swap(void **i, void **j){
void * t;
t = *i;
*i = *j;
*j = t;
}
void QuickSort(void **a, int lo, int hi, int(*cmpp)(void *, void *))
{
void *p;
int i, j;
while(lo < hi){
p = a[hi];
i = lo;
for(j = lo; j < hi; ++j){
if((cmpp(a[j], p) < 0)){
swap(a+i, a+j);
++i;
}
}
swap(a+i, a+hi);
if(i - lo <= hi - i){ /* avoid stack overflow */
QuickSort(a, lo, i-1, cmpp);
lo = i+1;
} else {
QuickSort(a, i+1, hi, cmpp);
hi = i-1;
}
}
}
#define COUNT (1024)
int main(int argc, char**argv)
{
XMPL *ax; /* array of structures */
XMPL **pax; /* array of pointers to structures */
int i;
ax = malloc(COUNT * sizeof(XMPL));
pax = malloc(COUNT * sizeof(void **));
for(i = 0; i < COUNT; i++){ /* init structs, array of ptrs */
ax[i].data = rand();
pax[i] = ax+i;
}
QuickSort(pax, 0, COUNT-1, cmpr);
for(i = 1; i < COUNT; i++){
if(pax[i-1]->data > pax[i]->data){
break;
}
}
if(i == COUNT)
printf("passed\n");
else
printf("failed\n");
free(pax);
free(ax);
return(0);
}
Hoare parition scheme will probably be a bit faster. However, in this case, merge sort should be faster than quick sort. Merge sort does more moves but fewer compares than quick sort, and in this case, only pointers are being moved, while the compare involves an indirection via a pointer and a call to a compare function via a pointer.
Same basic code, but using qsort. Note that the cmpr() function needed one more dereference for each parameter.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int data;
char name[32];
}XMPL;
int cmpr(const void * pi, const void *pj)
{
if((*(XMPL **)pi)->data < (*(XMPL **)pj)->data)
return -1;
if((*(XMPL **)pi)->data > (*(XMPL **)pj)->data)
return 1;
return 0;
}
#define COUNT (1024)
int main(int argc, char**argv)
{
XMPL *ax; /* array of structures */
XMPL **pax; /* array of pointers to structures */
int i;
ax = malloc(COUNT * sizeof(XMPL));
pax = malloc(COUNT * sizeof(void **));
for(i = 0; i < COUNT; i++){ /* init structs, array of ptrs */
ax[i].data = rand();
pax[i] = ax+i;
}
qsort(pax, COUNT, sizeof(XMPL *), cmpr);
for(i = 1; i < COUNT; i++){
if(pax[i-1]->data > pax[i]->data){
break;
}
}
if(i == COUNT)
printf("passed\n");
else
printf("failed\n");
free(pax);
free(ax);
return(0);
}

Trying to swap multiple values in a user entered array

I am trying to take a user entered array and swap the 0th value with the 7th, 8th value with the 3rd and the 0th with the 14th value. I have to use a function to swap which is where i think i messed up. When i compile it says to few arguments for function swap. also, its my 1st time using pointers so i wouldn't be surprised if there errors with that,. this is what i have, thanks!
#include <stdio.h>
void swap (int a[15], int *p, int *q, int *r ,int *s , int*t) {
int temp;
p = &a[0];
q = &a[7];
r = &a[8];
s = &a[3];
t = &a[14];
temp = *p;
*p = *q;
*q = temp;
temp = *r;
*r = *s;
*s = temp;
temp = *t;
*t = *p;
*p = temp;
}
int main (int argc, char *argv[]) {
int a[15], i;
printf(" Enter 15 integers: ");
for (i=0; i <15; i++)
swap(a);
printf(" Swapped array:\n %d", a[15]);
return 0;
}
Its not an error related to pointers.
You called swap() with one argument, like this swap(a);
And while defining it you have more then one arguments. Like
void swap (int a[15], int *p, int *q, int *r ,int *s , int*t) {
...
You do not need those extra arguments in the function definition.
Just change it to,
void swap (int a[15]) {
int temp;
int* p = &a[0];
int* q = &a[7];
int* r = &a[8];
int* s = &a[3];
int* t = &a[14];
...
A much better approach would be define a general function swap() and call it with proper required arguments multiple times when required.
void swap(int *p, int *q)
{
int tmp = *p;
*p = *q;
*q = tmp;
}
Call the above API something like
swap (&a[0], &a[7])
swap (&a[8], &a[3])
...
..

C qsort() with dynamic n by 2 multi-dimensional array

First, I defined a dynamic array with 2 columns and 10 row. The integer number is set to 10 here just for example.
int** array;
int number = 10;
array = malloc(number * sizeof(int*));
for (i = 0; i < number; i++)
array[i] = malloc(2 * sizeof(int));
Then I try to use qsort() on it.
qsort( array, number, sizeof array[0], compare );
This is my compare function. It sorts by the integer values in the first column, then sorts by the second column while preserving the order in the first column. E.g. "0 2, 1 7, 0 1" will become "0 1, 0 2, 1 7".
int compare ( const void *pa, const void *pb ) {
int (*a)[1] = pa;
int (*b)[1] = pb;
if ( (a[0][0] < b[0][0]) || (a[0][0] == b[0][0])&&(a[1][0] < b[1][0]) ) return -1;
if ( (a[0][0] > b[0][0]) || (a[0][0] == b[0][0])&&(a[1][0] > b[1][0]) ) return +1;
return 0;
}
Question
This worked with a static array. I know it doesn't work now because I have a dynamic array, which is an array of pointers.
How can I adapt this code to work with the dynamically created multi-dimensional array?
sample code
#include <stdio.h>
#include <stdlib.h>
int compare ( const void *pa, const void *pb ) {
const int *a = *(const int **)pa;
const int *b = *(const int **)pb;
if(a[0] == b[0])
return a[1] - b[1];
else
return a[0] - b[0];
}
/*
#define NUMCMP(x,y) (((x) < (y)) ? -1 : ((x) > (y)) ? 1 : 0)
int compare ( const void *pa, const void *pb ) {
const int (*a)[2] = *(const int (**)[2])pa;
const int (*b)[2] = *(const int (**)[2])pb;
int tmp;
if((tmp=NUMCMP((*a)[0], (*b)[0]))==0)
return NUMCMP((*a)[1], (*b)[1]);
else
return tmp;
}
*/
int main(void){
int **array;
int number = 10;
int i;
array = malloc(number * sizeof(int*));
for (i = 0; i < number; i++){
array[i] = malloc(2 * sizeof(int));
array[i][0] = rand()%20;
array[i][1] = rand()%20;
}
for(i = 0;i < number;++i)
printf("%2d, %2d\n", array[i][0], array[i][1]);
printf("\n");
qsort(array, number, sizeof array[0], compare);
for(i = 0;i < number;++i)
printf("%2d, %2d\n", array[i][0], array[i][1]);
return 0;
}
what *(const int **)pa
array = {(int *), (int *), (int *), ... , (int *) }
qsort need each element address for element (for swap, etc. Because the size and number and start address of the element since only the given information).
E.g &(int *), &(int *)
so (int **) pass to function compare.
call compare(int **, int **) &(int*) meant at arg int**
compare function prototypeis cmp(const void*, const void*)
cast (const int**)pa is cast to passed original pointer.
*((const int **)pa) is dereference original element pointer(int*)
Since you now have an array of pointers, the arguments to your comparison function are going to be pointers to pointers. Use them like this:
int *const *a = pa;
int *const *b = pb;
Now you have a and b as two pointers into the array you're sorting. Each one points to a single element that the sort function is asking you to examine. You can access these elements as *a and *b or a[0] and b[0] but should not ever use a[1] or b[1]. If the sort function asks you to compare the first element in the array (*a) and the fifth element in the array (*b), a[1] and b[1] are the second and sixth elements of the array - completely irrelevant to the comparison you're supposed to be doing.
After the first level of dereferencing, you're allowed to do whatever you need to do to examine the elements being compared. Since your array elements are themselves pointers to arrays (of 2 int each), the ints can be accessed as a[0][0] a[0][1] b[0][0] b[0][1]. Notice this is the opposite order from your a[1][0] and b[1][0].
Writing them as (*a)[0] would provide a reminder that the first level of indirection is a "single-element-access-only" pointer. I'm undecided on whether this makes the whole thing clearer.
I came across this thread in search of a ditto problem of mine, and I lastly end-up doing the below thing.
static int compareMatrixElements(const void *p1, const void *p2)
{
return ((*(int const *) p1) - (*(int const *) p2));
}
void sortMatrix(int** matrix, int r, int c)
{
int sort_matrix[r][c];
for(int i = 0; i < r; i++) {
memcpy(sort_matrix[i], matrix[i], c * sizeof(int));
}
qsort(sort_matrix, r*c, sizeof(int), compareMatrixElements);
for(int i = 0; i < r; i++) {
memcpy(matrix[i], sort_matrix[i], c * sizeof(int));
}
}
In the above code of mine I used qsort API directly, one can use this api or any other sort algo on a contiguous memory, but what If you are having a matrix whose rows are pointer to the memory of its columns (like in my case as well as described in the question of this thread). Hence I copied such matrix into a contiguous memory, ran sort on that contiguous memory and copied back the sorted elements to the matrix.
The above solution worked for me, I thought it might be helpful others so I posted it, suggest any improvement for the same.
const int *a = *(const int **)pa;
const int *b = *(const int **)pb;
#BLUEPIXY, this is not correct.
Just enough
const int *a = pa;
const int *b = pb;
becouse pa is const void * (array[0]) and it very well cast to const int *
const int (*a)[2] = *(const int (**)[2])pa;
const int (*b)[2] = *(const int (**)[2])pb;
#BLUEPIXY, this is not correct. Just enough
const int (*a)[2] = (int(*)[])pa;
const int (*b)[2] = (int(*)[])pb;
sizeof array[0] will be "2 * sizeof(int)", for this static array.
int array[10][2];
sizeof array[0] will be "sizeof(int*)", for this pointer-to-pointer.
sizeof array[0][0] will be "sizeof(int)", for this pointer-to-pointer.
int **array;
So, First thing is you cannot use "qsort( array, number, sizeof array[0], compare );" in case of pointer-to-pointer implementation.

correct way to change values of c pointers

Sorry, another C pointer question.. I have a function func() that sorts an array, then get the largest and smallest integers. I'm trying to put them inside pointer variables in main() but the values are only correct inside the func() function. I don't understand why :(
#include <stdio.h>
void func(int arr[], int *s, int *l, int n){
int i = 1;
for(; i < n; i++){
int temp = arr[i];
int n = i;
while( n > 0 && arr[n-1] > temp){
arr[n] = arr[n-1];
n--;
}
arr[n] = temp;
}
l = &arr[n-1];
s = &arr[0];\
printf("%d %d\n",*l,*s);
}
int main(void){
int arr[] = {1,2,9,3,58,21,4};
int *s, *l;
int size = 7;
func(arr,s,l,size);
printf("%d %d\n",*l,*s);
}
When you pass a pointer as an argument to a function in C, a copy of the pointer is made. Thus, changing the value of the pointer has no effect outside of that function. However, changing the value at the memory referenced by the pointer will take effect everywhere, as you want. In your case, you would need to do this:
void func(int arr[], int *s, int *l, int n){
// sorting code..
// l = &arr[n-1]; WRONG - these change the value of the pointer,
//s = &arr[0];\ without changing the value of the memory they reference
*l = arr[n-1]; // CORRECT - changes the value at the referenced memory
*s = arr[0];
printf("%d %d\n",*l,*s);
}
Of course, the way you're using the pointers in main is also incorrect; they're uninitialized and likely to cause a segmentation fault. Since there appears to be no reason to use actual int* variables over ordinary int variables there, we can take another approach to passing them "by reference":
int main(void){
int arr[] = {1,2,9,3,58,21,4};
// int *s, *l; WRONG - we don't need pointers, we need to pass regular ints
int s, l;
int size = 7;
// Get the address of our variables with the address-of (&) operator
// This effectively creates int* variables out of our int variables
func(arr, &s, &l,size);
printf("%d %d\n",*l,*s);
}
Note that the term "by reference" here is not correct in the true sense of the phrase, since you are still receiving a copy of the address associated with the variable. Most languages provide a true by-reference faculty by removing this distinction and only allowing you access to the variable and its value, with the copying somewhat out of sight of the programmer. You can think of this as being "by reference with respect to l and s inside main", in the sense that their values can change due to the called function.
You need to pass the address of the pointer variables if you want to change what they are pointing at, otherwise a copy of the pointer variable is being changed inside the function (and is why it is correct within the function):
void func(int arr[], int** s, int** l, int n){
/* snip */
*l = &arr[n-1];
*s = &arr[0];
}
func(arr, &s, &l, size);
This would leave s and l pointing to elements of the array arr. If you just wanted the values of integers then the alternative would be to define int variables in main() and pass their addresses to func() and copy the relevent values from the array:
void func(int arr[], int* s, int* l, int n){
/* snip */
*l = arr[n-1];
*s = arr[0];
}
int s, l;
func(arr, &s, &l, size);
See this question from the C FAQ.
Your pointers are not initialized. You have two solutions:
use integers in main function (and eventually, although useless, make pointers point to them in the same function);
dynamically allocate memory for your pointer.
Easiest code:
#include <stdio.h>
int main(void)
{
int arr[] = {1, 2, 9, 3, 58, 21, 4};
int s, l;
int size = 7;
func(arr, &s, &l, size);
printf("%d %d\n", l, s);
}
In the current code, you don't need to make l and s point to the case of the array. So, as Dan F stated, you can just do integer's assignment.
void func(int arr[], int *s, int *l, int n)
{
int i = 1;
for(; i < n; i++){
int temp = arr[i];
int n = i;
while( n > 0 && arr[n-1] > temp){
arr[n] = arr[n-1];
n--;
}
arr[n] = temp;
}
*l = arr[n-1];
*s = arr[0];
printf("%d %d\n", *l, *s);
}

Resources