Finding end of char pointer, int and float - c

I have a function that will be passed a void pointer. This pointer can either be an int, char, or float. I know what data type will be passed to me by means of an associated value. For example, below is what my function looks like:
void * (int type, void * data);
If the void pointer I am passed was originally a char type, and I cast it back to a char type, is there a way of determining how many bytes are associated with that pointer? For example, if my function is called as follows:
f(1, (void *)"Hello world");
and I cast the void pointer back to a char pointer
char * p = (char *)data;
Is there some way I can figure out how many bytes were used? Would I possibly have to search for the null character and count how many bytes away it is from the original pointer? What would I have to do to find the size of the int and float as well?

Would I possibly have to search for the null character and count how
many bytes away it is from the original pointer?
Yes, if your void* is actually a char* this will work.
What would I have to do to find the size of the int and float as well?
int and float as always the same size (it depends from your architecture, generally 32 or 64 bit. Use sizeof operator to determine the exact size). If you are passing an array of int as void* you haven't any way to find its length.
Generally in these cases it's convinent to pass the size to your function too.

Related

How come you can cast a pointer to an integer, but not a double? (C)

I'm doing a random exercise where, given an integer array and double array, you are supposed to calculate the size of an integer and a double.
For the integer size, I simply use two pointers to point to two adjacent arrays, then I find their difference. Because pointer arithmetic calculates this as a difference of 1, I casted the pointers as integers because I assumed the pointers would explicitly refer to 4 bytes of memory, and I got the right result (4).
Now, I try the same exact thing for doubles, but I get this error: pointer value used where a floating point value was expected
A possible guess is that doubles are 8 bytes, whereas pointers are 4 bytes. But I' not sure if that actually matters.
Any insights?
my exact line:
int doubSize = (double)doubPtr2 - (double)doubPtr1;
//where doubtPtr1 and doubPtr2 poiny to two adjacent indexes of double array
The standard allows casting pointers to integer types, though unless the type is big enough, casting back won't recover the original pointer. Still, the actual mapping is implementation-defined though there is a suggestion it should mimic the underlying memory architecture, which sharply limits the utility of doing so. No such licence is given for floating-point types.
Take a look at intptr_t for a guaranteed-big-enough type.
Anyway, the better (and correct) way is getting those pointers to adjacent array elements, casting them to char* (char is guaranteed to be one byte big, a byte is not guaranteed to be an octet), and than subtracting them. (Result type should be size_t as for the operator)
That presupposes that for your exercise, sizeof was arbitrarily banned, which would otherwise be the solution of choice here.
Casting double pointer to a double isn't doing what you think it's doing, or at least I don't think it is... see for example:
int main(int argc, char *argv)
{
double *a;
double *b;
double dummy[3];
a = &dummy[0];
b = &dummy[1];
int *ai;
int *bi;
int dummyi[3];
ai = &dummyi[0];
bi = &dummyi[1];
char *ac;
char *bc;
ac = (char *)a;
bc = (char *)b;
printf("Check for double: %d vs %d\n",sizeof(double),bc-ac);
ac = (char *)ai;
bc = (char *)bi;
printf("Check for int: %d vs %d\n",sizeof(int),bc-ac);
}
(Print outs:
Check for double: 8 vs 8
Check for int: 4 vs 4
)
You're overthinking it. A pointer is an address, which is just a number. When you have an array of whatever type, each one is at the next available address. So, to find out the size of the type, you just need the addresses of adjacent entries in the array.
double tmp[2];
int size = (char *)(&(tmp[1])) - (char *)(&(tmp[0]));
The addresses have to be cast to char * in order to get the address of the first byte of the data type by treating the address space as storing bytes rather than whatever the data type is.

Need help to understand this main() function in C [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I'm learning C programming and do not quite understand the following program, need some help with the understanding.
Question 1: What do the two asterisks do preceding *argv in the main function parameters.
Question 2: Inside the main() function, why void is followed by an asterisk? What does it do?
Question 3: &retval has the "&", does the variable "retval" point to the memory address?
Thanks for help
/** Main */
int main(int argc, char **argv) {
pthread_t thread;
void* retval;
pthread_create(&thread, NULL, thread_proc, NULL);
printf("Hello from the main thread.\n");
pthread_join(thread, &retval);
printf("Done.\n");
return 0;
}
This issue is somewhat confusing when starting to learn C.
Here are the basic principles that might help you get started:
There are only a few basic types in C:
char: an integer value with the size of 1 byte.
short: an integer value with the size of 2 bytes.
long: an integer value with the size of 4 bytes.
long long: an integer value with the size of 8 bytes.
float: a non-integer value with the size of 4 bytes.
double: a non-integer value with the size of 8 bytes.
Note that the size of each type is generally defined by the compiler and not by the standard.
The integer types short, long and long long are usually followed by int.
It is not a must, however, and you can use them without the int.
Alternatively, you can just state int, but that might be interpreted differently by different compilers.
So to summarize this:
short is the same as short int but not necessarily the same as int.
long is the same as long int but not necessarily the same as int.
long long is the same as long long int but not necessarily the same as int.
On a given compiler, int is either short int or long int or long long int.
If you declare a variable of some type, then you can also declare another variable pointing to it.
For example:
int a;
int* b = &a;
So in essence, for each basic type, we also have a corresponding pointer type.
For example: short and short*.
There are two ways to "look at" variable b (that's what probably confuses most beginners):
You can consider b as a variable of type int*.
You can consider *b as a variable of type int.
Hence, some people would declare int* b, whereas others would declare int *b.
But the fact of the matter is that these two declarations are identical (the spaces are meaningless).
You can use either b as a pointer to an integer value, or *b as the actual pointed integer value.
You can get (read) the pointed value: int c = *b.
And you can set (write) the pointed value: *b = 5.
A pointer can point to any memory address, and not only to the address of some variable that you have previously declared. However, you must be careful when using pointers in order to get or set the value located at the pointed memory address.
For example:
int* a = (int*)0x8000000;
Here, we have variable a pointing to memory address 0x8000000.
If this memory address is not mapped within the memory space of your program, then any read or write operation using *a will most likely cause your program to crash, due to a memory access violation.
You can safely change the value of a, but you should be very careful changing the value of *a.
Type void* is exceptional in the fact that it doesn't have a corresponding "value type" which can be used (i.e., you cannot declare void a). This type is used only as a general pointer to a memory address, without specifying the type of data that resides in that address.
Answer one :
char **argv mean you have a two dimension array of char.
you can access it like this :
argv[0][2]
it give you a char.
But you can access like this :
argv[0]
who give you a char *
Here, the '*' told that it's a pointer.
So it's not a char directly in your memory, but a case which will contain an address to char.
The fact to have int *; or char *; or anything * mean that you probably have an array.
Answer 2:
The void * is simple.
You have a pointer to something you don't know yet what it will be.
So a void * pointer can take address of any type of value like a char, a int, r more sophisticate type like system time (here, thread pointer).
Answer 3:
The '&' mean : take the address of this field.
So if I have
int i = 5;
printf("%i", i);
printf("%i", &i);
the first print will show the value of int : here 5.
The second will show you the address of i, here something like 0x06528A7
the fact with '&' is that you can do this :
int *ptr;
int i = 5;
ptr = &i;
you can now send your 'int *ptr' or another function, to modify it.
It will be too in the main.
Cause while modifying 'ptr', you are modifying 'i' and not a copy.
Hope it helps you!
* in c is used to declare pointers. A pointer is a variable that holds the location of, literally the address-of, a variable stored in computer memory.
So in your question void* retval; declare a void pointer. A void pointer is a special type of pointer that can be pointed at objects of any data type!
char **argv
is a pointer to a pointer to char. Actually it is a variable that holds the address of a variable that is a pointer also
char** argv is equivalent to char **argv, and roughly means
A memory address value that when accessed, contains a memory address value which
when accessed contains a memory address value which contains the first char
C uses null terminated strings, so all that is needed to know the end of a string is the first memory address where it starts. The rest of the routines then search subsequent addresses looking for the null \0 character.
C also uses null terminated lists, so all that is needed to know the end of a list is the first memory address where the list starts (assuming you know the size of the list). In this case, the list is of size sizeof(*char), or in English "the size of a pointer to char". The rest of the list traversing routines then search subsequent indexes in the list (subsequent memory offsets) until it is terminated by the null character.
Try to read it right to left, and it reads "a pointer to a pointer to a char", or in easier terms "a list of strings".
* is a notation to mark pointer You should learn about pointers in c
1)By char** argv, argv is declared as a pointer to pointer to char
2) By void*, it means a variable that can hold address of any kind of variable.
3) as retval is a pointer, it can point to a memory location. and by &retval you are getting address of the variable named retval.
& is called the address of operator.

Void pointers pretending to be void double pointers

I've been doing some thinking. I haven't found anything directly answering this question, but I think I know the answer; I just want some input from some more experienced persons.
Knowns:
A void pointer points to just a memory address. It includes no type information.
An int pointer points to a memory address containing an int. It will read whatever is in the memory address pointed to as an integer, regardless of what was stuffed into the address originally.
Question:
If a void double pointer void ** foo were to point to a dynamically allocated array of void pointers
void ** foo = malloc(sizeof(void *) * NUM_ELEMENTS);
is it true, as I am supposing, that because of the unique nature of void pointers actually lacking any sort of type information that instead of void ** foo an equivalent statement would be
void * bar = malloc(sizeof(void *) * NUM_ELEMENTS);
and that when I use indirection to access by assigning a specific type, such as with
(It was pointed out that I can't dereference void pointers. For clarity to the purpose of the question the next line is changed to be appropriate to that information)
int ** fubar = bar;
that I would get an appropriate pointer from the single void pointer which is just acting like a double pointer?
Or is this all just in my head?
It is permissible to assign the result of malloc to a void * object and then later assign it to an int ** object. This is because the return value of malloc has type void * anyway, and it is guaranteed to be suitable for assignment a pointer to any type of object with a fundamental alignment requirement.
However, this code:
#define NUM_ELEMENTS 1000
void *bar = malloc(sizeof(void *) * NUM_ELEMENTS);
int **fubar = bar;
*fubar = 0;
is not guaranteed by the C standard to work; it may have undefined behavior. The reason for this is not obvious. The C standard does not require different types of pointers to have the same size. A C implementation may set the size of an int * to one million bytes and the size of a void * to four bytes. In this case, the space allocated for 1000 void * would not be enough to hold one int *, so the assignment to *fubar has undefined behavior. Generally, one would implement C in such a way only to prove a point. However, similar errors are possible on a smaller scale: There are C implementations in which pointers of different types have different sizes.
A pointer to an object type may be converted to a pointer to another object type provided the pointer has alignment suitable for the destination type. If it does, then converting it back yields a pointer with the original value. Thus, you may convert pointers to void * to pointers to void and back, and you may convert pointers to void * to pointers to int * and back, provided the alignments are suitable (which they will be if the pointers were returned by malloc and you are not using custom objects with extended alignments).
In general, you cannot write using a pointer to an object type and then read the same bytes using a pointer to a different object type. This violates aliasing rules. An exception is that if one of the pointers is to a character type. Also, many C implementations do support such aliasing, but it may require setting command-line options to enable such support.
This prohibition on aliasing includes reinterpreting pointers. Consider this code:
int a;
int *b = &a;
void **c = (void **) &b;
void *d = *c;
int *e = (int *) d;
In the fourth line, c points to the bytes that b occupies but *c tries to interpret those bytes as a void *. This is not guaranteed to work, so the value that d gets is not necessarily a pointer to a, even when it is converted to int * as in the last line.
Under the C Standard, the behavior of the code you gave is undefined because you allocated an array of void pointers and then tried to use it as an array of int pointers. There is nothing in the Standard that requires these two kinds of pointer to have the same size or alignment. Now if you had said
void * bar = malloc(sizeof(int*) * NUM_ELEMENTS);
int ** fubar = bar;
Then all would be fine.
Now on the vast majority of machines, an int* and a void* will actually have the same size and alignment. So your code ought to work fine in practice.
Additionally, these two are not equivalent:
void ** foo = malloc(sizeof(void *) * NUM_ELEMENTS);
void * bar = malloc(sizeof(void *) * NUM_ELEMENTS);
This is because foo can be dereferenced at any element to get a void pointer, while bar cannot. For example, this program is correct and prints 00000000 on my 32-bit machine:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
void **a = calloc(10, sizeof(void*));
printf("%p\n", a[0]);
return 0;
}
One other point is that you seem to be thinking that type information is explicit in the pointer at the machine level. This is not true (at least for the vast majority of implementations). The type of C pointers is normally represented only while the program is being compiled. By the time compilation is done, explicit type information is normally lost except in debugging symbol tables, which are not runnable code. (There are some minor exceptions to this. And for C++ the situation is very different.)

Explanation of converting from void* to int in c

in my code i have:
int number_compare(void *val1, void *val2) {
if (*(int*) val1 < *(int*s) val2) {
So basically to convert from void* to int i have to cast *(int *).
This works and give me the correct results, could someone please tell me why though or point me to a thread that explains it. I have already looked and cannot find an answer I understand.
That's not converting a void * to an int. It's interpreting whatever the void * is pointing at as an int. Break it down:
val1 // void pointer - not dereferenceable
(int *)val1 // pointer to 'int'
*(int *)val1 // the 'int' being pointed to
So your function is getting passed two pointers: it then interprets them as pointers to int and dereferences them, comparing the two int values being pointed to.
In contrast, converting from a void * to an int would look something like this:
int x = (int)val1;
But that's almost certainly not what you want - first because int is signed, and pointers aren't, and second because int and pointer types might not be the same size.
first thing void pointer cannot be defreferenced. maybe because it doesn't yet know how to fetch data. (i.e) if its char should fetch 1 byte, int 4 bytes...
so here first you are converting some address (void pointer) to int pointer.
(int*) val1;
later to fetch the value from that address [now the system knows it should take data from 4 bytes from that address : val1].
*(int*)val1
this 'll give you the data in that address.
This is formally said to be casting "(data_type) data" casting the data to specified data_type;

dereference an array of void pointers

I have a set of void pointers which I would like to put in an array of void pointers. I start with malloc:
void **p2vals=malloc(nelems*sizeof(void*));
..which gives me an array of pointers to pointers. But then I want to dereference p2vals like *p2vals which supposedly gets me one void pointer. Of course the compiler doesn't like it but I have a need for it. I want to set
*(p2vals+someoffset)=somevoidptr;
If you want to store memory address as a variable, I suggest you to use uintptr_t instead of void *.And if you want write or read any offset, just do (uintptr_t)((char *)(pointer) + offset).
Consider,
int a = 5;
int *p = &a;
In this case we indicate to the compiler that p is going to point to an integer. So it is known that when we do something like *p , at runtime, the no. of bytes equal to size of an int would be read.
Dereferencing void pointers, the compiler will not understand how many bytes to read exactly. You need to typecast them to some type before
using them

Resources