I was reading about function pointer. That it contains address of instructions. And there I encountered one question to find an element in array using function pointer. Here is the code.
#include <stdio.h>
#include <stdbool.h>
bool compare(const void* a, const void* b)
{
return (*(int*)a == *(int*)b);
}
int search(void* arr, int arr_size, int ele_size, void* x, bool compare(const void*, const void*))
{
char* ptr = (char*)arr; // Here why not int *ptr = (int*)arr;
int i;
for (i = 0; i < arr_size; i++)
{
if (compare(ptr + i * ele_size, x))
{
return i;
}
}
return -1;
}
int main()
{
int arr[] = { 2, 5, 7, 90, 70 };
int n = sizeof(arr) / sizeof(arr[0]);
int x = 7;
printf("Returned index is %d ", search(arr, n, sizeof(int), &x, compare));
return 0;
}
In the search function char *ptr = (char*)arr; is used which is giving perfect answer = 2.
But when I have used int *ptr = (int*)arr; it gives -1 as answer.
Why is this? Can anyone explain this?
A char is the smallest addressable unit in any C program, and on most system it corresponds to a single byte. That treats the array as a generic sequence of bytes, and uses the ele_size to calculate the byte-position of each element with ptr + i*ele_size.
If you use int *ptr then the byte-position calculation will be wrong by a factor of sizeof(int) (typically 4), since the pointer arithmetic will be done in units of the base type (int instead of char).
The function search knows nothing about what is the type of elements of the array pointed to by the pointer arr of the type void *.
So casting the pointer to the type int * does not make a sense. If to do so then the expression ptr + i*ele_size where the pointer arithmetic is used will produce an incorrect result.
That it contains address of instructions
There is a subtle difference between normal (object) pointers and function pointers. It is not possible to access the single instructions of a function - they do not have the same length.
With other pointers the increment (arithmetic) is adapted to the type, whether as p[i] or p + i or *(p+i).
Side note: there still is int at the bottom of the call chain:
return (*(int*)a == *(int*)b);
Related
code:
int arr[5] = {1,2,3,4,5};
int (*p)[5] = &arr;
printf("p:%p\n",p);
printf("*p:%p\n",*p);
result: p = *p = arr = 0x7ffee517c830 they are all the address of the array
The right way to use p to visit arr[i] is *(*p+i)
The type of pointer p is int(*)[5], so p point to an array which type is int [5]. But we can't say that p point to an invisible shell of arr, p is a variable after all. It stores the address of arr, which is also the address of arr[0], the first element of arr.
I thought *p will get me 1, which is the first element of arr.
The dereference operation means take the value in p as address and get the value from this address. Right?
So p stores the address of arr,which is 0x7ffee517c830 here, and 1 is stored in this address. Isn't **p illegal? The first dereference give us 1, and second dereference will use 1 as address which is illegal.
What I am missing?
The result of *p is an lvalue expression of array type. Using (*p) is exactly the same as using arr in any expression you could now think of.
For example:
&*p means &arr
**p means *arr (which is legal).
(*p)[i] means arr[i].
sizeof *p means sizeof arr.
Arrays are not special in this regard. You can see the same phenomenon with int x; int *q = &x;. Now *q and x have exactly the same meaning.
Regarding your last paragraph, I think you are confusing yourself by imagining pointers as glorified integers. Some people teach pointers this way but IMO it is not a good teaching technique because it causes the exact confusing you are now having.
If you dereference an int(*)[5] you get an int[5] and that's all there is to it. The data type matters in dereferencing. It does not make sense to talk about "dereferencing 0x7ffee517c830". Again this is not peculiar to arrays; if you dereference a char ***, you get a char ** etc.
The only way in which arrays are "different" in this discussion is what happens if you try to do arithmetic on them, or output them, etc. If you supply an int[5] as a printf argument for example, there is implicit conversion to int * pointing at the first of those 5 ints. This conversion also happens when applying the * operator to an int[5], which is why you get an int out of that.
p is declared as a 'pointer to int[5]'.
arr is declared as an 'int[5]`
so the initializer p = &arr; is not really that strange. If you substituted any primitive type for int[5] you wouldn't bat an eye.
*p is another handle on arr. so (*p)[0] = 1.
This really only comes up in wierd cases. It's most natural where you dereference the pointer-to-array using the subscript operator. Here's a contrived example where I want to pass a table as argument.
#include <stdio.h>
int print_row_range(int (*tab) [2], int first, int last)
{
int i;
for(i=first; i<= last; i++)
{
printf("{%d, %d}\n", tab[i][0], tab[i][1]);
}
}
int main(int argc, char *argv[])
{
int arr[3][2] = {{1,2},{3,4},{5,6}};
print_row_range(arr,1,2);
}
This example treats the table as an array of rows.
Dereferencing doesn't give you a value. It gives you an object, which can be used as a value of its type if it can be converted to.
*p, being identical to arr, is an object of an array of 5 ints, so if you want to get an integer from the array, you must dereference it again like (*p)[3].
Consider a bigger example:
int arr[5][5];
int (*p)[5] = arr;
Now you get arr[0] with *p, which itself is an array of 5. Here comes the difference:
*( p+1) == arr[1];
*(*p+1) == arr[0][1];
^ ^^^
Got the point?
One use case is to be able to allocate with malloc an 2D (or more) pointer of arrays with only one malloc:
#include <stdio.h>
#include <stdlib.h>
static int (*foo(size_t n))[42] {
return malloc(sizeof *foo(0) * n);
// return malloc(sizeof(int [n][42]); works too
}
int main(void) {
size_t n = 42;
int (*p)[42] = foo(n);
if (!p) {
return 1;
}
printf("p:");
int accu = 0;
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < sizeof *p / sizeof **p; j++) {
p[i][j] = accu++;
printf(" %d", p[i][j]);
}
}
printf("\n");
free(p);
}
I think this very funny.
One more with VLA:
#include <stdio.h>
#include <stdlib.h>
static void *foo(size_t elem, size_t n, size_t m) {
return malloc(elem * n * m);
}
int main(void) {
size_t n = 42;
int (*p)[n] = foo(sizeof **p, n, n);
if (!p) {
return 1;
}
printf("p:");
int accu = 0;
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < sizeof *p / sizeof **p; j++) {
p[i][j] = accu++;
printf(" %d", p[i][j]);
}
}
printf("\n");
free(p);
}
So I'm starting to understand the basics of generic programming in C. I'm currently building a program that says if a value occurs or not in a given sequence of number.
I think that the bug occurs in the cmpValues function. Would anyone point it out? (for example, for want=4 and v={1,2,3,4,5}, the program says that want is not in v)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void *search(const void *x, const void *t, int n, int d, int (*cmpValues)(const void *, const void *)){
char *p = (char *)t;
int i;
for(i=0;i<n;++i)
if(cmpValues(x,p+i*d))
return p+i*d;
return NULL;
}
int cmpValues(const void *a, const void *b){
if((char *)a == (char *)b)
return 1;
return 0;
}
int main() {
FILE *f = fopen("datein.txt", "r");
FILE *g = fopen("dateout.txt", "w");
int *v, n, i, want;
fscanf(f, "%d", &n);
v = (int *)malloc(n * sizeof(int));
for(i = 0; i < n; ++i)
fscanf(f, "%d", v + i);
fscanf(f, "%d", &want);
if(search(&want, v, n, sizeof(int), cmpValues))
fprintf(g, "The value %d is found at position %d.\n\n", want, search(&want, v, n, sizeof(int), cmpValues));
else
fprintf(g, "The value does bot occur in the given sequence.\n\n");
return 0;
}
In cmpValues, you are comparing 2 objects pointed by 2 void pointers (i.e. you don't know their type, nor their size). Let's assume we are having ints, and that an int has 4 bytes, which is usually the case.
Just for the sake of it, let's assume that the a pointer has value 0x100 (i.e. points to a int from 0x100 to 0x103, inclusive) and b pointer has a value of 0x104 (i.e. points to the int from 0x104 to 0x107).
Now, you are converting them to char* (char has 1 byte) and compare the value of the pointers. Now, the type of the pointer does not matter in comparisons. In that comparison, you will compare memory addresses (in my example, 0x100 and 0x104). Obviously, the only way the function will return 1 is if the pointers would point to the same variable.
Now, in order to fix it, you should compare the values at the memory addresses pointed by your pointers. However, simply dereferencing the pointers:
*((char *)a) == *((char *)b)
won't be enough, since this would compare just the first byte of a with the first byte of b (under the assumption that char has 1 byte). Also, you can't dereference void*.
So, you need to iterate over your variables and compare them byte by byte (this assumes that you know the size of the data type):
int comp(void *a, void *b, int size) {
// convert a and b to char* (1 byte data type)
char *ca = a;
char *cb = b;
// iterate over size bytes and try to find a difference
for (int i = 0; i < size; i++) {
if (*(ca + i) != *(cb + j)) {
return 0;
}
}
// if no difference has been found, the elements are equal
return 1;
}
side note: you don't need to call cauta twice in main.
Say I have a void pointer (more like; array), and I want to get the items inside it.
So, I know that pointer[i] won't work since it's void and I don't know the type; I tried using the offset technique:
void function(void* p, int eltSize){
int offset = 3;
for(i = 0; i<offset; i++){
memcpy(p+(i*eltsize), otherPointer, eltSize);//OtherPointer has same type.
}
//End function
}
This function works good and everything, but the only problem is that at the end of main(..) I get segmentation fault. I know it's because of the pointer and how I accessed the items of it, but I don't know how to correct the problem and avoid segmentation fault.
As pointed out by #sunqingyao and #flutter, you can not use arithmetic with void pointers in Standard C; instead, use a char * (a chunk of bytes a la qsort):
#include <stdio.h>
#include <string.h>
void function(void *ptr, size_t eltSize, void *otherPointer, size_t offset)
{
char *p = ptr;
for (size_t i = 0; i < offset; i++) {
memcpy(p + (i * eltSize), otherPointer, eltSize);
}
}
int main(void)
{
int arr[] = {1, 2, 3};
int otherValue = 4;
function(arr, sizeof *arr, &otherValue, sizeof arr / sizeof *arr);
for (int i = 0; i < 3; i++) {
printf("%d\n", arr[i]);
}
return 0;
}
Quoted from N1570 6.5.6 Additive operators(emphasis mine):
2 For addition, either both operands shall have arithmetic type, or
one operand shall be a pointer to a complete object type and the
other shall have integer type. (Incrementing is equivalent to adding
1.)
Obviously, void isn't a complete object type. Thus, applying + operator on void * invokes undefined behaviour, which may result in segmentation fault or anything else.
One approach to solve your problem would be declaring parameter p as a char *.
Consider this code for qsort:
#include <stdio.h>
#include <stdlib.h>
int values[] = { 88, 56, 100, 2, 25 };
int cmpfunc(const void * a, const void * b)
{
return *(int*)a - *(int*)b;
}
int main()
{
int n;
printf("Before sorting the list is: \n");
for (n = 0; n < 5; n++)
{
printf("%d ", values[n]);
}
qsort(values, 5, sizeof(int), cmpfunc);
printf("\nAfter sorting the list is: \n");
for (n = 0; n < 5; n++)
{
printf("%d ", values[n]);
}
return(0);
}
what does *(int*)a means specifically? It looks like a pointer to a pointer? why cant i do:
**a // dereferrencing twice would get the value, no?
or
*(int *a) // looks about the same. Also why do i need the int?
apologies if this question seemed obvious as I've been looking at this for hours now, and i still cant grasp why that '*' is wrapping around the bracket.
void* and const void* are used in C to stand in for a generic pointer of unknown type. qsort doesn't really know what it's sorting: the callback comparison function cmpfunc does that task. But C is statically-typed, so the callback function needs to have a specific prototype. That's where const void* is useful.
Of course, within your supplied cmpfunc, you know the type of object being sorted, so you are able to cast the const void* to your type. That is what (int*) is doing: it's a cast.
Technically you should cast to const int* instead:
return *(const int*)a - *(const int*)b;
Casting away const can cause you trouble.
A pointer to void can't be dereferenced. Therefore, in the given case it must have to cast to int * before dereferencing.
In *(int*)a, (int*) is casting a to pointer to int and then * outside the parenthesis dereferencing the value at that address.
Greetings,
I am trying to learn pointers in C, I simply want my "addtwo" function to add 2 to every element of the input integer array, yet I get odd compilation errors, here is the non-pointer version which indeed won't properly compile.
addtwo(int *arr[]) {
int i=0;
for(;i< sizeof(arr)/sizeof(int);i++) {
arr[i] = arr[i] + 2;
}
}
main() {
int myarray[] = {1,2,3,4};
addtwo(myarray);
}
Regards
You've some problems. First, you try to pass a int* to a parameter that's type int**. That won't work. Give it type int*:
void addtwo(int *arr){
int i=0;
for(;i< sizeof(arr)/sizeof(int);i++){
arr[i] = arr[i] + 2;
}
}
Then, you need to pass the size in an additional argument. The problem is, that when you pass arrays, you really pass just a pointer (the compiler will make up a temporary pointer that points to the array's first element). So you need to keep track of the size yourself:
void addtwo(int *arr, int size){
int i=0;
for(;i<size;i++){
arr[i] = arr[i] + 2;
}
}
int main(void) {
int myarray[] = {1,2,3,4};
addtwo(myarray, sizeof myarray / sizeof myarray[0]);
}
Now it will work. Also put the return type before them. Some compilers may reject your code, since it doesn't comply to the most recent C Standard anymore, and has long been deprecated (omitting the return type was the way you coded with the old K&R C).
addtwo(int *arr[]) should be addtwo(int *arr)
You cannot use sizeof to get the size of an array from a pointer. Typically you would either pass the size of the array as a separate arg or have some special value marking the last element.
Not to do with the compile error, but...
You have to pass sizeof(arr) to the function instead of calling it in the function. When an array is passed to a function, C no longer sees it as an array, but as a single pointer to memory, so that sizeof(arr) as you are calling it now, will return the size of the pointer arr, which is most likely 4.
Here's what I mean in code:
void addtwo(int *arr, int size){
int i=0;
for(;i< size;i++){
arr[i] = arr[i] + 2;
}
}
int main(){
int myarray[] = {1,2,3,4};
addtwo(myarray, sizeof(arr)/sizeof(int));
return 0;
}
In C a notation int *arr[] is the same as int** arr.
You need to pass a pointer to the first element of the array and the array size. Array types decay to pointers in the context of function parameters. Try:
void addtwo(int *arr, size_t size){
for(size_t i = 0; i < size; i++){
arr[i] = arr[i] + 2;
}
}
int main() {
int v[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
addtwo(v, sizeof v / sizeof v[ 0 ]);
return 0;
}
Though others already gave the correct response, basically you have an array of pointers when you have
int *arr[]
I doubt that is what you want. If you have
int arr[]
then that will also be equivalent to
int *arr
addtwo argument declaration really reads:
arr is an array of pointers to integer
when you probably really want
a pointer to an array of integers
"How to Read C Declarations" has really helped me to grok the topic a while ago, maybe it will do the same for you.