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.
Related
I was given a solution to the problem of recreating the function strlen in C Programming and it was the following, I need help understanding what the code is actually doing.
void *ft_memset(void *b, int c, size_t len)
{
size_t i;
i = 0;
while (i < len)
{
((unsigned char *)b)[i] = c;
i++;
}
return (b);
}
My biggest doubts are the meaning of ((unsigned char *)b)[i] = c, specially because I don't understand the ( *)b, and the need for a return b in a void function.
Thank you very much for your help, sorry if I did something wrong its my first post in stack overflow.
Let's break it down, albeit my C skills are somewhat rusty. Edits are welcome :)
void *ft_memset(void *b, int c, size_t len)
{
size_t i;
i = 0;
while (i < len)
{
((unsigned char *)b)[i] = c;
i++;
}
return (b);
}
First, you have declared a function called ft_memset which returns void *.
void * means a pointer to any object. It's just a number, pointing to a memory address. But we do not know what's in it because it's not properly annotated.
Your function takes three arguments:
b which is a pointer to anything (or void pointer if you will)
c which is an int 32-bit signed integer number.
len which is a size_t which is usually an alias to an unsigned integer. Read more about size_t over here
Your function iterates through the first len bytes and sets the c's value to those.
We're basically overwriting b's contents for the first len bytes.
Now, what does ((unsigned char*)b) mean. This statement is casting your void * to an unsigned char* (byte pointer), this is just
telling the compiler that we're gonna deal with the contents pointed by b as if they were just a unsigned char.
Later we're just indexing on the i-th position and setting the value c in it.
Understanding code of function strlen
void *ft_memset(void *b, int c, size_t len) is like void *memset(void *s, int c, size_t n). They both assign values to the memory pointed to by b. These functions are quite different form strlen().
size_t strlen(const char *s) does not alter the memory pointed to by s. It iterates through that memory looking for a null character.
size_t strlen(const char *s) {
const char *end = s;
while (*end != '\0') {
end++;
}
return (size_t)(end - s);
}
// or
size_t strlen(const char *s) {
size_t i = 0;
while (s[i] != '\0') {
i++;
}
return i;
}
I was looking at a quick sort implementation for generic purpose and one of the parameters of the quick sort function was a void pointer, and I saw the ff arithmetics on void pointers, so I was wondering what that actually does and if it's even possible?
void _qsort(void *v, int size, int left, int right, int (*comp)(void *, void *));
void swap(void *v1, void *v2, int size) {
char buffer[size];
memcpy(buffer, v1, size);
memcpy(v1, v2, size);
memcpy(v2, buffer, size);
}
This part appears in the body of the quick sort defined above:
void *vl = (char *)(v + (left * size));
void *vr = (char *)(v + (mid * size));
swap(vl, vr, size);
so from above code,
How is it possible to do arithmetic on void pointer v, like v + (left * size)?
What does void *vl = (char *)(v + (left * size)); part mean? isn't already casted to char pointer, if so why are we assigning it to a void pointer?
In the swap part, what exactly is happening, like are the vl and vr changing their memory location, value or something else?
You assume right: arithmetics on void pointers is not defined by the C Standard.
The program you are looking at uses a common compiler extension supported by gcc, clang, tcc and many others, that implements arithmetics on void pointers as if they were byte pointers. With this extension, v + (left * size) behaves as
(void *)((char *)v + (left * size))
So the declaration void *vl = (char *)(v + (left * size)); is equivalent to:
void *vl = (char *)((void *)((char *)v + (left * size)));
Note that the whole expression is cast implicitly to (void *) in C.
This declaration can be simplified as:
void *vl = (char *)v + left * size;
This is probably what the programmer meant to write and their mistake went unreported because the compiler allows void * arithmetics with exactly the same effect.
Regarding your third question, the swap function exchanges the contents of the memory blocks pointed to by v1 and v2 using a local variable length array buffer of size bytes. qsort is usually called with a rather small element size, so this approach is OK, but calling qsort with an array of very long elements (more than a few megabytes) is allowed and could cause a stack overflow.
Here is a safer implementation:
void swap(void *v1, void *v2, size_t size) {
unsigned char *p1 = v1;
unsigned char *p2 = v2;
while (size >= 8) {
char buffer[8];
memcpy(buffer, p1, sizeof buffer);
memcpy(p1, p2, sizeof buffer);
memcpy(p2, buffer, sizeof buffer);
p1 += sizeof buffer;
p2 += sizeof buffer;
size -= sizeof buffer;
}
if (size > 0) {
if (size >= 4) {
char buffer[4];
memcpy(buffer, p1, sizeof buffer);
memcpy(p1, p2, sizeof buffer);
memcpy(p2, buffer, sizeof buffer);
p1 += sizeof buffer;
p2 += sizeof buffer;
size -= sizeof buffer;
}
while (size > 0) {
unsigned char temp = *p1;
*p1 = *p2;
*p2 = temp;
p1++;
p2++;
size--;
}
}
}
Also note these remarks:
The standard library function qsort has a different prototype:
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
Using int for sizes and index values is not recommended. left * size might overflow for a large array on systems with 64-bit size_t and 32-bit int: The _qsort function assumes that left * size and right * size are within the range of type size_t and at most the size of the array pointed to by v, yet this size might exceed INT_MAX, causing the int multiplication to overflow with undefined behavior. The correct type is size_t and a sanity check at the beginning of the function can be used to detect invalid arguments.
I've problem using void *. How should I do to use this clean_buffer function for int and float arrays.
void clean_buffer( void *ptr, int n)
{
for( int i = 0; i < n; i++)
ptr[i]=0;
}
int main(void)
{
float *pf;
int *pi;
pf = (float *) malloc(10*sizeof(float));
pi = (int *)malloc(10*sizeof(int));
clean_buffer( (float *)pf, 10);
clean_buffer( (int *)pi, 10);
return 0;
}
void is a non value you cannot use *((void*) x) = v; and to use a cast to use a pointer to an other type is dangerous because the size may not be the same
But, in your case you set to 0, so you can use memset or replace the malloc my calloc and it is useless to have clean_buffer :
int main(void)
{
float *pf;
int *pi;
pf = calloc(10, sizeof(float));
pi = calloc(10, sizeof(int));
return 0;
}
Type void has no size. Therefore you cannot use void * to clear an array.
You can not dereference that type for the same reason.
You must cast to a pointer with specific type:
void clean_buffer(void *ptr, size_t n)
{
unsigned char *my_ptr = ptr;
for (int i = 0; i < n; i++)
my_ptr[i]=0;
}
You need to take care that the size passed to your function cannot be the number or arrays because the compiler cannot do pointer arithmetics with void* pointers.
And for sizes you should use size_t
Instead you have to pass the size of the array in bytes:
int main(void)
{
float *pf;
int *pi;
pf = malloc(10*sizeof(float));
pi = malloc(10*sizeof(int));
clean_buffer( pf, 10*sizeof(float));
clean_buffer( pi, 10*sizeof(int));
return 0;
}
Or you need to pass any other information that can be used to determine type and/or size of the data.
Also:
Casting the return value of malloc is not needed in C.
Casting the parameters of clean_buffer to a type that the variable already has, is useless. The pointer type is converted to void * anyway as this is what the function expects.
Note:
Other answers and comments mention that you could simply pass the pointer to memset or use calloc etc.
This might be true for this very specific case but if you want to do anything else than simply zeroing the memory, the same aspects regarding void * pointers apply as I have shown here. And in those cases memset or calloc are of no help.
I've problem using void *. How should I do to use this clean_buffer function for int and float arrays (?)
Others have mentioned useful things like the need to sizeof to find the size, cast not needed and alternatives to use calloc() for a zero initialized memory allocation.
To add:
sizeof *object_pointer
Use sizeof *object_pointer to find the size. It is less error prone, easier to review and maintain than coding in the type.
// clean_buffer( (float *)pf, 10);
// clean_buffer( (int *)pi, 10);
// cast not needed
clean_buffer(pf, sizeof *pf * 10); // No need to mention type!
clean_buffer(pi, sizeof *pi * 10);
volatile
Scrubbing memory after its final use is prone to being optimized out and then a good reason to not use memset() when memory security is of concern. Instead use volatile to prevent clean_buffer() from itself being optimized out.
void clean_buffer(void *ptr, size_t n) {
volatile unsigned char *vuc = ptr;
for(size_t i = 0; i < n; i++)
vuc[i]=0;
}
}
You cast ptr to the appropriate type so it can dereferenced to clear what it points to; something you know points to a type that you want to clear i items of.
void clean_buffer( void *ptr, int n)
This function demands a void * as a parameter.
clean_buffer( (float *)pf, 10);
Here you are casting to a float pointer. So this a different type as demanded
Also void has no size, so you cant really use [] on ptr
malloc itself returns a void pointer as it doesn't really know for which type you are allocating memory. So, you need to use the same size which you pass to malloc for clearing the buffer also.
You can use memset and pass the size of the entire buffer to clear it without having to worry about it's type.
void clean_buffer( void *ptr, size_t n)
{
memset(ptr, 0, n)
}
int main(void)
{
float *pf;
int *pi;
pf = (float *) malloc(10*sizeof(float));
pi = (int *)malloc(10*sizeof(int));
clean_buffer(pf, 10*sizeof(float));
clean_buffer(pi, 10*sizeof(int));
return 0;
}
Additionally, as others have suggested, you can use calloc if it suits you.
Is that implementation valid and safe to swap two array or variable without worrying about their data type? Or should I use a function pointer?.
This type of code is focusing about using a good implementation of void pointers to swap without worring about the data type.
#include <stdio.h>
#include <string.h>
void swap(void *, void *, int);
int main(void) {
char a[] = "home";
char b[] = "door";
printf("%s %s\n", a, b);
swap(&a, &b, sizeof(a));
printf("%s %s \n", a, b);
return 0;
}
void swap( void *a, void *b, int siz){
char buff[siz]; // I voluntarily omitted dynamic allocation.
memcpy(buff,a,siz);
memcpy(a,b,siz);
memcpy(b,buff,siz);
}
In C, this approach is usually okay (and it's used by standard functions such as qsort()). The contra-indications that indicate you can't use this are when there are any pointers to your objects or their members. Also, take care in multi-threaded code.
Note that in C++, we have std::swap() which will respect user-defined copy/move constructors; copying a C++ object by simply copying its memory is not (in general) valid.
This swap() function is as good/bad as the memcpy() it uses.
If the data structures are just some data structures (of int, float, etc.), it works like a charm.
If you pass two pointers to different structures, all hell will break loose. Offending code:
Foo* myFoo = ...;
Bar* myBar = ...;
swap(myFoo, myBar, sizeof(*myFoo));
Note that your compiler won't complain on this as both pointer types are implicitly convertible to the void*s that swap() expects. But the result of compilation will be bullshit.
If the structure you copy contains a pointer into itself, that pointer will point into the other object after the swap(). The following struct would be an offender of this:
typedef struct {
char* data;
size_t length, allocatedLength;
char shortStringBuffer[32];
} myString;
The idea behind this is, that short strings will be stored in the shortStringBuffer, and data will point to the shortStringBuffer. Strings longer than 31 characters will be stored in dynamically allocated memory, and again be accessible via the data member. It is left as an exercise to the reader to figure out, what precisely happens when you try to copy this thing with a memcpy().
What you must understand, is that memcpy() really only copies bytes, and some data is not invariant to where it is stored. So, each and every use of memcpy() must be accompanied with a proof that it does the correct thing in this particular case. Well, it should. I've never seen such a proof in a comment for some reason...
You can just swap their addresses without further operation to swap two variables/arrays. I tried this and it works:
#include <stdio.h>
int main(void) {
char *a = "home";
char *b = "root";
char *c = a, *d = b;
printf("%s %s\n", a, b);
a = d;
b = c;
printf("%s %s \n", a, b);
return 0;
}
Outputs:
home root
root home
https://ideone.com/MMCOpf
It is safe to use generic pointers to swap, however you must make sure you get the sizes right, and that you don't overflow any array or object:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int swap(void *a, void *b,
size_t a_size, size_t b_size);
int main(void) {
char a[] = "home";
char b[] = "door";
printf("%s %s\n", a, b);
int ret = swap(a, b, sizeof(a), sizeof(b));
if(ret) {
printf("%s %s \n", a, b);
}
return ret;
}
int swap(void *a, void *b,
size_t a_size, size_t b_size)
{
if (b_size != a_size ) {
return 0;
}
void *tmp = malloc(a_size);
if(!tmp) {
return 0;
}
memcpy(tmp, a, a_size);
memcpy(a, b, b_size);
memcpy(b, tmp, a_size);
free(tmp); // tmp no longer needed.
return 1;
}
I solved this by C, code for your reference.
Using uint16_t is neccessary to hold the carry bit when two large uint8_t variables plus.
int main(){
uint8_t tmp[9] = {0x0};
for (int i=9-1; i>=0 ; i--) *(tmp+i) = 0xff-i;
uint16_t tmp2[9];
for (int i=0; i<9; i++) tmp2[i] = tmp[i];
byte_swap_uint8_data(tmp2, 9);
}
void byte_swap_uint8_data(uint16_t* data, int w) {
if (w < 2) return;
for (int i=0; i<w/2; i++) {
data[i] += data[w-1-i];
data[w-1-i] = data[i] - data[w-1-i];
data[i] = data[i] - data[w-1-i];
}
}
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.