I have a question about locating an index.
suppose I have a "relative" index in an array (that was allocated with malloc), or basically an index that doesn't tell me where I am really. how can I find the "absolute" index?
I'm trying to use binary search to locate a number in an array but I also need the index, and when I do it with recursion I loose the actual index.
I was thinking since it is an array maybe I can subtract sized or something (suppose it's an ints array) to figure out how many steps I made from the begining but I can't quite figure it out. can you help?
Assuming that by relative index you mean a pointer inside the array, you can get its offset using pointer arithmetic:
int *array = malloc(100*sizeof(int));
// Let's say you've got a pointer to an array element somehow,
// through your recursive search or in any other way.
// I'll assign it directly for simplicity:
int *ptr = &array[23];
int absIndex = ptr - array; // This equals 23
The compiler deals with dividing out the sizeof the array element for you, so the result of the subtraction does not change if your array elements are doubles, chars, structs, or anything else. The pointer types of ptr and array need to match, though.
Related
If I have:
int A[10][20];
printf("%p",A[3]);
it will print the address of A[3][0].
However, I'd like to know if this one dimensional array A[3] containing pointers really exists, or it is calculated in some way.
The way you have defined A means that the compiler will allocate for it a contiguous block of memory large enough to hold 10 x 20 (200) integers; see here (scroll down to "Multidimesional arrays"). As I'm sure you realize, if you were to do printf("%p", A); you would see the address of the beginning of that allocated block.
Now, when the compiler sees the expression A[3], it will add what it calculates as the necessary amount of "integer sizes" to the base address (that of A, or A[0][0]); in this case, it will add "3" (the index specified) multiplied by the combined size of all the other dimensions (in this case, there's only one, which is 20).
So, in your case, there is no actual array of pointers; just a memory block that the compiler can interpret according to how you described any part(s) of it.
However, in a more versatile approach, one can actually define a 2D array in terms of an actual array of pointers, like so:
int **A;
A = malloc(10 * sizeof(int*));
for (int n = 0; n < 10; ++n) A[n] = malloc(20 * sizeof(int));
In this case, using printf("%p",A[3]); would still be valid, but it would give a very different offset value from printf("%p",A); or printf("%p",A[0]);.
It's also, perhaps, worth noting that, even though these two different declarations for A can both resolve an individual element through an expression like A[i][j] (but the compiler would evaluate the addresses differently), there is here scope for major confusion! When, for example, passing such an array to a function: if the function expects data allocated in the second form, and you give it an array defined in the first form (and vice versa), you're gonna get major undefined behaviour .
yes there is a way to calculate the position:
for A[i][j]
the position of the memory block will be
pos = A + i*(number_of_columns_in_each_row) + j
here A is the pointer to the first element of the array
However, I'd like to know if this one dimensional array A containing pointers really exists, or it is calculated in some way.
The way you defined the array A :
int A[10][20];
does not contain any pointers as elements of the array. it contains only integer elements.
if you want to make an array of pointers, which should be assigned to int-variables is defined like that:
int *A[10][20];
You also can set a pointer to the start of the array, which means element [0] [0]
by using:
int *pointer;
int *A[10][20];
pointer = &A;
You also be able to set the pointer slightly forwards according to each element by increase the pointer.
pointer++;
int (*mapTerrain)[10] = (int (*)[10])malloc(sizeof(int[10][10]));
free(mapTerrain);
Someone on this site suggested these 2 lines for working with dynamical 2d arrays in C. Dimensions are [10][10]. Problem is, I'm not sure I understand them correctly. If I had to explain these 2 lines I'd say the following:
On the left we have an array of int pointers with size 10. (Can't explain the casting, I myself would expect it to be int *).
What's being passed to malloc is an array of int-s sized [10][10]. (Why isn't it ...malloc(sizeof(int*10*10));?) What allows us to pass an array to malloc instead of size_t size?
As for the free(mapTerrain); line. How come one free is enough? From what I remember you have to call free for every row of a dynamical 2d array.
The cast of the result of malloc is just clutter and not necessary.
The most correct, formal version would be:
int (*mapTerrain)[10][10] = malloc(sizeof(int[10][10]));
This is an array pointer to a int [10][10] array. However, such a pointer is a bit painful to work with in practice, since to get an item we have to do:
*mapTerrain to get the array pointed at from the array pointer.
(*mapTerrain) parenthesis to not trip over operator precedence.
(*mapTerrain)[i][j] to get a single item.
As a trick, we can instead use a pointer to the first element of the int[10][10]. The first element is of type int[10], and so an array pointer to that element is int(*)[10]. With this type, we can do mapTerrain[i][j] as expected, because i means "give me array number i" through pointer arithmetic.
This trick is essentially the same thing as when we do something like
char* ptp = malloc(sizeof("hello"));`
Here we don't point to the whole array either, we point at the first element of it.
sizeof(int[10][10]) is 100% equivalent to sizeof(int*10*10) (or 400 for that matter), but the first is self-documenting code, showing that we are expecting to use the allocated data as an array int[10][10].
One free is enough because there is just one malloc. You allocate the whole 2D array as a contiguous chunk of memory.
Further reading: Correctly allocating multi-dimensional arrays.
This question already has answers here:
How to find the size of an array (from a pointer pointing to the first element array)?
(17 answers)
Closed 8 years ago.
I have the following code in C:
int array[5] = {0,1,2,3,4};
int * p = &array[0];
how to use the pointer p to get the size of this array p point to?
Sorry, this is actually impossible. The size of an array is not saved anywhere. You'll have to do it yourself.
It can't be done just from a pointer. The pointer is literally the address in memory of the first element of the array. The array size is not automatically associated with this pointer. You must keep track of the size yourself.
One workaround you can use is to reserve a special value for your array elements, say -1. If you can arrange for your last element to always have this value, then you can always find the end of the array by searching through it for that value. This is why strings have a null terminator, so strlen() and family can find the end of the string.
The short answer: In C, an array size cannot be retrieved from a pointer. The size must be passed separately.
The slightly-less-short answer: In C, a pointer is just an address to a spot in memory. The pointer does not even guarantee that there is a valid array or variable here; it is just a descriptor of a memory location.
In fact, in C, the concept of an array "size" is somewhat loose. A certain amount of consecutive memory can be allocated, but there is no checking as to if a pointer leaves this memory.
For example:
int a[] = {1, 2, 3};
int b = a[7];
will compile properly. C does not have any bounds checking!
you can not know the size of array using pointer to it. you cant determine since there is no way to know the end of array or to know that we reached the last element of array.
So, after reading 5 previous answers, here a better one:
a) You cannot get the element count of an array using a pointer.
Common workaround are:
Using a sentinel value (see C-String aka asciiz)
Passing the length separately. (see counted strings using mem*())
Actually using a struct, resp. reserving element 0 (or -1) for a lenght value. (also see counted strings).
Just allocate a whopping big amount of memory you know will suffice and not bother with the actual length at all. Getting this wrong is fun and easy to do.
b) You can get the element count of an array using the array name:
struct foo[my_expr];
ìnt count = sizeof array / sizeof *array;
It's been a while since I looked at C code, but I'm trying to make sure I understand what's going on here. Someone has declared this (has more members in their code):
int trysizes[] = { 64, 64, 128, 64, };
Then later they use this as part of a for loop:
sizeof(trysizes)/sizeof*(trysizes)
I'm thinking the first part is the number of bytes in the array and the second part must be the size of each array member giving us the number of items in the array. Is this a standard way to calculate array length and what is the second sizeof actually doing?
Yes, after fixing the confusing syntax so this becomes
sizeof(trysizes)/sizeof(*trysizes)
or even better
sizeof(trysizes)/sizeof(trysizes[0])
this is the preferred way of computing the number of elements of an array. The second sizeof indeed computes the size of element 0 of the array.
Note that this only works when trysizes is actually an array, not a pointer to one.
You got it. The second sizeof in the denominator de-references the first element of the array, yielding the size of element 0. sizeof knows the total buffer size of an array variable - the numerator - and so this idiom will yield the number of elements in the array.
In my experience this is an uncommon expression of this particular idiom, usually I've seen, and I use:
sizeof(var)/sizeof(var[0]);
This more clearly identifies the variable as an array and not a pointer.
This is a pretty common trick, but be aware that it only works if the variable is declared as an array, e.g. this won't work on an array that's been converted to a pointer as a function parameter.
The keypiont is that,when using sizeof, although we mostly use int a; sizeof(a); , we can also omit the parentheses, like this: int a; sizeof a;
So in this case, sizeof*(trysizes) == sizeof *trysizes == sizeof(*trysizes)
My question is both specific to an assignment I'm working on and conceptual about the relationship between pointers and arrays. I'm writing a hash table in the form of an array of pointers to sorted lists. I've created a struct to define a type for the hash table and the number of elements in the table is defined in a macro. Since the size of the table is variable, the struct needs to contain a pointer to the table itself - a pointer to an array of pointers. My problem revolves around the idea that a pointer to some data type is the same as the label for the first element of an array of that data type.
I have a data type SortedList. As I understand things, SortedList* can be interpreted as either a pointer to a single SortedList or as a pointer to the first element of an array of SortedList's. Expanding on that, SortedList** can be an array of SortedList pointers and SortedList*** can be a pointer to that array. This is what I have in my hash table struct. My first question is, is my understanding of this correct?
In the function that creates the hash table I have this:
SortedList** array;
if ((array = calloc(size,sizeof(SortedList*))) == NULL) {
// error allocating memory
printf("Memory Error\n");
return NULL;
}
table->arrayPtr = &array;
So array is intended to be my array of SortedList pointers and arrayPtr is the SortedList*** type in my hash table struct. I'm using calloc because I think it will initialize all of my pointers to NULL. Please let me know if I'm mistaken about that. This all compiles with no errors so, as far as I know, so far
so good.
I have function that inserts data into the table that first checks to see if this pointer has not been used already by checking to see if it points to NULL, if not, it creates a SortedList for it to point to.
int i = index->hashFunc(word);
SortedList*** table = index->arrayPtr;
if (*(table +i) == NULL){
return 0;
}
So it seems to me that dereferencing (table +i) ought to give me a SortedList** - the ith element in an array of SortedList pointers - which I can then check to see if it's set to NULL. Unfortunately, the compiler disagrees. I get this error:
error: invalid operands to binary == (have ‘struct SortedList’ and ‘void *’)
So somewhere along the line my reasoning about all this is wrong.
You might need to read up a little bit more on arrays and pointers in C because I don't think you completely grasp the concept. I could be wrong but I doubt you'd need a three level pointer to achieve what you're trying to do; I think you might be confusing yourself and thinking that if you want to point to an array's data you need to point to the actual array (&array), which is essentially a pointer itself. Drawing a picture can also really help to visualise what's going on in memory.
An array is merely a block of sequential data, where the variable's name in C (without any [ ], which would get an element from the array) points to the first element in the array. The two lines in the example below are equivalent (where array is obviously an array):
int *p_array;
p_array = array; /* equivalent */
p_array = &array[0]; /* equivalent */
You could then use p_array exactly the same way as if you were to use array, ie.
p_array[3] == array[3]
The unnecessary thing that some people might do when they're learning is have a pointer to a pointer to an array (which I think is what you're doing):
int **p_p_array = &array;
And then to access the elements of array they would have to dereference the pointer and then use array notation to specify the element in the array:
*p_p_array[3] == array[3]
What we've actually done here is store the memory address of array (which itself is a pointer to the first element), which we then have to dereference to get to the first element, and then we move 3 positions forward to get to the fourth element (array[3]).
In the first example it's so much simpler and more logical, since we're storing a pointer to the first element in the array and having the pointer act in the same way as our initial array variable.
I recommend you draw out what you're trying to do on a piece of paper/whiteboard to see what you're doing wrong and it may then become obvious how to properly implement it the right way. My whiteboard is one of my best tools when I'm coding something.