Bubble Sort Trouble - c

gcc compiles the following code without error. I'm creating a bubble sort function that can be used with arrays of any data type (hence the function pointer).
It sorts the array of character strings (arr2) without a problem, however, I can't figure out why it won't properly sort the array of integers (arr). I added a printf statement in the compare_long function to see what is going on. It doesn't look like the integers are being passed to it properly. Any help will be greatly appreciated.
#include <stdio.h>
#include <string.h>
#define MAX_BUF 256
long arr[10] = { 3,6,1,2,3,8,4,1,7,2};
char arr2[5][20] = { "Mickey Mouse",
"Donald Duck",
"Minnie Mouse",
"Goofy",
"Pluto" };
void bubble(void *p, int width, int N, int(*fptr)(const void *, const void *));
int compare_string(const void *m, const void *n);
int compare_long(const void *m, const void *n);
int main(void) {
int i;
puts("\nBefore Sorting:\n");
for(i = 0; i < 10; i++) { /* show the long ints */
printf("%ld ",arr[i]);
}
puts("\n");
for(i = 0; i < 5; i++) { /* show the strings */
printf("%s\n", arr2[i]);
}
bubble(arr, 4, 10, compare_long); /* sort the longs */
bubble(arr2, 20, 5, compare_string); /* sort the strings */
puts("\n\nAfter Sorting:\n");
for(i = 0; i < 10; i++) { /* show the sorted longs */
printf("%d ",arr[i]);
}
puts("\n");
for(i = 0; i < 5; i++) { /* show the sorted strings */
printf("%s\n", arr2[i]);
}
return 0;
}
void bubble(void *p, int width, int N, int(*fptr)(const void *, const void *)) {
int i, j, k;
unsigned char buf[MAX_BUF];
unsigned char *bp = p;
for(i = N - 1; i >= 0; i--) {
for(j = 1; j <= i; j++) {
k = fptr((void *)(bp + width*(j-1)), (void *)(bp + j*width));
if(k > 0) {
memcpy(buf, bp + width*(j-1), width);
memcpy(bp + width*(j-1), bp + j*width , width);
memcpy(bp + j*width, buf, width);
}
}
}
}
int compare_string(const void *m, const void *n) {
char *m1 = (char *)m;
char *n1 = (char *)n;
return (strcmp(m1,n1));
}
int compare_long(const void *m, const void *n) {
long *m1, *n1;
m1 = (long *)m;
n1 = (long *)n;
printf("m1 = %l and n1 = %l\n", *m1, *n1);
return (*m1 > *n1);
}

The ANSI C spec defines long as a MINIMUM of 4 bytes (32 bits) but GCC is defining long as 8 bytes in your case. It is architecture-specific so you need to use sizeof(long) or one of the C99 types like uint32_t or int32_t if you want a specific size.

Related

How can I access my array via the sort function?

I have this project where I need to create an array, split it into two, and then sort each array using its own thread, then merge the two arrays back into a single array. Thankfully, the final array doesn't need to be sorted itself.
I wrote this code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
//Change length of main input array
const int arrLen = 20;
const int mid = arrLen/2;
void swap(int *a, int *b){
int temp = *a;
*a = *b;
*b = temp;
}
void *sort(void *arg){
int min_pos;
for(int a=0; a<arrLen-1; a++){
min_pos = a;
for(int b=a+1; b<arrLen; b++){
if(array[b] < array[min_pos]){
min_pos = b;
}
}
swap(&array[min_pos], &array[a]);
}
}
void printResult(int array[]){
for(int k=0; k<arrLen/2; k++){
printf("Num%d: %d\n", k, array[k]);
}
}
//Adds random values to each position in a given array
void arrayCreator(int array[]){
int random;
for(int i=0; i<arrLen; i++){
random = rand() % 100;
array[i] = random;
}
}
void main(){
printf("Program Initialized...\n");
int mainArray [arrLen], firstHalf[mid], secondHalf[mid], random;
time_t t;
srand((unsigned) time(&t));
//Populate mainArray
for(int i=0; i<arrLen; i++){
mainArray[i] = rand()%100;
}
printf("Array created...\n");
//Split mainArray[] into two seperate arrays
for(int p=0; p<arrLen; p++){
if(p<mid){
firstHalf[p]=mainArray[p];
}
else{
secondHalf[p-mid]=mainArray[p];
}
}
pthread_t tid1;
pthread_t tid2;
pthread_create(&tid1, NULL, sort, (void*)firstHalf);
//pthread_create(&tid2, NULL, sort, secondHalf);
printResult(firstHalf);
//printResult(secondHalf);
}
How can I get the sort function to access my array?
First, I would look at the signature of the standard function qsort and provide the same interface for your sort function. I'd also rename it into bubble_sort since it's doing bubble sorting. Your function would then look like this:
void bubble_sort(void *ptr, size_t arrLen, size_t elem_size,
int (*comp)(const void *, const void *)) {
char *array = ptr; // to be able to do pointer arithmetic
for (size_t a = 0; a < arrLen - 1; a++) {
for (size_t b = a + 1; b < arrLen; b++) {
if (comp(array + a * elem_size, array + b * elem_size) > 0) {
swap(array + a * elem_size, array + b * elem_size, elem_size);
}
}
}
}
elem_size is the size of the elements you want to sort, which will be set to sizeof(int) later.
comp is a function taking two void* and returns an int where ...
< 0 means *a < *b
> 0 means *a > *b
== 0 means *a == *b
swap also takes the elem_size parameter to be able to swap objects of any size. Implemented, it could look like this:
void swap(void *a, void *b, size_t elem_size) {
char tmp[elem_size];
memcpy(tmp, a, elem_size);
memcpy(a, b, elem_size);
memcpy(b, tmp, elem_size);
}
Now, you can't start a thread by calling bubble_sort directly. A thread start routine only takes a single void* as an argument so we need some way of passing all the necessary arguments on. We can package them in a struct like this:
struct sort_thread_args {
pthread_t tid;
void *array;
size_t arrLen;
size_t elem_size;
int (*comp_func)(const void *, const void *);
};
void *sort_thread(void *arg) { // the thread start routine
struct sort_thread_args *ta = arg;
bubble_sort(ta->array, ta->arrLen, ta->elem_size, ta->comp_func);
return NULL;
}
As can be seen above, the struct contains all the necessary information to call bubble_sort + the thread id, which I've stored there for convenience only. It's not needed by the thread itself.
The above functions are type agnostic so you can use these to sort any contiguous array, either by calling bubble_sort directly or in a thread.
Since you'll be using this to sort arrays of int, we need a comparison function for ints which does what was described above:
int comp_int(const void *va, const void *vb) {
const int *a = va;
const int *b = vb;
if (*a < *b) return -1;
if (*a > *b) return 1;
return 0;
}
Then for sorting half the array in one thread and the other half in another thread, I suggest that you don't copy the contents of mainArray to new arrays. Just leave the content in mainArray and tell each thread where to start sorting and how many elements it should sort.
Example:
#define Size(x) (sizeof(x) / sizeof *(x))
int main() {
srand((unsigned)time(NULL));
puts("Program Initialized...");
int arrLen = 35; // just an example to show that it handes uneven amounts too
int mainArray[arrLen];
// Populate mainArray
for (size_t i = 0; i < Size(mainArray); i++) {
mainArray[i] = rand() % 100;
}
puts("Array created...");
// print the created array
for (size_t i = 0; i < Size(mainArray); ++i) printf("%2d ", mainArray[i]);
putchar('\n');
puts("Running sorting threads...");
struct sort_thread_args ta[2]; // 2 for 2 threads
for (size_t i = 0; i < Size(ta); ++i) {
// element index for where this thread should start sorting:
size_t base = i * Size(mainArray) / Size(ta);
// prepare the arguments for this thread:
ta[i] = (struct sort_thread_args) {
.array = mainArray + base, // points at the first element for this thread
.arrLen = (i + 1) * Size(mainArray) / Size(ta) - base,
.elem_size = sizeof(int),
.comp_func = comp_int // the comparison function we made above
};
// and start the thread:
pthread_create(&ta[i].tid, NULL, sort_thread, &ta[i]);
}
puts("Joining threads");
for (size_t i = 0; i < Size(ta); ++i) {
pthread_join(ta[i].tid, NULL);
}
puts("Result:");
for (size_t i = 0; i < Size(mainArray); ++i) printf("%2d ", mainArray[i]);
putchar('\n');
}
Demo
Simply assign arg to your array variable in order to convert from void * to int *.
void *sort(void *arg){
int min_pos;
int *array = arg;
for(int a=0; a<arrLen-1; a++){
min_pos = a;
for(int b=a+1; b<arrLen; b++){
if(array[b] < array[min_pos]){
min_pos = b;
}
}
swap(&array[min_pos], &array[a]);
}
}

How to print void * array with printf when length, element size and format are known?

I've tried it this way. Then got rubbish in the output and figured out that I'm doing it the wrong way.
#include "stdlib.h"
#include "stdio.h"
/*
* Prints array from the anonymous array pointer.
*
* Returns 0 on success.
* Return -1 on failure.
*/
int print_array(const void *arr, size_t arr_len,
size_t elem_size, const char *format) {
for (size_t i = 0; i < arr_len; ++i)
if (printf(format, (char *) arr + i * elem_size) < 0)
return -1;
printf("\n");
return 0;
}
// Usage example
int main() {
const int n = 3;
int arr[n];
for (int i = 0; i < n; ++i)
arr[i] = i;
print_array(arr, n, sizeof(int), "%d ");
}
My code is supposed to work with different possible types. The type is actually deduced somewhere in the beginning of the execution and then this minimal description is used. Such trick nicely works with scanf as it takes pointer to an element rather than the element itself.
Such complexity is needed to conform the open-closed priciple and therefore minimise the number of swithes and conditionals in the code. I'm trying to concentrate actual type deducing in one place only.
I guess the same thing as with scanf should be possible somehow because printf is actually a variadic function which can take any values and parse them during runtime. Abusing "stdarg.h" might help somehow.
Of course I would like to have the solution that is not compiler-specific.
Instead of passing a formatting string, pass a function to print it, allowing the user to do whatever he wants/needs to print the actual data.
int print_array(const void *arr, size_t arr_len, size_t elem_size,
int (*print_elem)(const void *el, void *cookie), // I would add FILE* argument
void *cookie // allow users to pass additional context if they wanna
) {
for (size_t i = 0; i < arr_len; ++i) {
if (print_elem((char*)arr + i * elem_size, cookie) < 0) {
return -1;
}
}
printf("\n");
return 0;
}
int print_int(const void *el, void *cookie) {
return printf("%d", *(int*)el);
}
// print and allow users to pass options
int print_int_with_width(const void *el, void *cookie) {
int width = *(int*)cookie;
return printf("%*d", width, *(int*)el);
}
int arr[5];
int main() {
print_array(arr, 5, sizeof(int), print_int, NULL);
int width = 5;
print_array(arr, 5, sizeof(int), print_int_with_width, &width);
}
int print_array(const char *format, const void *arr, size_t arr_len, size_t elem_size, int fp)
{
const uint8_t *uarr = arr;
uint8_t u8;
uint16_t u16;
uint32_t u32;
uint64_t u64;
float f; double d;
int result;
for (size_t i = 0; i < arr_len; ++i)
{
switch(elem_size)
{
case 1:
memcpy(&u8, uarr + i, 1);
result = printf(format, u8);
break;
case 2:
memcpy(&u16, uarr + i * 2, 2);
result = printf(format, u16);
break;
case 4:
if(fp)
{
memcpy(&f, uarr + i * 4, 4);
result = printf(format, f);
}
else
{
memcpy(&u32, uarr + i * 4, 4);
result = printf(format, u32);
}
break;
case 8:
if(fp)
{
memcpy(&d, uarr + i * 8, 8);
result = printf(format, d);
}
else
{
memcpy(&u64, uarr + i * 8, 8);
result = printf(format, u64);
}
break;
default:
result = -1;
break;
}
}
return result;
}
// Usage example
int main()
{
const int n = 3;
int arr[n];
double arrd[3];
for (int i = 0; i < n; ++i)
{
arr[i] = i;
arrd[i] = 1.1 * i;
}
print_array("%d\n", arr, n, sizeof(*arr), 0);
print_array("%f\n", arrd, n, sizeof(*arrd), 1);
}
typedef int (*print_fn)(char*,void*);
int print_char (char *fmt, void *c) { return printf(fmt, *((char*) c)); }
int print_int (char *fmt, void *i) { return printf(fmt, *((int*) i)); }
int print_float (char *fmt, void *f) { return printf(fmt, *((float*) f)); }
int print_str (char *fmt, void *str) { return printf(fmt, *((char**) str)); }
// add more types here
int print_array (
void *arr,
size_t arr_len,
size_t elem_size,
char* fmt,
print_fn print_elem
){
for (void *end = arr + arr_len * elem_size; arr < end; arr += elem_size)
if (print_elem(fmt, arr) < 0)
return -1;
return 0;
}
Another way using a macro, you don't need to pass the size of each element:
#include <stdio.h>
#define print_array(format, array, elems) \
do { \
for (int ___ = 0; ___ < elems; ___++) \
printf(format, array[___]); \
printf("\n"); \
} while (0)
int main (void)
{
char *str[] = {"one", "two", "three"};
print_array("%s ", str, 3);
int arr[] = {1, 2, 3};
print_array("%d ", arr, 3);
return 0;
}
I use ___ as iterator to prevent shadowing/poluting variable names.
The advantage over a void * attached to a callback is that the compiler can detect wrong format specifiers, i.e. passing "%s " for the array of ints returns:
demo.c: In function ‘main’:
demo.c:16:22: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
16 | print_array(arr, "%s ", 3);
| ^~~~~
demo.c:6:16: note: in definition of macro ‘print_array’
6 | printf(format, array[___]); \
| ^~~~~~
demo.c:16:24: note: format string is defined here
16 | print_array(arr, "%s ", 3);

Sort an array in the relative order of elements of another array in c

I wish to sort a second array as per the first array. e.g.
first = {1,8,7,2,4}
second = {9,7,2,10,3}
I want first to be unchanged and second to be sorted in the same relative order as the first. i.e. the lowest value is at index 0, the second lowest value is at index 3, third lowest value is at index 4 etc etc
second = {2,10,9,3,7}
I have already tried some code for the following
#include <stdio.h>
typedef struct
{
int num;
int pos;
}ArrType;
ArrType arrA[5] = {{1,0},{8,1},{7,2},{2,3},{4,4}};
ArrType arrB[5] = {{9,0},{7,1},{2,2},{10,3},{3,4}};;
int cmparr(const void *a, const void *b)
{
ArrType *tmpa, *tmpb;
tmpa = (ArrType*) a;
tmpb = (ArrType*) b;
return(arrA[tmpa->pos].num - arrA[tmpb->pos].num);
}
int main(void)
{
int i;
qsort(arrB,5, sizeof(ArrType), cmparr);
for (i=0; i<5; i++)
{
printf ("%d ",arrB[i].num);
}
return (0);
}
The actual output is
9 10 3 2 7
I am open to a different data structure, but arrB should only be sorted one time.
I have seen some solutions for this in C++, Javascipt and other languages. But there is not a solution in C.
Edit - These arrays would be quite large in the final program. I am looking for a single sorting operation. i.e. single call to qsort
You need to create the meta-data that matches the desired ordering (i.e an array of indexes). Then apply that meta-data to the second array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int first[] = {1,8,7,2,4};
int second[] = {9,7,2,10,3};
int compare(const void * a, const void * b);
int binary_search(int array[], int min, int max, int target);
void print_array(int * array, int c);
int main()
{
int idx;
int c = sizeof(first)/sizeof(int);
int * sorted = NULL;
int * indexes = NULL;
int * result = NULL;
if (NULL == (sorted = malloc(sizeof(first)))) {
return -1;
}
memcpy(sorted, first, sizeof(first));
if (NULL == (indexes = malloc(sizeof(first)))) {
free(sorted);
return -1;
}
memset(indexes, -1, sizeof(first));
if (NULL == (result = malloc(sizeof(second)))) {
free(sorted);
free(indexes);
return -1;
}
memset(result, -1, sizeof(second));
// 1st: Sort the reference array
qsort (sorted, c, sizeof(int), compare);
// 2nd: Record the position of each sorted element in the original array (this is your meta-data)
for (idx=0; idx<c; idx++) {
indexes[idx] = binary_search(sorted, 0, c, first[idx]);
}
// 3rd sort the target array
memcpy(sorted, second, sizeof(second));
qsort (sorted, c, sizeof(int), compare);
// 4th apply the stored positions to the sorted target array
for (idx = 0; idx < c; idx++) {
result[idx] = sorted[indexes[idx]];
}
print_array(result, c);
free(result);
free(indexes);
free(sorted);
return 0;
}
int compare(const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
int binary_search(int array[], int min, int max, int target)
{
int mid;
while (min <= max)
{
mid = min + (max - min)/2;
if (target > array[mid])
min = mid + 1;
else if (target < array[mid])
max = mid - 1;
else
return mid;
}
return -1;
}
void print_array(int * array, int c)
{
for(int i = 0; i < c; i++) {
printf("%d ", array[i]);
}
printf("\n");
}
Demo
Here is my approach, it uses qsort twice and arrC contains the result.
#include <stdio.h>
typedef struct
{
int num;
int pos;
}ArrType;
ArrType arrA[5] = {{1,0},{8,1},{7,2},{2,3},{4,4}};
int arrB[5] = {9,7,2,10,3};;
int arrC[5];
int cmpInt(const void *a, const void *b)
{
return(*a - *b);
}
int cmp(const void *a, const void *b)
{
ArrType *tmpa, *tmpb;
tmpa = (ArrType*) a;
tmpb = (ArrType*) b;
return(tmpa->num - tmpb->num);
}
int main(void)
{
int i;
qsort(arrA,5, sizeof(ArrType), cmp);
qsort(arrB,5, sizeof(ArrType), cmpInt);
for (i=0; i<5; i++)
{
arrC[arrA[i].pos] = arrB[i];
}
return (0);
}
Since C doesn't have a lambda compare (which could be used to sort an array of indexes according to first[]), the code below sorts an array of pointers ap[] to the elements of first[] using qsort(). Using pointers eliminates the need to pass an array name as a parameter for the compare function, which in turn allows the compare function to work with qsort(). The expression (ap[i]-first) converts a pointer into an index. Next second[] is sorted, also using qsort(). Then ap[] is used as a set of ranks to reorder second[] in place and in O(n) time.
To explain reorder by rank versus reorder by index:
dst[rank[i]] = src[i]; /* reorder by rank */
dst[i] = src[index[i]]; /* reorder by index */
Example code:
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
/* compare for ptr to integer */
int cmppi(const void *p0, const void *p1){
return (*(int *)p0 - *(int *)p1);
}
/* compare for ptr to ptr to integer */
int cmpppi(const void *p0, const void *p1){
return (**(int **)p0 - **(int **)p1);
}
int main()
{
int first[] = {1, 8, 7, 2, 4};
int second[] = {9, 7, 2,10, 3};
int **ap; /* array of pointers */
int *tmpp;
int tmpi;
size_t i, j;
/* allocate and generate array of pointers to first[] */
ap = (int **)malloc(sizeof(first)/sizeof(first[0])*sizeof(int *));
for(i = 0; i < sizeof(first)/sizeof(first[0]); i++)
ap[i] = &first[i];
/* sort ap */
qsort(ap, sizeof(first)/sizeof(first[0]), sizeof(int *), cmpppi);
/* sort second */
qsort(second, sizeof(second)/sizeof(second[0]), sizeof(int), cmppi);
/* reorder ap and second in place using ap as rank (O(n) time) */
for (i = 0; i < sizeof(second) / sizeof(second[0]); i++){
while(i != (j = ap[i] - first)){
tmpp = ap[i]; /* swap(ap[i], ap[j]) */
ap[i] = ap[j];
ap[j] = tmpp;
tmpi = second[i]; /* swap(second[i], second[j] */
second[i] = second[j];
second[j] = tmpi;
}
}
/* display second[] */
for (i = 0; i < sizeof(second) / sizeof(second[0]); i++)
printf("%3d", second[i]);
printf("\n");
free(ap);
return 0;
}

C - Sorting 3d string array by specific column

I have code example which sorts 3d string array.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
static char * rand_string(size_t ssize)
{
char * str = malloc(sizeof(char) * ssize);
const char charset[] = "abcdefghijklmnopqrstuvwxyz";
if (ssize) {
--ssize;
for (size_t n = 0; n < ssize; n++) {
int key = rand() % (int) (sizeof charset - 1);
str[n] = charset[key];
}
str[ssize] = '\0';
}
return str;
}
char *** init_array(char *** array, int n_rows, int n_cols, int ssize)
{
int i, j;
array = malloc(n_rows * sizeof(char **));
for (i = 0; i < n_rows; i++)
{
array[i] = malloc(n_cols * sizeof(char *));
for (j = 0; j < n_cols; j++)
array[i][j] = malloc(ssize * sizeof(char));
}
return array;
}
void gen_array(char *** array, int n_rows, int n_cols, int ssize)
{
int i, j, k;
for (i = 0; i < n_rows; i++)
for (j = 0; j < n_cols; j++)
snprintf(array[i][j], ssize, "%s", rand_string(ssize));
}
int str_compare(const void * a, const void * b)
{
const char *pa = **(const char ***) a;
const char *pb = **(const char ***) b;
// printf("debug: a = %s\n", **(const char ***) a);
return strcmp(pa, pb);
}
void print_array(char *** array, int n_rows, int n_cols)
{
int i, j;
for (i = 0; i < n_rows; i++) {
for (j = 0; j < n_cols; j++)
printf("%s ", array[i][j]);
printf("\n");
}
}
int main(void)
{
int n_rows = 3, n_cols = 5, ssize = 10;
char *** z;
z = init_array(z, n_rows, n_cols, ssize);
gen_array(z, n_rows, n_cols, ssize);
print_array(z, n_rows, n_cols);
printf("\n");
qsort(z, 3, sizeof(char *), str_compare);
print_array(z, n_rows, n_cols);
return 0;
}
with the following output, where are origin array and sorted array (these are example values and randomness doesn't matter):
nwlrbbmqb hcdarzowk kyhiddqsc dxrjmowfr xsjybldbe
fsarcbyne cdyggxxpk lorellnmp apqfwkhop kmcoqhnwn
kuewhsqmg bbuqcljji vswmdkqtb xixmvtrrb ljptnsnfw
fsarcbyne cdyggxxpk lorellnmp apqfwkhop kmcoqhnwn
kuewhsqmg bbuqcljji vswmdkqtb xixmvtrrb ljptnsnfw
nwlrbbmqb hcdarzowk kyhiddqsc dxrjmowfr xsjybldbe
I am looking for a way to sort by another column (second or third). Is it possible?
Thanks.
You can sort the matrix along its second column with this sorting function:
int str_compare2(const void * a, const void * b) {
const char *pa = ((const char ***)a)[0][1];
const char *pb = ((const char ***)b)[0][1];
return strcmp(pa, pb);
}
Changing the 1 into 2 will sort along the third column, etc.
Note that you should invoke qsort this way:
qsort(z, 3, sizeof(char **), str_compare);
z is an array of char **, not char *. On most architectures, sizeof(char*) == sizeof(char **), so there is no difference, but for consistency and readability, using the correct type is advisable.

How to undo changes to an array after passing to a function

Is there any way to undo the actions or get the original array after I changed the array as shown below.
#include <stdio.h>
void function(int array[]){
array[2] = 20;
//do some extra work
return;
}
int main(void){
int array[5] = {1,2,3,4,5};
function(array);
// code which has to use original array
return 0;
}
You can pack two 32 bit integers (old / new) into a 64 bit integer, example:
#include <stdio.h>
#include <stdint.h>
void function(int64_t array[])
{
array[2] = (array[2] << 32) | 20;
}
void printarr(int64_t array[], size_t n)
{
size_t i;
for (i = 0; i < n; i++) {
printf("%d ", (int32_t)(array[i]));
}
printf("\n");
}
int main(void)
{
int64_t array[] = {1, 2, 3, 4, 5};
size_t i, n = sizeof(array) / sizeof(array[0]);
function(array);
puts("After function:");
printarr(array, n);
for (i = 0; i < n; i++) {
if (array[i] >> 32 != 0) /* Changed */
array[i] = array[i] >> 32; /* Undo */
}
puts("Original values:");
printarr(array, n);
return 0;
}
Output:
After function:
1 2 20 4 5
Original values:
1 2 3 4 5
Note:
Of course you can pack two 16 bit integers in a 32 bit integer if you are using short values in order to save some space.
To be portable use PRId32 format (defined in <inttyes.h>) for printf and int32_t:
printf("%"PRId32" ", (int32_t)x);
Another method:
If those changes are made sequentially over positive integers you can change the sign (to identify a change) and store only the changes using realloc:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int *value;
size_t length;
} t_undo;
void function(t_undo *undo, int array[], int index, int value)
{
undo->value = realloc(undo->value, sizeof(int) * (undo->length + 1));
/* check realloc */
undo->value[undo->length++] = array[index];
array[index] = -value;
}
void printarr(int array[], size_t n)
{
size_t i;
for (i = 0; i < n; i++) {
printf("%d ", abs(array[i]));
}
printf("\n");
}
int main(void)
{
t_undo *undo;
int array[] = {1, 2, 3, 4, 5};
size_t i, j = 0, n = sizeof(array) / sizeof(array[0]);
undo = malloc(sizeof(*undo));
/* check malloc */
undo->value = NULL;
undo->length = 0;
function(undo, array, 2, 20);
puts("After function:");
printarr(array, n);
for (i = 0; i < n; i++) {
if (array[i] < 0) /* Changed */
array[i] = undo->value[j++]; /* Undo */
}
puts("Original values:");
printarr(array, n);
free(undo->value);
free(undo);
return 0;
}
Making it short: No. You cannot have your operations reverted - Not in a simple way anyway. What you probably want is to have a local copy of your data in your function(). You could do this by creating a new array and copy it to your first one:
int array[5] = whatever;
int array_copy[5];
memcpy(array_copy, array, 5*sizeof(int));
function(array_copy);
//You have your array now unchanged
If you really don't wanna do that, there's another way of enclosing your array into a struct and let the compiler synthesize a copy operation for you. However there's a serious downside for this one since for big such struct you may end up wasting your stack.
struct MyArray {
int array[5];
};
void function(struct MyArray m) {
//This will create a local copy of m
int i;
for (i = 0; i < 5; i++) {
m.array[i] = i + 1;
}
}
void initialize(struct MyArray* m) {
int i;
assert(m != NULL);
for (i = 0; i < 5; i++) {
m->array[i] = i;
}
}
int main(int argc, char *argv[]) {
struct MyArray m;
int i;
initialize(&m);
function(m);
//Your m here will be untouched
return 0;
}
#include <stdio.h>
void function(int array[]){
array[2] = 20;
}
void save(const char *filename, const void *data, size_t size);
void undo(const char *filename);
int main(void){
int array[5] = {1,2,3,4,5};
save("save_2", &array[2], sizeof(int));//array[2] save to file
function(array);
undo("save_2");//restore
save("save_all", array, sizeof(array));
function(array);
undo("save_all");
// code which has to use original array
for(int i=0;i<5;++i)
printf("%d\n", array[i]);
remove("save_2");
remove("save_all");
return 0;
}
void save(const char *filename, const void *data, size_t size){
FILE *fp = fopen(filename, "wb");
fwrite(&data, sizeof(void *), 1, fp);
fwrite(&size, sizeof(size_t), 1, fp);
fwrite(data, size, 1, fp);
fclose(fp);、
}
void undo(const char *filename){
FILE *fp = fopen(filename, "rb");
void *data;
size_t size;
fread(&data, sizeof(void*), 1, fp);
fread(&size, sizeof(size_t), 1, fp);
fread(data, size, 1, fp);
fclose(fp);
}

Resources