Getting address boundary error when working with pointers in C - c

The following code gives me a terminated by signal SIGSEGV (Address boundary error):
void rec(int x, int *arr, int *size) {
if (x < 0) {
rec(-x, arr, size);
return;
}
arr = realloc(arr, sizeof(int) * ++(*size));
*(arr + (*size) - 1) = x % 10;
if (x % 10 != x)
rec(x / 10, arr, size);
}
int main() {
int *arr = malloc(sizeof(int));
int *size = malloc(sizeof(int));
*size = 0;
rec(20, arr, 0);
}
I already figured our that the arr counter in the main method won't hold the desired result, but I still can't understand why I'm getting an error.

Notice that you are passing NULL as third argument:
rec(20, arr, 0); // 0 is NULL
and you get a segfault dereferencing it:
arr = realloc(arr, sizeof(int) * ++(*size)); // here size is `NULL`
try with
rec(20, arr, size);

For starters these memory allocations
int *arr = malloc(sizeof(int));
int *size = malloc(sizeof(int));
does not make a sense. They are redundant.
You could just write
int *arr = NULL;
size_t size = 0;
Secondly the variable size is declared but not used because instead of the variable you passed the integer constant 0
rec(20, arr, 0);
So within the function rec
void rec(int x, int *arr, int *size);
the pointer size was initializer by the null pointer constant 0. That is size is a null pointer within the function and using a null pointer to access memory results in undefined behavior.
Also you should pass the pointer to the function by reference. Otherwise passing it to the function does not make a great sense because the pointer in main will not be changed.
The code in main could look like
int *arr = NULL;
size_t size = 0;
rec( 20, &arr, &size );
Pay attention to that you should free all the allocated memory when it will not be used any more.
Correspondingly the function should be declared like
void rec(int x, int **arr, size_t *size);
Use the type size_t instead of the type int because this unsigned integer type is the type of the second argument of the function realloc.
In general to get the result of realloc you should use an intermediate variable because the function can return a null pointer and the current pointer will be lost.
Also pay attention to that the call of the function is unsafe and can result in an infinite recursion due to this if statement
if (x < 0) {
rec(-x, arr, size);
return;
}
when the user passes to the function the value of x equal to INT_MIN.
Consider the following demonstrative program.
#include <stdio.h>
#include <limits.h>
int main(void)
{
int x = INT_MIN;
printf( "x = %d\n", x );
printf( "-x = %d\n", -x );
return 0;
}
Its output might look like
x = -2147483648
-x = -2147483648
As you can see negating the value of the variable x you get the same negative value. So maybe it is better to declare the first function parameter as having the type unsigned int.
Your function can look for example the following way as it is shown in the demonstrative program below.
#include <stdio.h>
#include <stdlib.h>
int rec( unsigned int x, unsigned int **arr, size_t *size )
{
const unsigned int Base = 10;
unsigned int *tmp = realloc( *arr, sizeof( int ) * ++*size );
int success = tmp != NULL;
if ( success )
{
*arr = tmp;
*( *arr + *size - 1 ) = x % Base;
if ( x % Base != x )
{
success = rec( x / Base, arr, size );
}
}
return success;
}
int main(void)
{
unsigned int *arr = NULL;
size_t size = 0;
rec( 123456789, &arr, &size );
for ( size_t i = 0; i < size; i++ )
{
printf( "%u", *( arr + i ) );
}
putchar( '\n');
free( arr );
return 0;
}
The program output is
987654321

Related

How to return 2 1D arrays from function to main in C

#include <stdio.h>
int *func()
{
int *a=malloc(5);
int *b=malloc(5);
for(int i=0;i<5;i++)
{
a[i]=i+1;
b[i]=i+5;
}
int *l= malloc(2);
l[0]=a;
l[1]=b;
//printf("%p %p ",l[0],l[1]);
return l;
}
int main()
{
int *k=func();
}
For the above code, how to return a,b arrays to main function?
Here after assigning values to the two arrays a and b i have given their adresses to new array l. Now after returning l to main, how to peint values of both the arrays a and b in main function?
You can do it the following way
struct Array
{
int a[5];
int b[5];
};
struct Array func( void )
{
struct Array a =
{
{1,2,3,4,5},
{1,2,3,4,5}
};
return a;
}
int main( void )
{
struct Array a = func();
//...
}
Another approach is to allocate arrays dynamically and return pointers to the allocated arrays from the function through output parameters. For example
#include <stdio.h>
#include <stdlib.h>
void func( int **a, size_t *n1, int **b, size_t *n2 )
{
*n1 = 5;
*a = malloc( sizeof( int ) * *n1 );
if ( *a != NULL )
{
int value = 1;
for ( size_t i = 0; i < *n1; i++ )
{
( *a )[i] = value++;
}
}
*n2 = 5;
*b = malloc( sizeof( int ) * *n2 );
if ( *b != NULL )
{
int value = 1;
for ( size_t i = 0; i < *n2; i++ )
{
( *b )[i] = value++;
}
}
}
int main(void)
{
int *a = NULL;
int *b = NULL;
size_t n1 = 0;
size_t n2 = 0;
func( &a, &n1, &b, &n2 );
//...
free( a );
free( b );
return 0;
}
void func(int **aa, int **bb)
{
static int a[5]={1,2,3,4,5};
static int b[5]={1,2,3,4,5};
*aa = a;
*bb = b;
}
void func2(int **aa, int **bb)
{
int *a = malloc(5 * sizeof(*a));
int *b = malloc(5 * sizeof(*b));
memcpy(a, (int []){1,2,3,4,5}, 5 *sizeof(*a));
memcpy(b, (int []){1,2,3,4,5}, 5 *sizeof(*b));
*aa = a;
*bb = b;
}
typedef struct
{
int a[5];
int b[5];
}mydata;
mydata func1(void)
{
mydata d = { .a = {1,2,3,4,5}, .b = {1,2,3,4,5}};
/* ... */
return d;
}
The second method is very expensive as the whole struct is being copied via (in most implementations) stack.
Example usage:
int main(void)
{
int *a,*b;
func2(&a, &b);
for(size_t i = 0; i < 5; i++)
{
printf("a[%zu] = %d, b[%zu]=%d\n", i, a[i], i, b[i]);
}
}
Functions in C can only return a single thing - that thing can be a struct with multiple attributes, but you cannot return and assign multiple independent items like you can in Python or Perl.
If the caller needs several independent items from the function, then you will need to use multiple output parameters - the caller must pass pointers to the things it wants the function to update, and the function updates the things being pointed to:
bool f( T *a, T *b ) // for some arbitrary type T
{
/**
* The *expressions* *a and *b have type T; writing to *a
* and *b in f is equivalent to writing to x and y in main.
*/
*a = new_T_value(); // writes a new value to the thing a points to
*b = another_new_T_value(); // writes a new value to the thing b points to
return some_boolean_value();
}
int main( void )
{
T x, y; // for some arbitrary type T
if ( f( &x, &y ) ) // f will write new values to x and y
do_something();
...
}
We can replace T with a pointer type P *, which gives us:
bool f( P **a, P **b ) // for some arbitrary type P
{
/**
* The expressions *a and *b have type P *; writing to *a and *b
* in f is equivalent to writing to x and y in main.
*/
*a = new_Pstar_value(); // writes a new value to the thing a points to
*b = another_new_Pstar_value(); // writes a new value to the thing b points to
return some_boolean_value();
}
int main( void )
{
P *x, *y; // for some arbitrary type T
if ( f( &x, &y ) ) // f will write new values to x and y
do_something();
...
}
The semantics are exactly the same - we want the function f to write new values to x and y, so we have to pass pointers to x and y as arguments. It's just in this case x and y already have a pointer type (P *), so we wind up passing pointers to pointers (P **).
Here’s the most straightforward way that requires the fewest changes to your existing code:
#include <stdio.h>
#include <stdlib.h> // need this for malloc
/**
* We want func to dynamically allocate arrays of int and
* assign the resulting pointers to *a and *b. We also want
* to dynamically allocate and return an array of int *.
*/
int **func( int **a, int **b)
{
/**
* malloc(5) allocates 5 *bytes*, not 5 ints.
* We need to multiply the number of things we
* want by the size of each thing.
*/
*a=malloc(5 * sizeof **a); // sizeof **a == sizeof (int)
*b=malloc(5 * sizeof **b);
for(int i=0;i<5;i++)
{
/**
* The postfix [] operator has higher precedence than the
* unary * operator; we don't want to dereference a[i] and
* b[i], we want to index into what a and b *point to*, so
* we must explicitly group the * operator with the variable
* name.
*/
(*a)[i]=i+1;
(*b)[i]=i+5;
}
/**
* Each l[i] holds a value of type int *,
* so l needs to have type int **
*/
int **l= malloc(2 * sizeof *l);
l[0]=*a;
l[1]=*b;
//printf("%p %p ",l[0],l[1]);
return l;
}
int main( void )
{
int *a, *b;
int **k=func( &a, &b );
}

Passing array of structs with reference - segmentation fault

#include <stdio.h>
#include <stdlib.h>
struct X {
char surname[30];
int deg;
};
void read_record(struct X** a, int size){
for (int i = 0;i < size; i++){
a[i]->deg = 0;
}
}
int main(){
int n = 10;
struct X *container = (struct X*)malloc(sizeof(struct X) * n);
read_record(&container, n);
}
I created a 1D array of size n, then I passed it by reference to the function read_record. However, when I execute the program, there is a segmentation fault. What is the problem?
EDIT:
As a next step, I want to reallocate the array of 10 elements in the function with size of 20. That's why I want to send the array as a reference. If I did it in main then I would write:
container = realloc(container, (n + 10) * sizeof(Struct X));
How can I do this in the function?
container is already a pointer, you don't need to pass the address-of the pointer, instead:
#include <stdio.h>
#include <stdlib.h>
struct X {
char surname[30];
int deg;
};
void read_record(struct X *a, size_t size)
{
for (size_t i = 0; i < size; i++) {
a[i].deg = 0;
}
}
int main(void)
{
size_t n = 10;
struct X *container = malloc(sizeof(struct X) * n);
read_record(container, n);
}
also, prefer size_t to store the number of allocated objects.
Nitpick: read_record doesn't seem a good name for a function that modifies the contents of the records.
EDIT: As a next step, I want to reallocate the array of 10 elements in the function with size of 20. (in the function). That's why I want to send the array as a reference.
Same approach but returning a reallocated container:
#include <stdio.h>
#include <stdlib.h>
struct X {
char surname[30];
int deg;
};
struct X *read_record(struct X *a, size_t size)
{
struct X *new = realloc(a, sizeof(struct X) * size);
if (new != NULL)
{
for (size_t i = 0; i < size; i++) {
new[i].deg = 0;
}
}
return new;
}
int main(void)
{
size_t n = 10;
struct X *container = malloc(sizeof(struct X) * n);
container = read_record(container, n * 2);
if (container == NULL)
{
fprintf(stderr, "Can't read record\n");
exit(EXIT_FAILURE);
}
}
As a next step, I want to reallocate the array of 10 elements in the function with size of 20. (in the function). That's why I want to send the array as a reference.
The pointer is passed by value, so to save the changes and have them usable outside the function scope, after the function ends, i.e. in main, a pointer to pointer must be the argument, and the address of the pointer must be passed, your overall assessment is correct.
Your implementation, however, is not correct, here's how you shoud do it:
Live demo
void read_record(struct X **a, int size) //double pointer
{
*a = realloc(*a, sizeof **a * (size + 10)); //reallocate memory for 20 ints
if (*a == NULL)
{
perror("malloc");
}
for (int i = 0; i < size + 10; i++) //assing new values
{
(*a)[i].deg = 1;
}
}
int main()
{
int n = 10;
struct X *container = malloc(sizeof *container * n); //original allocation
//the pointer now has space for 10 ints
if (container == NULL)
{ //check allocation errors
perror("malloc");
}
for (int i = 0; i < n; i++) //assign values
{
container[i].deg = 0;
}
read_record(&container, n); //pass by reference
//the pointer now has space for 20 ints
}
Alternatively you can return the pointer instead, refering to David Ranieri's answer.
The first function parameter has the pointer to pointer type struct X**. So dereferencing the parameter a you will get a pointer of the type struct X*. Now you may apply the subscript operator that yields lvalue of the type struct X..
That is the function definition will look like
void read_record(struct X** a,int size){
for (int i=0;i<size;i++){
( *a )[i].deg = 0;
}
}
Or this statement
( *a )[i].deg = 0;
may be substituted for this statement
a[0][i].deg = 0;
On the other hand, there is no great sense to declare the first parameter as having the type struct X**. The function can look simpler as for example
void read_record(struct X* a,int size){
for (int i=0;i<size;i++){
a[i].deg = 0;
}
}
and be called like
read_record( container, n );
When you call read_record you pass a pointer to a pointer to the first element of an array of X structures.
But inside the read_record you treat it as a pointer to the first element of an array of pointers to X structures (i.e. as an array of pointers to X). There's a subtle but very important difference here.
If you want to emulate pass-by-reference for the pointer variable, you need to dereference it inside the read_record to get the original pointer (and remember that then you have an array of objects, not pointers):
(*a)[i].deg = 0;
Double pointer is the problem. The code should be:
void read_record(struct X* a,int size){ // Check the change
for (int i=0;i<size;i++){
a[i]->deg = 0;
}
}
int main(){
int n = 10;
struct X *container=(struct X*)malloc(sizeof(struct X)*n);
read_record(container,n); // Check the change
}

Pointers to pointers segmentation fault

I created an insertion sort method which accepts an array, its size and a comparator. The comparator function is this:
int compare_int_ptr(void* ptr1, void* ptr2) {
double i1 = *(double*)ptr1;
double i2 = *(double*)ptr2;
if(i1<i2) {
return -1;
}
if(i1 == i2) {
return 0;
}
return 1;
}
The insertion is this:
void insertion_sort(void** array, int size, CompFunction compare){
int i,j;
void* key;
for(i = 1; i<size;i++){
key = array[i];
for(j = i-1; j>=0 && compare(array[j],key)>=0;j--){
swap(&array[j+1],&array[j]);
}
array[j+1] = key;
}
}
If I try to execute it, I get the segmentation fault error, so I think that I didn't used the pointer correctly. Is it correct that when I do the swap i pass it with the &?
EDIT: this is where I call the method:
int main(int argc, char const *argv[]) {
if(argc < 2) {
printf("Usage: sortingfirstusage <file_name>\n");
exit(EXIT_FAILURE);
}
double* array = load_array(argv[1]);
insertion_sort((void**)array, 3, compare_int_ptr);
free(array);
return 0;
The array is correctly loaded because I printed all the elements before calling the insertion sort and they were in.
You are trying to sort an array of doubles. double *array points to the first of n elements:
array ==> [ double ] \
[ double ] |
. > n elements
. |
[ double ] /
You are casting array to a void **:
(void **)array ==> [ void * ] \
[ void * ] |
. > n elements
. |
[ void * ] /
It should not be hard to determine that trouble lies ahead. A void * is not a double. It may or may not be the same size as a double. It almost certainly doesn't point to a valid memory location, so if you dereference it you will invoke undefined behavior, almost certainly resulting in your program being killed by a signal. Unfortunately, your insertion_sort function does dereference it when it calls the comparison function:
key = array[i];
for(j = i-1; j>=0 && compare(array[j],key)>=0;j--){
array[i] and array[j] are both invalid void * values (because the underlying memory contains doubles, not void *s). Your comparison function dereferences them here:
double i1 = *(double*)ptr1;
double i2 = *(double*)ptr2;
ptr1 and ptr2 contain meaningless pointer values. They do not point to doubles. Dereferencing them invokes undefined behavior.
Here is a working version of insertion_sort using the same function type and equivalent functionality to the qsort function from the C standard library (although the function is a lot less efficient than qsort):
insertion_sort.h:
#ifndef INSERTION_SORT_H_INCLUDED__
#define INSERTION_SORT_H_INCLUDED__
#include <stddef.h>
void insertion_sort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
#endif
insertion_sort.c:
#include <string.h>
#include "insertion_sort.h"
void insertion_sort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *))
{
char (*b)[size] = base;
size_t i;
size_t j;
int cmp;
for (i = 1; i < nmemb; i++) {
j = i - 1;
/* search backwards for insertion point */
while ((cmp = compar(b + j, b + i)) > 0 && j > 0)
j--;
if (cmp <= 0)
j++; /* went back one too far */
if (j < i) {
/* rotate element i to position j, j to j+1, ..., i-1 to i */
char tmp[size];
memcpy(&tmp[0], &b[i][0], size);
memmove(&b[j + 1][0], &b[j][0], size * (i - j));
memcpy(&b[j][0], &tmp[0], size);
}
}
}
Here is an example of the usage of the above function:
main.c:
#include <stdio.h>
#include "insertion_sort.h"
int compar_double(const void *a, const void *b)
{
double d1 = *(const double *)a;
double d2 = *(const double *)b;
if (d1 < d2)
return -1;
if (d1 > d2)
return 1;
return 0;
}
void print_doubles(const double *d, size_t n)
{
size_t i;
for (i = 0; i < n; i++)
printf("%g\n", d[i]);
}
int main(void)
{
double numberlist[] = { 3.0, 1.0, 5.0, -4.0, 2.0 };
size_t len = sizeof numberlist / sizeof numberlist[0];
printf("Unsorted:\n");
print_doubles(numberlist, len);
printf("\n");
insertion_sort(numberlist, len, sizeof numberlist[0], compar_double);
printf("Sorted:\n");
print_doubles(numberlist, len);
return 0;
}
Here is the output produced by the above program:
Unsorted:
3
1
5
-4
2
Sorted:
-4
1
2
3
5
void qsort( void *ptr, size_t count, size_t size,
int (*comp)(const void *, const void *) );
Like qsort, your sorting function should take a void * as the first parameter, not void **. The double indirection is a mistake that you should have noticed when calling insertion_sort. Converting a double[] array to void ** requires a cast, whereas it can be converted automatically to void * without one.
Without knowing what load_array(argv[1]); does, the answer is impossible to predict as Peter suggested in the comments.
Assuming this function call is doing something legitimate and loading the array with pointers that can be de-referenced properly then your problem is the cast. You cannot make a pointer into a pointer to pointers. You have to pass the address of the pointer to accomplish what you want.
insertion_sort(&array, 3, compare_int_ptr);

Add an adress to an array of pointers C

I have to write a function that will add an adress at the end of an array of pointers. Here is what I've done. I want to know if I did right and if not, please correct me.
#include <stdio.h>
#include <stdlib.h>
#define MAX 3
void add( int *array[MAX], int *addr)
{
array = realloc(array, 1*sizeof(int));
array[MAX+1] = addr;
}
int main()
{
int *addr = 4;
int *array[MAX] = {"1","2","3"};
add(array, addr);
int i;
for(i = 0; i<4;i++)
printf("%d ", array[i]);
return 0;
}
from the manual for realloc:
The realloc() function changes the size of the memory block pointed to
by ptr to size bytes. The contents will be unchanged in the range from
the start of the region up to the minimum of the old and new sizes. If
the new size is larger than the old size, the added memory will not be
initialized. If ptr is NULL, then the call is equivalent to
malloc(size), for all values of size; if size is equal to zero, and
ptr is not NULL, then the call is equivalent to free(ptr). Unless ptr
is NULL, it must have been returned by an earlier call to malloc(),
calloc() or realloc(). If the area pointed to was moved, a free(ptr)
is done.
if its too long to read ill explain.
first of all you should use realloc after allocating memory ( using malloc for example ) and not after local declaration
second you're treating pointers to int ( int * ) as if they we're int. also shown as warning
examples:
int *addr = 4;
int *array[MAX] = {"1","2","3"};
array = realloc(array, 1*sizeof(int)); // here you're using sizeof( int )
another problem is reaching out of bound of array
array[MAX+1] = addr;
for an array with 3 spaces - you have array[ 0 ], array[ 1 ] and array[ 2 ].
in this line you're trying to reach the array[ 4 ] of an array ( that's suppose to be ) of size 4 --> out of bounds
my suggested code for this will be:
code edited
#include <stdio.h>
#include <stdlib.h>
#define MAX 3
void add( int **array[ MAX ], int *addr )
{
*array = realloc( *array, ( MAX + 1 ) * sizeof( int* ) );
(*array)[ MAX ] = addr;
}
int main()
{
int i;
int *addr;
int **array;
addr = &i;
array = malloc( MAX * sizeof ( int* ) );
for ( i = 1; i <= MAX; i++ ) {
array[ i - 1 ] = addr + 4 * i;
}
add( &array, addr );
for ( i = 0; i < MAX + 1; i++ ) {
printf( "%p ", array[ i ] );
}
return 0;
}

Concatenate two arrays using void pointer (C)

I want to concatenate two arrays of the same type into a single new array with the same type. But the problem is I have to use void pointers, and somehow my code won't work from the third element on. I searched a bit on the internet but seems like noone is having this problem
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void array_float_fill(float *arr1, float *arr2, int n, int m){
for(int i = 0;i<n;i++){
*(arr1+i)=i+n;
}
for(int i = 0;i<m;i++){
*(arr2+i)=i+m;
}
}
void array_concat(void *arr1, void *arr2, void *arr3, int n, int m,int size){
for(int i=0;i<n;i++){
memcpy((arr3+i),(arr1+i),size);
}
for(int i=0;i<m;i++){
memcpy((arr3+i+n),(arr2+i),size);
}
}
int main(int argc, char const *argv[])
{
int n=10;
int m=10;
float f1[n];
float f2[m];
array_float_fill(f1,f2,n,m);
printf("%f",*(f1+3));
float* f3 = malloc((n+m) * sizeof(float));
array_concat(f1,f2,f3,n,m,sizeof(float));
printf("%f",*(f3+3));
return 0;
}
I tried it with a for-loop to copy every single element to the new array, because the function will just give me a pointer to the start of the array. Dunno why it doesn't work. Any help and hints would be much appreciated
void* pointer arithmetic ...
... is not actually allowed in standard C. gcc allows it and assumes a base operand size of 1. Thus it follows
Index assumption
You are confusing bytes with indexes when using memcpy.
When (non-standardly) adding integer to void pointers, the integer's meaning (in gcc) is that of a byte-offset. This is unlike a typed pointer, there the compiler will do the appropriate scaling for you:
void *p;
int i;
p[i]; // This will be literally p+i after compiling on your compiler
But for example:
float *p;
int i;
p[i]; // This will be p+i*sizeof(float) after compiling.
So instead of ...
for(int i=0;i<n;i++){
memcpy((arr3+i),(arr1+i),size);
}
for(int i=0;i<m;i++){
memcpy((arr3+i+n),(arr2+i),size);
}
... you got to write (this is still compiler-specific):
for(int i=0;i<n;i++){
memcpy((arr3+i*size), (arr1+i*size), size);
}
for(int i=0;i<m;i++){
memcpy((arr3+i*size+n*size), (arr2+i*size), size);
}
... or go standards-conforming:
for(int i=0;i<n;i++){
memcpy((char*)arr3+i*size, (char*)arr1+i*size, size);
}
for(int i=0;i<m;i++){
memcpy((char*)arr3+i*size+n*size, (char*)arr2+i*size, size);
}
By conversion to char*, you enforce a base operand size of 1 byte (more precisely, 1 C byte), which is what you want given the generic nature of your concat function.
However
Note that you can pass arbitrary strides to memcpy, you do not actually need the loops; instead, just do:
memcpy((char*)arr3, arr1, size*n);
memcpy((char*)arr3+n*size, arr2, size*m);
Conversions are only needed where you do arithmetics.
You don't have to memcpy in a loop. If you know the size and the length of the arrays you only need two:
void array_concat(void *arr1, void *arr2, void *arr3, int n, int m,int size)
{
memcpy( arr3 , arr1 , size * n ) ;
memcpy( ( char* )arr3+( size * n ) , arr2 , size * m ) ;
}
The line ( char* )arr3+( size * n ) gives a pointer to the end of the first part.
The cast to char* is needed because pointer arithmetic doesn't work on void*, so we manually increment the pointer to the correct offset.
For example ( char* )arr3+( n ) would not be correct because the underlying type is float. That is why you pass the size of float and then use it.
Your compiler seems to have an extension that allows you to use void* as it were a char* when using pointer arithmetic.Then you increment it incorrectly here: arr3+i just by the value of sizeof( char ),instead of sizeof( float ).
You can copy an entire array with a single memcpy. Check the signature of memcpy:
void *memcpy(void *dest, const void *src, size_t n);
It will copy n contiguous bytes from src to dest, as simple as it sounds. An array is a contiguous block of memory, so you can copy an entire array using a single call to memcpy.
I fixed this and a few other things in the code below:
Access arrays by indices rather than doing pointer arithmetic, which is easy to get wrong.
Constness
Usage of size_t rather than int for sizes and array indices. See Why size_t matters.
It's a good habit to pass the output buffer size and check it prior to any copying in order to prevent buffer overflows.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void array_float_fill(float *arr1, float *arr2, size_t n, size_t m) {
for (size_t i = 0; i<n; i++) {
arr1[i] = i + n;
}
for (size_t i = 0; i<m; i++) {
arr2[i] = i + m;
}
}
void array_concat(
void *out_arr,
size_t out_arr_size,
const void *in_arr1,
size_t in_arr1_size,
const void *in_arr2,
size_t in_arr2_size)
{
const size_t total_size = in_arr1_size + in_arr2_size;
// BE AWARE that `assert` will be gone if you define `NDEBUG`
// (or compile with `-DNDEBUG`).
// This assertion guarantees we have enough space before copying.
assert(out_arr_size >= total_size);
memcpy(out_arr, in_arr1, in_arr1_size);
memcpy((char *)out_arr + in_arr1_size, in_arr2, in_arr2_size);
// The cast to `char *` above is important for portability.
// Arithmetic on a pointer to void is a GNU extension.
// See http://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html
}
void dump_array(const char *name, float *array, size_t num_elems) {
printf("%s = ", name);
for (size_t i = 0; i < num_elems; i++) {
printf("%f ", array[i]);
}
printf("\n");
}
int main() {
const size_t n = 10;
const size_t m = 10;
float f1[n];
float f2[m];
array_float_fill(f1, f2, n, m);
const size_t f3_size = (n + m) * sizeof(float);
float *f3 = malloc(f3_size);
array_concat(f3, f3_size, f1, sizeof(f1), f2, sizeof(f2));
// Show the results
dump_array("f1", f1, n);
dump_array("f2", f2, m);
dump_array("f3", f3, n + m);
return 0;
}
Arithmetic operations cannot be performed on void pointers. Since void pointers don't have any fixed data type like int or float, thus they don't know with what value they should get incremented or decrement upon arithmetic operations. For example, when you increment integer pointer, the value is automatically increased by 4 upon every increment. Similarly character pointer will be incremented by 1 upon every increment. Here in your example, when memcpy operation trying to copy the value from arr1 to arr3, it can't be able to de-reference arr3, hence the problem. Generally whenever any such operations performed on void pointers, first they need to be de-referenced. De-reference it to floating pointer will work, see below
memcpy(((float*)arr3+i),((float*)arr1+i),size);
memcpy(((float*)arr3+i+n),((float*)arr2+i),size);
Try the following
void array_concat( const void *arr1, const void *arr2, void *arr3, int n, int m, int size )
{
memcpy( arr3, arr1, n * size );
memcpy( ( char * )arr3 + n * size, arr2, m * size );
}
Here is how the program can look
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void array_float_fill( float *arr1, float *arr2, size_t n, size_t m )
{
for ( size_t i = 0; i < n; i++ )
{
*( arr1 + i ) = i + n;
}
for ( size_t i = 0; i < m; i++ )
{
*( arr2 + i ) = i + m;
}
}
void array_concat( const void *arr1, const void *arr2, void *arr3,
size_t n, size_t m, size_t size )
{
memcpy( arr3, arr1, n * size );
memcpy( ( char * )arr3 + n * size, arr2, m * size );
}
int main( void )
{
size_t n = 10;
size_t m = 10;
float f1[n];
float f2[m];
array_float_fill( f1, f2, n, m );
printf( "%f\n",*( f1 + 3) );
float *f3 = malloc( ( n + m ) * sizeof( float ) );
array_concat( f1, f2, f3, n, m, sizeof( float ) );
printf( "%f\n", *( f3 + 3 ) );
free( f3 );
return 0;
}
The output is
13.000000
13.000000
Do not forget to free the dynamically allocated array. Also you should include header <string.h> where memcpy is declared.
Take into account that this declaration of main
int main(int argc, char const *argv[])
is wrong.
The correct declaration looks like
int main(int argc, char *argv[])

Resources