Loop control in C using pointers for an array of structures - c

I am a newbie and am trying to understand the concept of pointers to an array using the example below. Can anyone tell me what the exit condition for the loop should be?
The while loop seems to be running forever but the program terminates with no output.
Thank you.
typedef struct abc{
int a;
char b;
} ABC;
ABC *ptr, arr[10];
int main()
{
ptr = &arr[0];
int i;
for(i = 0; i < 10; i++){
arr[i].a = i;
}
while(ptr!=NULL){
printf("%d \n", ptr->a);
ptr++; //Can I use ptr = ptr + n to skip n elements for some n?
}
}

while(ptr!=NULL){
This will run until ptr becomes NULL. Since it points to the first element of the array, and it's always incremented, and we don't know any other implementation detail, it may or may not become NULL. That's not how you check for walking past the end of the array. You would need
while (ptr < arr + 10)
instead.
Can I use ptr = ptr + n to skip n elements for some n?
Of course. And while we are at it: why not ptr += n?

The loop isn't infinite, it stops when ptr == 0.
Assuming you have a 32bit computer, ptr is 32 bits wide.
SO it can hold numbers from 0 to 4294967296-1 (0 to 2 ^ 32 -1).
Each time through the loop it adds 8 to ptr.
Eventually ptr will get to be 4294967296-8.
Adding 8 to that results in 4294967296 - but that is an overflow so the actual result is 0.
Note: This only works if PTR happens to start at a multiple of 8.
Offset it by 4 and this would be an infinite loop.
CHange the printf from "%d" to "%x" - printing the numbers in hex will make it more clear I think.

Related

why a array-pointer gives me different values

The code goes
#include<stdio.h>
int sumOfElements_new(int *A, int size){ // int *A or int A[] same thing
int i, sum = 0; // remember arrays decay as pointers in other functions besides main
for (i =0; i<size;i++){
sum += A[i]; // A[i] = *(A+i)-> value at that address
}
return sum;
}
int main(){
int A[] = {1,2,3,4,5};
int size = sizeof(A)/sizeof(A[0]);
int total = sumOfElements_new(&A[0], size);
printf("%d\n", &A[4]);
printf("Sum of elements = %d\n", total);
printf("Size of A = %d and size of A[0] = %d\n", sizeof(A), sizeof(A[0]));
return 0;
}
Now when I do something like this
int total = sumOfElements_new(&A[3], size);
the result is
Sum of elements = 30
Size of A = 20 and size of A[0] = 4
whenever I use &A[1] to any &A[6], it gives me different values.
Then why calling it in
int size = sizeof(A)/sizeof(A[0]);
gives me the correct answer of the Sum of the elements but, using &A[1-6] the answer goes up and its not even memory address??
Given how you define size, (e.g) int size = sizeof(A)/sizeof(A[0]); you can [only] do:
sumOfElements_new(&A[0],size)
If you use (e.g.) &A[3], you can't pass:
sumOfElements_new(&A[3],size)
because you're telling the function to sum past the end of the array. This is UB (undefined behavior). The program will fetch the data beyond the end, but that data is random (it is just whatever happens to be there).
You have to shorten the size/length you pass to the function. What you'd want is:
sumOfElements_new(&A[3],size - 3)
UPDATE:
May want to comment on printf("%d\n", &A[4]); as well..
This presents another issue. You [probably] want to print the value of the element of the A that has index 4.
The indexing is correct (i.e. it does not go beyond the end of the array), but you're passing the address of that element and not its value.
With your original code, if you compiled with warnings enabled (e.g. using the -Wall option--which you should always do, IMO), the compiler would flag this statement.
That's because you're passing an address [which on modern x86 cpus is probably 64 bits]. That's an unsigned quantity and you're trying to print it in decimal using only 32 bits [because an int is usually only 32 bits].
So, to print the value, you'd probably want:
printf("%d\n", A[4]);
If you truly wanted to print the address of that element [a more advanced usage], you could do:
printf("%p\n", &A[4]);

Pointers and arrays in c

Can any one explain what does the following code do? As per my knowledge this program converts the number to the given base but I can't understand how it is done?
#include<stdio.h>
char *fun(unsigned int num, int base);
int main()
{
char *s;
s=fun(128, 2);
s=fun(128, 16);
printf("%s\n",s);
return 0;
}
char *fun(unsigned int num, int base)
{
static char buff[33];
char *ptr = &buff[sizeof(buff)-1];
*ptr = '\0';
do
{
*--ptr = "0123456789abcdef"[num %base];
num /=base;
}while(num!=0);
return ptr;
}
What does this line *--ptr = "0123456789abcdef"[num %base]; in the above code means?
You can split *--ptr = "0123456789abcdef"[num %base]; into several separate statements so it becomes more clear:
*ptr= is the same as ptr[0]=, i.e. it stores some value at location 0 of the memory where ptr is poiinting to. (End of the buff during the first loop iteration)
--ptr decreases the value of ptr by 1 (after it is used). So it points to to the previous (second last) location of buff.
Combined, *--ptr = first sets the value of ptr[0] and then decreases the pointer.
Next, "0123456789abcdef" char(acter) array, so "0123456789abcdef"[...] gets a value from the array of chars at the specified index.
The used index num % base' calculates the remainder after dividingnumbybase`
So combined the complete line grabs a value from the char array (at index num % base), stores it at the location where ptr it pointing to and decreases ptr (i.e. the points the the previous memory location)
About the actual working of the application: What this is doing is checking the remainder of num (for the given base) and grabs the correct (char)-value from the string (i.e. gets the representing number). Next, it divides the number by its base, in order to be able to determine the next remainder, and so on.
This would result in the representation being reversed (reading to right to left), so the buffer is written from the back to the start (hence the --ptr part, instead of ++ptr).
I think your main confusion lies in the statement
"0123456789abcdef"[num %base];
Well, this can be rewritten as a combination of
char arr[] = "0123456789abcdef";
and
arr[num %base];
Other than that, *--ptr = can be broken down to
--ptr;
*ptr = <some value>;
As far as the program logic in considered, you're quite right and the digit is chosen by using the [num %base] position from the array holding the digits.
ptr is a pointer that holds memory address of a char variable.
--ptr simply decrements the pointer (now it'll point to the previous object of the same type). * is simply accessing the value.
"0123456789abcdef"[num %base]
will return the char at the position num % base.
Here *--ptr is decrement the one position in a array and pointing to one place.
So when you are using that "0123456789abcdef"[num %base]. answer of num % base is giving
one output. Take that is two. So it will return the character that is placed on the second place.
So based on the answer of num % base is storing the value in the given string.
My analysis is as follows after googling in net.
Firstly, "0123456789abcdef" is used to pick values if it is decimal values are picked from 0-9, if it is octal values are picked from 0 to 7, if it is hexa decimal values are picked from 0-f, if it is binary only between 0 and 1.
Simple "0123456789abcdef" can be treated as character array i.e. char a[] = "0123456789abcdef";
and "0123456789abcdef"[num % base] means a[num % base]. Each time the the number given is divided with base the character is picked up from the string.

Using negative number as array index

I came along a competitive question that asks the output of the following:
#include <stdio.h>
int main()
{
int a[] = {0,1,2,3,4};
int i, *ptr;
for(ptr = a+4, i=0; i <=4; i++)
printf("%d", ptr[-i]);
return 0;
}
I did read this topic: Are negative array indexes allowed in C? However it was unclear to me how the -ve symbol generates the array in the reverse order, ie. 4, 3, 2, 1, 0.
First, recall that in C the expression ptr[index] means the same thing as *(ptr+index).
Now let's look at your expression again: ptr is set to a+4 before the loop; then you apply -i index to it. Therefore, the equivalent pointer arithmetic expression would be as follows:
printf("%d", *(a+4-i));
This expression iterates the array backwards, producing the results that you see.
The reason it works is because the [] operator does pointer addition.
When you reference
a[x]
Whats actually happening is its taking the memory address of a and adding the sizeof(int)*x
So if you set ptr to a+4, you are going to a+sizeof(int)*4
then, when you put in a negative value, you move backwards through the memory address.
ptr[-i] decays into *(ptr + (-i)). At the first iteration, when i = 0, ptr[-i] accesses last element of a array, because initially ptr was set to be equal a + 4, which means - take address of beginning of a and add 4 * sizeof(int) (because ptr was of size int). On every next iteration, when i is incremented, previous element of array is accessed.
In is for statement
for(ptr = a+4, i=0; i <=4; i++)
pointer ptr is set to a+4 It could be done also the following way
ptr = &a[4];
If you tray to output the value pointed to by the pointer as for example
printf( "%d\n", *ptr );
you will get 4. That is the pointer points to the last element of the array.
Inside the loop there is used expression ptr[-i] . for i equal to 0 it is equivalent to ptr[0] or simply to *ptr that is the last element of the array will be outputed.
For i equal to 1 expression ptr[-i] is equivalent to a[4 - 1] or simply a[3]. When iequal to 2 when expression ptr[-i] is equivalent to a[4 - i] that is a[4 - 2] that in turn is a[2] and so on.
SO you will get
4321
a+4 gives a pointer to the fifth element of a. So ptr refers to that location.
Then the loop counts i from 0 up to (and including) 4.
The dereference ptr[-i] is equivalent to *(ptr - i) (by definition). So, since i is 0 and ptr is a+4, it's equivalent to a+4-0, then a+4-1, then a+4-2, and so on until a+4-4, which is (obviously enough) equal to a.
As I mentioned in my comment in C/C++
a[b] == *(a+b) == b[a]
For your case all of these is fine
printf("%d", *(a + 4 - i));
printf("%d", a[4 - i]);
printf("%d", 4[a - i]);
...

int* vector accepts only the first given value

I'm experiencing some troubles with my code written in C. It's all about an int * vector intially declared and dynamically allocated but when it comes to filling it with data it stuck on the first element and won't increment the counter to fill the rest of the vector
my header file : instance.h
struct pbCoupe
{
int tailleBarre;
int nbTaillesDem;
int nbTotPcs;
int * taille;
int * nbDem;
};
my code : coupe.c
pb->taille = (int*) malloc (pb->nbTaillesDem * sizeof(int));
pb->nbDem = (int*) malloc (pb->nbTaillesDem * sizeof(int));
while (i < pb->nbTaillesDem)
{
fscanf_s(instanceFile,"%s",data,sizeof(data));
pb->taille[i] = atoi(data); //<-- here is the problem !! it only accept the first value and ignore all the rest
printf("%s\n",data);
fscanf_s(instanceFile,"%s",data,sizeof(data));
pb->nbDem[i] = atoi(data); //<-- the same problem here too !!
printf("%s\n",data);
i++;
}
Your interpretation of sizeof is wrong, since data is the buffer that the string is being parsed into.
It returns the size of the the variable, not the size of the the what the variable (or namely a pointer) points to
Strings in C are all pointer to the size would be 4 bytes on a 32-bit system, 8 on a 64-bit.
Since it prints all the number it reading more numbers that intended with each loop iteration 4 bytes = 4 characters, atoi on parses the first integer and returns,
EDIT: If it is a buffer array, sizeof returns the size of the array.
You need to make sure you are only reading in a single number per iteration of the loop to solve this issue.
If you don't care for the literal string, best thing you can do is use:
fscanf(instanceFile, "%d", ((pb->taille) + i)));
//and store the integer into the index right away
//last param same as &pb->taille[i]

Does making the iterator a pointer speed up a C loop?

I ran the following:
#include <stdio.h>
typedef unsigned short boolean;
#define false 0
#define true (!false)
int main()
{
int STATUS = 0;
int i = 0;
boolean ret = true;
for(i = 0; i < 99999; i++)
{
ret = ret && printf("Hello, World.");
}
if(!ret)
{
STATUS = -1;
}
return STATUS;
}
It completes in just under a second. Typically 0.9 - 0.92.
Then I changed int i = 0; to int *i = 0; and now I am getting execution times under 0.2 seconds. Why the speed change?
Your runtime is dominated by the time required to print to the console. i++ on an int* will increment the pointer by the size of a pointer. That will be either 4 or 8 depending on your computer and compiler settings. Based on the numbers you report, presumably it would be 4. So printf is executed only a quarter as many times.
Typically, printing to a console will be several orders of magnitude larger than any gain with micro optimization you could do to such a loop.
Are you really sure your second version prints hello world 99999 times as well ?
When you're doing for(int *i = 0; i++ ; i < 99999 ) , you're cheking if the pointer value(an address) is less than 99999, which doesn't normally make a lot of sense. Incrementing a pointer means you step it up to point at the next element, and since you have an int*, you'll increment the pointer by sizeof(int) bytes.
You're just iterating 99999/sizeof(int) times.
Your comment on nos's answer confirmed my suspicion: it's pointer arithmetic. When you increment an int pointer using ++, it doesn't just add one to the number, but it actually jumps up by the size of an integer, which is usually 4 (bytes). So i++ is actually adding 4 to the numeric value of i.
Similarly, if you use += on a pointer, like i += 5, it won't just add 5 (or whatever) to the numeric value of i, it'll advance i by the size of that many integers, so 5*4 = 20 bytes in that case.
The reasoning behind this is that if you have a chunk of memory that you're treating as an array,
int array[100]; // for example
you can iterate over the elements in the array by incrementing a pointer.
int* i = array;
int* end = array + 100;
for (i = array; i < end; i++) { /* do whatever */ }
and you won't have to rewrite the loop if you use a data type of a different size.
The reason is because the increment operates differently on pointers.
On ints, i++ increments i by 1.
For pointers, i++ increments by the size of the pointed-to object, which will be 4 or 8 depending on your architecture.
So your loop runs for only 1/4 or 1/8 of the iteration count when i is a pointer vs when i is an int.
The correct way to do this test with a pointer would be something like:
int i;
int *i_ptr = &i;
for (*i_ptr = 0; *i_ptr < 99999; *i_ptr++) {
...

Resources