I fall in some problem.
I need to write some function like memcpy(void*, const void*), which its signature should be:
void arrayCopy(void *dest, int dIndex, const void *src, int sIndex, int len)
I noticed that, in many implementation of memcpy, we cast void* to char*, but I think this is not the case of me, as the arrayCopy function needed to be used on arrays of many types including structs.
So, how can I accomplish this?
EDIT:
the source code might be something like that:
#include <stdio.h>
#include <string.h>
void arrayCopy(void *, int, const void *, int, int, size_t);
int main(void)
{
int i;
int dest[10] = {1};
int src [] = {2, 3, 4, 5, 6};
arrayCopy(dest, 1, src, 0, 5, sizeof(int));
for (i=0; i<10; i++) printf("%i\n", dest[i]);
return 0;
}
void arrayCopy(void *dest, int dIndex, const void *src, int sIndex, int len, size_t size)
{
char *cdest = (char*) dest;
const char *csrc = (char*) src;
int i;
len *= size;
if (dest == src)
{
printf("Same array\n");
}else
{
cdest += (dIndex * size);
csrc += (sIndex * size);
for (i=0; i<len; i++)
*cdest++ = *csrc++;
}
}
Thanks.
"char * " is just a bunch bytes, everything in C is ultimately bytes - you can cast a pointer to any data structure to char* (you will also need to know the size in memory of the structure)
The function must have an element-size info, eg:
void *arrayCopy(void *dest, size_t di,const void *src, size_t si, size_t num, size_t esize)
{
char *cdest = (char*) dest;
const char *csrc = (char*) src;
return memcpy( &cdest[esize*di], &csrc[esize*si], esize*num );
}
...
arrayCopy(dest, 1, src, 0, 5, sizeof*src);
You cannot work with objects of type void. The Standard doesn't allow that. So you need to cast the void away, and the best type to use is unsigned char. There's a guarantee by the Standard that unsigned char can access all bits of any other type representable in your system.
Related
So i wanted to create a swap function that will allocation size of character array dynamically. Is it possible? Is it recommended?
My code that shows errors.
void swap(void * vp1, void * vp2, int size)
{
char buffer[size]; //size must have a constant value is the error i am getting.
memcpy(buffer, vp1, size);
memcpy(vp1, vp2, size);
memcpy(vp2, buffer, size);
}
char buffer[size];
An array whose size is not known at compile time is known as a variable length array. These are C-only features. Since this is giving an error, you are using a C++ compiler. You must change size so that it will be known at compile time.
The following are valid C++ array definitions
#define NUM 8
int a[16];
int a[NUM];
This is ill-formed:
int n;
printf("What is your age?\n");
scanf("%d", &n);
int a[n];
because n depends on what the user types.
The solution is to cast the void pointer arguments into pointers to unsigned char, and then manipulate the unsigned char *
void swap(void *a, void *b, size_t n)
{
unsigned char *p = (unsigned char *) a,
*q = (unsigned char *) b,
tmp;
for (size_t i = 0; i < n; ++i) {
tmp = p[i];
p[i] = q[i];
q[i] = tmp;
}
}
But since you're using C++, it is a better idea to use templates.
Unfortunately MSVC is the only major C compiler that doesn't support your code. To support all compilers you can write:
void swap(void * vp1, void * vp2, int size)
{
char *buffer = malloc(size);
if ( buffer )
{
memcpy(buffer, vp1, size);
memcpy(vp1, vp2, size);
memcpy(vp2, buffer, size);
free(buffer);
}
}
Note: This way is simple in code but there may be more efficient options, especially if you are typically only swapping small buffers.
I was asked to implement my own version of memcopy. This is what I found from the internet. The thing confuses me is that we have two void * pointers, why do we then typecast them onto char*?
Is this even correct?
// A C implementation of memcpy()
#include<stdio.h>
#include<string.h>
void myMemCpy(void *dest, void *src, size_t n)
{
// Typecast src and dest addresses to (char *)
char *csrc = (char *)src;
char *cdest = (char *)dest;
// Copy contents of src[] to dest[]
for (int i=0; i<n; i++)
cdest[i] = csrc[i];
}
The cast is needed because you may not dereference pointers of the type void *. Thus you may not for example to write src[i] when src is a pointer of the type void *. The type void is an incomplete type.
As for the function then it is wrong.
If you look at the declaration of the standard function memcpy you will see that it is declared like
void * memcpy(void * restrict s1, const void * restrict s2, size_t n);
^^^^^^ ^^^^^^^^^^^
Thus the function written by you should look at least like
void * memcpy(void *s1, const void *s2, size_t n);
The function definition can look as it is shown in this demonstrative program.
#include <stdio.h>
void * myMemCpy(void *s1, const void *s2, size_t n)
{
const unsigned char *src = s2;
unsigned char *dsn = s1;
while ( n-- ) *dsn++ = *src++;
return s1;
}
int main(void)
{
char s1[] = "Hello";
char s2[sizeof( s1 )];
puts( ( char * )myMemCpy( s2, s1, sizeof( s1 ) ) );
return 0;
}
The program output is
Hello
You need to typecast them because the "type" void doesn't have a size (mind void * does).
Then your loop will be able to move one char (ideally a byte) at a time.
I can't figure out what seems to be the problem that I get a segmentation fault from this:
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
void alloc(unsigned char *data) {
data = (unsigned char *) malloc(20);
memset(data, 0, 20);
}
void main() {
unsigned char *data = NULL;
int i;
alloc(data);
for (i = 0; i < 20; i++) {
data[i] = i;
printf("%d ", *(data + i));
}
free(data);
}
Unsigned char is 1 byte so the loop through 20 should be correct
void alloc(unsigned char *data) {
data = (unsigned char *) malloc(20);
memset(data, 0, 20);
}
modifies a local copy of your pointer. You could pass it by reference to make your example work:
void alloc(unsigned char *&data) {
data = (unsigned char *) malloc(20);
memset(data, 0, 20);
}
It seems that your program is written in C instead of C++. In C++ you should use operator new [] instead of malloc.
The problem with the function is that function parameters are its local variables. So the function parameter char *data is a copy of its argument declared in main like
unsigned char *data = NULL;
So any changes of the parameter in function alloc do not influence on the original argument. After exiting the function the parameter (local variable) will be destroyed and the original variable in main will not be changed.
You have two approaches. Either you declare the function the following way
void alloc(unsigned char **data) {
*data = (unsigned char *) malloc( 20 );
if ( *data ) memset( *data, 0, 20 );
}
and call it like
alloc( &data );
Or you declare the function the following way
unsigned char * alloc() {
unsigned char *data = (unsigned char *) malloc( 20 );
if ( data ) memset( data, 0, 20 );
return data;
}
and call it in main like
data = alloc();
Take into account that function main shall be decalred in C like
int main( void )
^^^
and in C++ like
int main()
^^^
You could also return the pointer, rather than passing it to the function.
unsigned char *alloc() {
unsigned char *data = (unsigned char *) malloc(20);
memset(data, 0, 20);
return data;
}
And then,
...
unsigned char *data = alloc();
int i;
...
You tagged C++, but your code looks like C. If you really are trying to write C++ you shouldn't be using malloc. Either use new[] or the appropriate smart pointers.
EDIT: You're using void main(). Don't do that.
What should main() return in C and C++?
I have been searching for a solution but can't seem to find one similar to mine. Am trying to sort
a 2D char * array by a certain column.
char *objs[50][3];
/***** within a loop to populate with values *****/
objs[count][0]=obj->level; //this is a number to be sorted
objs[count][1]=obj->cost; //this is a number
objs[count][2]=obj->short_desc->str; //this is a string
count++;
/***** end loop *********/
qsort(objs, count, sizeof(char *), compare_function); //to sort by obj->level, int values
i deleted my previous solution because it was showing all kinds
of weird numbers or not even sorting. i am not very experienced with
C, and would greatly appreciate help on how to do this.
thank you in advance.
When sorting implicit structs in "C" defined by 2d arrays, where each row corresponds to a single object, I find it useful to use qsort_s() because it allows me to pass in more information about the the array entries to be sorted into the comparison function.
Thus the following accepts a 2d array of strings with nRows rows and nColumns columns and sorts on a column specified by sortColumnIndex. The extra context pointer provided to qsort_s() communicates the sort index down to the sorting method without requiring global variables:
struct sort_on_index_context
{
size_t nRows;
size_t nColumns;
size_t sortColumnIndex;
};
static int compare(void *p_vcontext, const void *ventry1, const void *ventry2)
{
struct sort_on_index_context *p_context = (struct sort_on_index_context *)p_vcontext;
char **entry1 = (char **)ventry1;
char *s1 = entry1[p_context->sortColumnIndex];
char **entry2 = (char **)ventry2;
char *s2 = entry2[p_context->sortColumnIndex];
return strcmp(s1, s2);
}
void sort_on_index(char **objs, size_t nRows, size_t nColumns, size_t sortColumnIndex)
{
struct sort_on_index_context context;
if (sortColumnIndex < 0 || sortColumnIndex >= nColumns)
return; /* Print an error or throw an exception! */
context.nColumns = nColumns;
context.sortColumnIndex = sortColumnIndex;
context.nRows = nRows;
qsort_s(objs, nRows, sizeof(char *) * nColumns, compare, (void *)&context);
}
We pass sizeof(char *) * nColumns because we want qsort_s to treat each contiguous group of nColumns char pointers as single blocks to be rearranged in order.
And then you would call it something like this:
char *objs[50][3];
size_t nRows = sizeof(objs)/sizeof(objs[0]);
size_t nColumns = sizeof(objs[0])/sizeof(objs[0][0]);
size_t column_id_to_sort = 1; /* or whatever you want to define as your sort key. */
/* Fill up your "objs" array however you like */
/* Now do the sort: */
sort_on_index(&objs[0][0], nRows, nColumns, column_id_to_sort);
Edit
If qsort_s or some equivalent is not available in your development environment, you may need to communicate the necessary information to your sort function via a static variable, e.g.
static struct sort_on_index_context context;
static int compare(const void *ventry1, const void *ventry2)
{
char **entry1 = (char **)ventry1;
char *s1 = entry1[context.sortColumnIndex];
char **entry2 = (char **)ventry2;
char *s2 = entry1[context.sortColumnIndex];
return strcmp(s1, s2);
}
Update
You can extend the method to supply your own custom comparison method like so:
struct sort_on_index_context_custom
{
size_t nRows;
size_t nColumns;
size_t sortColumnIndex;
int (*comparer)(const char *, const char *);
};
static int compare_custom(void *p_vcontext, const void *ventry1, const void *ventry2)
{
struct sort_on_index_context_custom *p_context = (struct sort_on_index_context_custom *)p_vcontext;
char **entry1 = (char **)ventry1;
char *s1 = entry1[p_context->sortColumnIndex];
char **entry2 = (char **)ventry2;
char *s2 = entry2[p_context->sortColumnIndex];
return p_context->comparer(s1, s2);
}
void sort_on_index_custom(char **objs, size_t nRows, size_t nColumns, size_t sortColumnIndex, int (*comparer)(const char *, const char *))
{
struct sort_on_index_context_custom context;
if (sortColumnIndex < 0 || sortColumnIndex >= nColumns)
return; /* Print an error or throw an exception! */
context.nColumns = nColumns;
context.sortColumnIndex = sortColumnIndex;
context.nRows = nRows;
context.comparer = comparer;
qsort_s(objs, nRows, sizeof(char *) * nColumns, compare_custom, (void *)&context);
}
And then call it like this to sort a given column of strings as integers:
static int integer_compare(const char *s1, const char *s2)
{
int int1 = atoi(s1);
int int2 = atoi(s2);
return int1 - int2;
}
sort_on_index_custom(&objs[0][0], nRows, nColumns, 1, integer_compare);
Working on using qsort.
#include <string.h>
#include <stdlib.h>
#pragma once
int cstring_cmp(const void *a, const void *b);
int main()
{
int count = 0;
char * randomStr = "sdjsn9i3ms;sa;'smsn92;w;''[w0p4;dsmsdf";
char * charArray[] =
{"s","d","j","s","n","9","i","3","m","s",";","s","a",";","'","s","m","s","n"
,"9","2",";","w",";","'","'","[","w","0","p","4",";","d","s","m","s","d","f"};
size_t strings_len = sizeof(charArray) / sizeof(char *);
/*void qsort(void *base, size_t nel,
size_t width, int (*compar)(const void *, const void *));*/
qsort(charArray, strings_len, sizeof(char *), cstring_cmp);
qsort(randomStr, strings_len, sizeof(char *), cstring_cmp);
// Pause at command prompt
system("pause");
return 0;
} // Close function Main
int cstring_cmp(const void *a, const void *b)
{
const char **ia = (const char **)a;
const char **ib = (const char **)b;
return strcmp(*ia, *ib);
}
So obviously my second qsort is not working. whether that's based on my cstring_cmp function that goes into my qsort not being able to support the base i give it or because my base is not formatted to correctly input into the qsort is a mystery to me.
My Question is how do I convert char * randomStr to char * charArray[] dynamically, during runtime, on the fly, or whatever cool phrase you can come up with. I've searched around a lot and maybe I was just not asking the right question, so I'm coming to you guys for some real question answering power.
Just starting C so if you please try not to fry my brain with your answers me and my brain would appreciate it.
My end goal here is to convert randomStr to a format of charArray, qsort it then convert it back to the randomStr format so i can do some find and replace things I have set up already.
Any help would be great, thanks.
First of all if you use char *randomStr = "Stuff" you can't change it, it's undefined behavior. Second, try this:
int
cmp_fry_brain(const void *a, const void *b)
{
return *((const char *)a) - *((const char *)b);
}
/* This is equivalent to the one above (the compiler will likely emit the
* exact same code).
*/
int
cmp(const void *a, const void *b)
{
const char *x = a;
const char *y = b;
return *x - *y;
}
int
main()
{
char str[] = "This is the end";
qsort(str, strlen(str), 1, cmp_fry_brain);
/* ... */
}