I have a header file with this type definition:
typedef struct {
int rows;
int columns;
int **values;
} bidimensional_matrix;
As an example, If I instantiate the matrix from a main function I'd just do:
int matrix[][] = {{1, 2, 3}, {1, 1, 1}, {5, 5, 5}};
How would you generate the same matrix but with the typedef provided previously? (I mean, with pointers and malloc)
Is the approach correct? Maybe I'm a little object oriented biased and in c it's not convenient to handle it that way. I've defined the struct that way so I can just pass two bidimensional_matrix by parameter and do a multiplication.
I propose you to use flexible member array, exemple:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
size_t n;
size_t m;
int matrix[];
} bidimensional_matrix;
bidimensional_matrix *new_bidimensional_matrix(size_t n, size_t m) {
bidimensional_matrix *bm = malloc(sizeof *bm + sizeof *bm->matrix * n * m);
if (!bm) {
return NULL;
}
*bm = (bidimensional_matrix){ .n = n, .m = m };
return bm;
}
int get_bidimensional_matrix(bidimensional_matrix *bm, size_t i, size_t j) {
return bm->matrix[i * bm->m + j];
}
int set_bidimensional_matrix(bidimensional_matrix *bm, size_t i, size_t j, int x) {
return bm->matrix[i * bm->m + j] = x;
}
int main(void) {
bidimensional_matrix *bm = new_bidimensional_matrix(5, 10);
if (!bm) {
return EXIT_FAILURE;
}
for (size_t i = 0; i < bm->n * bm->m; i++) {
bm->matrix[i] = i;
}
printf("sample value %d\n", get_bidimensional_matrix(bm, 4, 5));
set_bidimensional_matrix(bm, 4, 5, 42);
printf("sample value %d\n", get_bidimensional_matrix(bm, 4, 5));
free(bm);
}
But you could use this too, that have other avantage but generally is more slow:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
size_t n;
size_t m;
int **matrix;
} bidimensional_matrix;
int main(void) {
bidimensional_matrix bm = { .n = 5, .m = 10, .matrix = malloc(sizeof *bm.matrix * bm.n) };
if (!bm.matrix) {
return EXIT_FAILURE;
}
for (size_t i = 0; i < bm.n; i++) {
bm.matrix[i] = malloc(sizeof *bm.matrix[i] * bm.m);
if (!bm.matrix[i]) {
return EXIT_FAILURE;
}
for (size_t j = 0; j < bm.m; j++) {
bm.matrix[i][j] = i * bm.m + j;
}
}
printf("sample value %d\n", bm.matrix[4][5]);
for (size_t i = 0; i < bm.n; i++) {
free(bm.matrix[i]);
}
free(bm.matrix);
}
If you need to swap rows the second could be a little faster cause swap row are O(1). But like you see the first one has only one malloc(), in practice with the cache of the processor it should be a lot more faster than the second implementation.
Related
I have a problem. I have to divide array into dynamic array and return pointer with parameter.
When I try to run this code, I get (interrupted by signal 11: SIGSEGV) this message. I think it is something with my pointers. But I don't even get any warnings, I don't know where to look else.
#include <stdio.h>
#include <stdlib.h>
int splitData(int data[], int size, int splitPlace, int **firstArray);
int main() {
int data[6] = {1, 2, 3, 4, 5, 6};
int size = 6;
int *ptr = NULL;
int n = splitData(data, size, 3, &ptr);
printf("%d", n);
for(int i = 0; i < 3; ++i)
{
printf("[%d]", ptr[i]);
}
return 0;
}
int splitData(int data[], int size, int splitPlace, int **firstArray)
{
*firstArray = (int *)malloc(splitPlace * sizeof(int));
for(int i = 0; i < splitPlace; ++i)
{
*firstArray[i] = data[i];
}
return 0;
}
You have the precedence wrong with *firstArray[i]. You need (*firstArray)[i].
Clearer might be to allocate
int *new_array = malloc(...);
*firstArray = new_array.
Then use new_array in your loop body.
The program doesn't crash, the build is successful, and it runs through the rest of main properly. The only problem is that the sort doesn't actually sort the array.
I left out the creation of the array and the rest of main simply because I've already tested them with another sort, and they work properly. However I'm supposed to use a higher level sort so I have to change things.
//struct for the array
typedef double darray_value_t;
typedef struct darray_t_tag {
darray_value_t *data;
size_t size;
size_t capacity;
} darray_t;
//top of main
quickSort(&dataset, 0, dataset.size - 1);
//rest of main
//functions used to for the quick sort
void quickSort(darray_t *dataset, int lowValue, int highValue) {
if (lowValue < highValue) {
int part = partition(dataset, lowValue, highValue);
quickSort(dataset, lowValue, part - 1);
quickSort(dataset, part + 1, highValue);
}
}
darray_value_t partition(darray_t *dataset, int lowValue, int highValue) {
int pivot = dataset->data[highValue];
int i = (lowValue - 1);
for (int j = lowValue; j < highValue; j++) {
if (dataset->data[j] <= pivot) {
i++;
swapValues(&dataset->data[i], &dataset->data[j]);
}
}
swapValues(&dataset->data[i + 1], &dataset->data[highValue]);
return (i + 1);
}
void swapValues(darray_value_t *a, darray_value_t *b) {
darray_value_t temp = *a;
*a = *b;
*b = temp;
}
There are multiple problems in your code:
the return value of partition should be int, not darray_value_t,
conversely, the type of pivot should be darray_value_t, not int.
Here is a modified version:
#include <stdio.h>
//struct for the array
typedef double darray_value_t;
typedef struct darray_t_tag {
darray_value_t *data;
size_t size;
size_t capacity;
} darray_t;
void swapValues(darray_value_t *a, darray_value_t *b) {
darray_value_t temp = *a;
*a = *b;
*b = temp;
}
int partition(darray_t *dataset, int lowValue, int highValue) {
darray_value_t pivot = dataset->data[highValue];
int i = lowValue;
for (int j = lowValue; j < highValue; j++) {
if (dataset->data[j] <= pivot) {
swapValues(&dataset->data[i++], &dataset->data[j]);
}
}
swapValues(&dataset->data[i], &dataset->data[highValue]);
return i;
}
//functions used to for the quick sort
void quickSort(darray_t *dataset, int lowValue, int highValue) {
if (lowValue < highValue) {
int part = partition(dataset, lowValue, highValue);
quickSort(dataset, lowValue, part - 1);
quickSort(dataset, part + 1, highValue);
}
}
int main() {
darray_value_t arr[] = { 2.0, 1.5, 4.5, -1 };
darray_t dataset = { arr, 4, 4 };
quickSort(&dataset, 0, dataset.size - 1);
for (size_t i = 0; i < dataset.size; i++) {
printf(" %g", dataset.data[i]);
}
printf("\n");
return 0;
}
I'm a newbie in C and trying to insert a number at the last position in C such that, the size of the array is changed over time.
The first array is like this:
temp[10] = {1, 2, 0, 0, 5, 6, 0, 8, 0, 0};
Now how can we insert those values in temp that are != 0 to a new array which has a defined length of 5: tmp
Here's what I'm trying:
void push(int arr[], int value, int current){
arr[current] = value;
}
int main(void) {
int temp[10] = {1, 2, 0, 0, 5, 6, 0, 8, 0, 0};
int tmp[5];
for(int i=0;;i++){
if(temp[i]) push(tmp, temp[i],sizeof(tmp)/sizeof(tmp[0]));
// I don't put i < 10 int the loop initialization. Since the tmp's length is just 5
}
// I put sizeof(tmp)/sizeof(tmp[0]) there because we want at every time the tmp is inserted a new value,
// it's length will change (increase by 1).
// So next loop round, the new value will be added to the last position
// But I failed to do so
}
Current output:
exited segmentation fault
// I'd be very grateful if someone can also explain for me why this error happens
Desired output:
tmp[5] = {1, 2, 5, 6, 8}
C does not have dynamic arrays. Arrays have a fixed size determined from their definition. You can allocate objects with malloc() that behave as arrays, but you must keep track of their allocated size separately. Appending an element requires reallocating the array so its address in memory may change.
In your code, tmp has a fixed size of 5 elements. You could maintain an index specifying how many elements are used and update that in the push function:
#include <stdio.h>
int push(int arr[], int value, size_t size, size_t *current) {
if (*current < size) {
arr[(*current)++] = value;
return 0;
} else {
/* array is full */
return -1;
}
}
int main(void) {
int temp[10] = { 1, 2, 0, 0, 5, 6, 0, 8, 0, 0 };
int tmp[5];
size_t pos = 0;
for (size_t i = 0; i < sizeof(temp) / sizeof(temp[0]); i++) {
if (temp[i])
push(tmp, temp[i], sizeof(tmp) / sizeof(tmp[0]), &pos);
}
printf("tmp:");
for (size_t i = 0; i < pos; i++) {
printf(" %d", tmp[i]);
}
printf("\n");
return 0;
}
Your definition of push requires the 3rd parameter to be the position to place the element. However, the expression sizeof(tmp)/sizeof(tmp[0]) provides the size of the array and it will thus index past the array's last element (because indexes in C go from 0..n-1). This in itself can cause a segmentation fault.
Neither did you provide a terminating condition for your loop. It will continue forever.
Your solution could simply be:
for(int i=0, j=0; i<10; i++)
if(temp[i]) push(tmp, temp[i], j++);
What is
trying to insert a number at the last position in C
Although you got an explanatory answer by David Ranieri, I want to show the simplest approach keeping in mind that you are a newbie. Look at this code:-
Code:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
void push(int arr[], int value, int current){
arr[current] = value;
}
int main(void) {
int temp[SIZE] = {1, 2, 0, 0, 5, 6, 0, 8, 0, 0};
int *tmp = NULL, count = 0, i, j;
// Loop for counting non-zero values in temp array.
for (i = 0; i < SIZE; ++i)
if (temp[i])
count++;
// Dynamically allocating space for tmp along with checking errors if any.
if((tmp = (int *)malloc(count * sizeof(int))) == NULL)
{
printf("Memory Not Available.\n");
exit(-1);
}
for(i = 0, j = 0; i < SIZE; i++){
if(temp[i])
push(tmp, temp[i], j++);
}
// Printing your desired output.
for(i = 0; i < count; ++i)
printf("%d\t", tmp[i]);
free(tmp);
}
Here the size of tmp will change according to the non-zero elements of temp.
Now if you want to make the temp array a dynamic array, use the same approach as used for the tmp, just ask the user at run-time to input the size of temp and then its elements/values as well.
The problem is that you are accessing outside of the bounds of temp because you don't specify when to stop in the loop.
For a dynamic array, when you don't know the number of elements before hand, you can use realloc:
#include <stdio.h>
#include <stdlib.h>
void push(int **arr, size_t *size, int value)
{
int *ptr = realloc(*arr, sizeof(*ptr) * (*size + 1));
if (ptr == NULL)
{
free(*arr);
perror("push");
exit(EXIT_FAILURE);
}
ptr[*size] = value;
*size += 1;
*arr = ptr;
}
int main(void)
{
int temp[10] = {1, 2, 0, 0, 5, 6, 0, 8, 0, 0};
int *arr = NULL;
size_t size = 0;
for (size_t i = 0; i < sizeof temp / sizeof temp[0]; i++)
{
if (temp[i])
{
push(&arr, &size, temp[i]);
}
}
for (size_t i = 0; i < size; i++)
{
printf("%d\n", arr[i]);
}
free(arr);
}
Notice that even if it ilustrates the use of a growable array, this example is considered bad code, a more robust design will take care of the size and is able to manage the allocation and deallocation by itself:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int *data;
size_t size;
} dyn_array;
dyn_array *create_dyn_array(void)
{
dyn_array *arr = calloc(1, sizeof *arr);
if (arr == NULL)
{
perror("create_dyn_array");
exit(EXIT_FAILURE);
}
return arr;
}
void destroy_dyn_array(dyn_array *arr)
{
free(arr->data);
free(arr);
}
void push_dyn_array(dyn_array *arr, int value)
{
int *ptr = realloc(arr->data, sizeof(*ptr) * (arr->size + 1));
if (ptr == NULL)
{
destroy_dyn_array(arr);
perror("push_dyn_array");
exit(EXIT_FAILURE);
}
ptr[arr->size++] = value;
arr->data = ptr;
}
int main(void)
{
int temp[10] = {1, 2, 0, 0, 5, 6, 0, 8, 0, 0};
dyn_array *arr = create_dyn_array();
for (size_t i = 0; i < sizeof temp / sizeof temp[0]; i++)
{
if (temp[i])
{
push_dyn_array(arr, temp[i]);
}
}
for (size_t i = 0; i < arr->size; i++)
{
printf("%d\n", arr->data[i]);
}
destroy_dyn_array(arr);
}
This is better, but still not perfect because we are limited to a fixed type (int), with some extra memory we can adapt our code to support any type (using the generic type void *), as an optimization, the dynamic array grows by a factor of 2 instead of calling realloc on each iteration:
#include <stdio.h>
#include <stdlib.h>
/* Begin - This API is supposed to be in a header */
typedef struct
{
void **data;
size_t room;
size_t size;
} dynarray;
dynarray *dynarray_create(void)
{
dynarray *array = calloc(1, sizeof *array);
if (array == NULL)
{
return NULL;
}
array->data = malloc(sizeof(void *));
if (array->data == NULL)
{
free(array);
return NULL;
}
array->room = 1;
return array;
}
void *dynarray_push(dynarray *array, void *data)
{
if (data == NULL)
{
return NULL;
}
if (array->size == array->room)
{
array->room *= 2;
void *ptr = realloc(array->data, array->room * sizeof(void *));
if (ptr == NULL)
{
return NULL;
}
array->data = ptr;
}
array->data[array->size++] = data;
return data;
}
void *dynarray_get(dynarray *array, size_t index)
{
return array->data[index];
}
size_t dynarray_size(dynarray *array)
{
return array->size;
}
void dynarray_destroy(dynarray *array, void (*func)(void *data))
{
if (func != NULL)
{
for (size_t i = 0; i < array->size; i++)
{
func(array->data[i]);
}
}
free(array->data);
free(array);
}
/* End API */
int main(void)
{
int temp[10] = {1, 2, 0, 0, 5, 6, 0, 8, 0, 0};
dynarray *array = dynarray_create();
if (array == NULL)
{
perror("dynarray_create");
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < sizeof temp / sizeof temp[0]; i++)
{
if (temp[i])
{
if (dynarray_push(array, &temp[i]) == NULL)
{
perror("dynarray_push");
exit(EXIT_FAILURE);
}
}
}
size_t size = dynarray_size(array);
for (size_t i = 0; i < size; i++)
{
int *data = dynarray_get(array, i);
printf("%d\n", *data);
}
dynarray_destroy(array, NULL);
}
Basically I'm trying to assign the matrix elements to an array of structs. First struct to have a=1, b=2, c=3, second one a=4, b=5, c=6 and so on. My problem right now is that I can't figure it out how to do in the setmat function.
#include <stdio.h>
#include <stdlib.h>
#define COLS 3
#define MAX_ENTRIES 3
typedef struct str_t_ {
int a;
int b;
int c;
} str_t;
void setmat(str_t *str, int mat[][COLS]) {
str->a = mat[][0];
str->b = mat[][1];
str->c = mat[][2];
}
void printmat(str_t str[MAX_ENTRIES]) {
int i;
for (i = 0; i < MAX_ENTRIES; i++) {
printf("%d %d %d\n\n", str[i].a, str[i].b, str[i].c);
}
}
int main(void) {
int matrix[][COLS] = {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
typedef str_t str_;
str_ *structs[MAX_ENTRIES];
int i;
for (i = 0; i < MAX_ENTRIES; i++) {
setmat(&structs[i], matrix);
}
printmat(structs);
return EXIT_SUCCESS;
}
You are mixing up copying a 2d array with copying one row of a 2d array.
A version copying the 2d-array could look like:
void setmat(str_t *str, int mat[][COLS]) {
for(i = 0;i < MAX_ENTRIES;i++) {
str->a = mat[i][0];
str->b = mat[i][1];
str->c = mat[i][2];
str++;
}
}
and the call should be:
setmat(structs, matrix);
Change the definition of setmat to take a pointer to a row of the matrix:
void setmat(str_t *str, int row[COLS]) {
str->a = row[0];
str->b = row[1];
str->c = row[2];
}
There is another problem in your main function: structs is not an array of str_t, it is defined as an array of pointers to str_t. Furthermore, it is bad style and unnecessary to define types with local scope.
Here is a corrected version:
int main(void) {
int matrix[][COLS] = {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
str_t structs[MAX_ENTRIES];
int i;
for (i = 0; i < MAX_ENTRIES; i++) {
setmat(&structs[i], matrix[i]);
}
printmat(structs);
return EXIT_SUCCESS;
}
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);
}