How to access an array within a structure using only pointer arithmetic - c

Is it possible to do the same thing as I did below, but without using [] or ->.
I don't understand why .*(points + 2) doesn't work. Shouldn't this replace array?
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int points[2];
}_student;
int foo(_student *stud);
int main()
{
int second;
_student students[2];
students[1].points[1] = 100;
second = foo(students);
printf("%d", second);
return 0;
}
int foo(_student *stud) // returns 3rd member of the array within a struct
{
int second;
second = (*(stud+1)).points[1]; // Works
//second = (*(stud+1)).*(points+1); ----> Does not work!
return second;
}
The result should be 100.

You don't say what is failing in your code, but whatever it is, it's because of buffer overflow.
Here
_student students[2];
students[2].points[2] = 100;
you can't access students[2] because it's the third element, and your array has only two, accessing the third element invokes undefined behavior, and of course the same goes for points.
In c, an array index starts at 0, instead of 1, hence the second element would be
_student students[2];
students[1].points[1] = 100;
Also don't use that kind of identifier for a type name, it's quite confusing, and generally it's better to make it clear when something is a struct, like in this case.
I would recommend the following
struct student {
int points[2];
};
struct student students[2];
students[1].points[1] = 100;
Edit: Since the question was edited now the above content seems not logical or incorrect, the actual problem is that this syntax
second = (*(stud+1)).*(points+1); /* ----> Does not work for sure ! */
is invalid, the obvious way is
second = *((*(stud + 1)).points + 1); /* ----> Does work! */
or even
second = *((stud + 1)->points + 1); /* ----> Does work! */
I don't understand why .*(points + 2) doesn't work. Shouldn't this replace array?
A good question would be, Why do you think it should work?

Related

How can I change a structure array in C

I need to change the properties of the structure within a function, so I could do a calculation with the properties and set new values,but when i try to change the value of a structure i am getting the following error: cannot convert 'data specs (*) [2]' to 'data specs' for argument '1' to 'void changeValues ​​(data specs)' changeValues ​​(& stats);
Does anyone know how to fix it?
typedef struct
{
char nome;
int vida;
int dano;
int x;
int y;
} dadospecas;
void changeValues(dadospecas *a[]){
a[1]->vida = 5;
printf("%i", a[1]->vida);
}
int main() {
dadospecas stats[2];
stats[1].nome = 'W';
stats[1].vida = 3;
stats[1].dano = 1;
stats[1].x = 4;
stats[1].y = 1;
stats[2].nome = 'F';
stats[2].vida = 33;
stats[2].dano = 11;
stats[2].x = 44;
stats[2].y = 14;
changeValues(&stats);
return 0;
}
In addition to the great answer by #Stuart, you seem to be a little confused on how to handle sending values to your function to be changed, (here you are changing the vida member only). As noted in the other answer, on access, an array is converted to a pointer to its first element. C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3).
To make your function useful (as it is it hardcodes the entire operation), you should provide parameters for a pointer to dadospecas, the index to change and the new value to assign to the vida member. The caller is responsible for ensuring the index to change is within bounds (you can pass the number of elements as an additional index if desired)
If you put those pieces together and change the name of the function to reflect the fact you are only changing the vida member, you could do:
/* pass a pointer to the array as your parameter (inlcude index and value) */
void changeVida (dadospecas *a, int index, int newvida)
{
a[index].vida = newvida;
}
A short example showing the use, and fixing your indexing problem, could be written as:
#include <stdio.h>
#define NSTRUCT 2 /* if you need a constant, #define one (or more) */
typedef struct {
char nome;
int vida,
dano,
x,
y;
} dadospecas;
/* pass a pointer to the array as your parameter (inlcude index and value) */
void changeVida (dadospecas *a, int index, int newvida)
{
a[index].vida = newvida;
}
int main (void)
{
dadospecas stats[NSTRUCT] = {{'W', 3, 1, 4, 1}, {'F', 33, 11, 44, 14}};
for (int i = 0; i < NSTRUCT; i++) { /* loop over each struct */
changeVida (stats, i, stats[i].vida + 5); /* increment vida by 5 */
printf ("stats[%d].vida = %d\n", i, stats[i].vida); /* output new vida */
}
}
Example Use/Output
Where the example simply adds 5 to the existing value of the vida member:
$ ./bin/dadospecas
stats[0].vida = 8
stats[1].vida = 38
If You Pass The Address of stats
While there is no need to pass the address of stats, there is nothing to prevent you from doing it -- it is perfectly fine -- just unnecessary. For sake of argument, let's say you did. Continuing from my comment, in main stats is an array of type dadospecas [2], so when you take the address your type is pointer to array of dadospecas [2]. The formal type is dadospecas (*)[2]
So passing the pointer your function parameter would become: dadospecas (*a)[2].
Within your function to operate on your array, you would first need to dereference the parameter to allow you to operate on the elements of the array, e.g. (*a)[index] and finally to change the vida member you would have:
(*a)[index].vida = newvida;
The changes to the example above to pass the address of stats would be:
/* pass a pointer to array[NSTRUCT] as your parameter (inlcude index and value) */
void changeVida (dadospecas (*a)[NSTRUCT], int index, int newvida)
{
(*a)[index].vida = newvida;
}
int main (void)
{
dadospecas stats[NSTRUCT] = {{'W', 3, 1, 4, 1}, {'F', 33, 11, 44, 14}};
for (int i = 0; i < NSTRUCT; i++) { /* loop over each struct */
changeVida (&stats, i, stats[i].vida + 5); /* increment vida by 5 */
printf ("stats[%d].vida = %d\n", i, stats[i].vida); /* output new vida */
}
}
(same output)
It is simply a matter of keeping the levels of pointer indirection straight and observing C operator precedence.
Look things over and let me know if you have further questions.
I think there are two things you don't understand about arrays in C.
Arrays are indexed starting from 0 and not 1.
The first element of your stats array is stats[0] and the second is stats[1]. You need to change the assignments in your main function, and in your changeValues function if you want it to change the first element of the array.
Arrays are const pointers (i.e. pointers that have a fixed value).
The stats array is really a const pointer to dadospecas. It's a const pointer meaning you can't change the value of stats. You can change the values contained by (i.e. pointed to) by stats.
If you want to define a function that will modify the contents of an array, you don't need to pass a pointer to the array, you can just pass the array.
Your changeValues function should be defined like this:
void changeValues(dadospecas *a){
//put code here.
}
or
void changeValues(dadospecas a[]){
//put code here.
}
In either case, your main function would call changeValues like this
changeValues(stats);
By the way, if you want to check that changeValues has modified the vida member of the first element of stats, I would remove the printf call from the changeValues function and replace it with
printf("%i", stats[0].vida);
in your main function (after the call to changeValues of course).

Passing a struct to a function

So I am trying to pass my struct to a function and I am also trying to assign my variable to the struct, which does not seem to work. I don't know what's wrong with it either.
This is how my code looks:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ACE 1;
#define CardSize 52
#define colors 4
struct MyCards {
int *cards;
char *color[4];
};
void count(struct MyCards record);
int main() {
struct MyCards record;
count(record);
system("pause");
return 0;
}
void count(struct MyCards record) {
int i, j, f;
// I actually want to put this variable and the values into the struct, how do i do it?
char *color[4] = { "Diamon", "Heart", "Spade", "Clubs" };
record.cards = malloc(CardSize * sizeof(int));
for (f = 0; f < 4; f++) {
for (i = 0; i < 13; i++) {
record.cards[i] = (i % 13) + 1;
printf("%d of %s\n", record.cards[i], color[f]);
}
}
}
As you might see, the thing I commented out, I also want to put that variable AND the values that I have assign to it, but I dont know how to do that, would love some help there as well.
C uses pass-by-value. record inside count is a different variable to record in main - a copy is made when you call the function.
If you want main to see the changes you either need to return the changed object (in which case you wouldn't pass it in in the first place, in this example), or use pass-by-reference which you implement by passing a pointer to the object.
Returning the object would look like:
struct MyCard count(void)
{
struct myCard record;
// ... do stuff with record ...
return record;
}
Passing by reference would look like:
void count(MyCard *p_record)
{
// ... do stuff with (*p_record)
}
Also you want record.color[f] = color[f]; as the first line of the f loop. And (as discussed last time you posted about this code) you should be using string or char const *, not char *.
You have to pass a pointer to the struct in order to edit it, or you will edit the variable only in the stack of the function, which will be deleted once the function returns. Try passing &record to your function.
Also change your prototype: you have to accept a pointer to the struct.
When you have a pointer, to resolve the struct you have to use the -> operator. Let's do an example:
records->cards[i] = ...

Segfault when trying to index pointer to pointers in function

I'm trying to do something with an array (malloc-ed), namely arr of a custom struct. The array is passed by reference to a function. I get a segfault whenever I tried to index anything other than arr[0] in the function at runtime (e.g (*arr[1])->i = 3;). Why is this happening?
The full source code is:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 100
typedef struct{
int i;
float f;
}foo;
void doSomething(foo ***arr);
int main()
{
foo **arr = (foo**) malloc (SIZE * sizeof(foo*));
int i;
for(i = 0; i < SIZE; i++)
arr[i] = (foo*)malloc(sizeof(foo));
arr[1]->i = 1;
printf("Before %d\n",arr[1]->i );
doSomething(&arr);
printf("After %d\n",arr[1]->i );
return 0;
}
void doSomething(foo ***arr)
{
(*arr[1])->i = 3;
}
Your problem is the line
(*arr[1])->i = 3;
Because the subscripting operator's evaluation precedes the dereferencing's evaluation it is equivalent to the following:
(*(arr[1]))->i = 3;
This is obviously wrong. You need
(*arr)[1]->i = 3;
therefore.
Notes:
do not cast the result of malloc
add #include <stdlib.h> to resolve the warning
adding an extra level of indirection (foo*** pointing to foo**) is unnecessary; just copy by value
(in addition to the upper note) a good old 1D array should actually be sufficient in your case
call free after malloc
The warning you get is because you forgot to #include <stdlib.h>, so malloc is not declared, so the compiler assumes it should return int. This can lead to all kinds of fun problems. (And you should remove those casts.)
The other problem is in this line: (*arr[1])->i = 3;
Postfix operators (like []) bind tighter than prefix operators (like *), so *arr[1] parses as *(arr[1]).
You can write (*arr)[1]->i instead to fix this, but as it turns out, your function never actually modifies *arr, so there's no reason to pass arr (the other arr, the one in main)'s address to it. Just do this:
void doSomething(foo **arr)
{
arr[1]->i = 3;
}
and call it as doSomething(arr).

C Passing double pointer from function

I am working on a non homework question that I just can't solve no matter what I try.
The problem is one from Project Euler that involves solving for even Fibonacci numbers and summing them together, I chose this one as a chance to learn more about functions, pointers, and working with large numbers that would be best served by not copying their value but instead passing a memory address.
I currently have the following:
/*Second attempt at fibo 4mil
problem.*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
//MAX is 20 for testing reasons
//Actual value is MAX 0X3D0900
#define MAX 20
//Function will accept even fibo numbers
//then sum them together for output later
void evenCount (double* evenPoint);
int main(void){
double firstVar = 0;
double secondVar = 1;
double thirdVar;
double modVar = 2;
double sumVar;
double count;
for(count = 0; count < MAX; count++){
thirdVar = firstVar + secondVar;
secondVar = firstVar;
firstVar = thirdVar;
if(fmod(firstVar, modVar) == 0){
evenCount(&firstVar);
}
printf("Currently: %.2f\n", firstVar);
}
sumVar = &evenCount();
printf("Final even sum is: %f\n", sumVar);
return 0;
}
void evenCount (double* evenPoint){
double tempOne, tempTwo, tempThree;
tempOne = *evenPoint;
tempThree = tempOne + tempTwo;
tempTwo = tempOne;
tempOne = tempThree;
evenPoint = &tempOne;
}
I can't tell if the data from main() is being properly passed to the evenCount function for them to be summed and have it's value updated to be printed at the end of main().
My questions are:
Do I need a second double pointer in evenCount to pass the final value or can I just reference one value updating it as it loops through?
Does main() need a pointer so that pointer can reference evenCount pointer?
I would really appreciate any help because I have bought a Safari online subscription, have the "C A Reference Manual" sitting next to me but I just can't figure this out. Plus i read over this question and it kind of answered my question, but the person is using multiple function prototypes.
too few arguments to function and can't be used as a function---- beginning C
Thanks to anybody that looks
I am not completely clear about what the evenCount() function is supposed to do.
Fact is that you are calling it the wrong way - sumVar = &evenCount(); is even twice wrong, as it is missing an argument and the & doesn't make sense - and that it doesn't do what you probably want.
Let's have a look:
void evenCount (double* evenPoint){
double tempOne, tempTwo, tempThree;
Here you define three auto variables, but they haven't got a value yet.
tempOne = *evenPoint;
tempThree = tempOne + tempTwo;
What do you expect to be tempTwo here?
tempTwo = tempOne;
tempOne = tempThree;
evenPoint = &tempOne;
You might mean *evenPoint = tempOne here, but I am not sure.
}
I suppose you want a way to make a "step" in terms of Fibonacci numbers. So let's look:
In order to create the "next" Fib number, you need the two previous ones and add them together. So a "step" could be done in a function like
void fibStep(double * curr, double *prev) {
double new = *curr + *prev;
*prev = *curr;
*curr = new;
}
and then
int main(void){
double firstVar = 0;
double secondVar = 1;
double sumVar = 0;
int count; // no need to have this as a double...
for(count = 0; count < MAX; count++){
fibStep(&secondVar, &firstVar);
if(fmod(secondVar, 2) == 0){
sumVar += secondVar);
}
printf("Currently: %.2f\n", secondVar);
}
printf("Final even sum is: %f\n", sumVar);
return 0;
}
I'm not quite sure what evenCount is meant to do as it is. Edit: see below.
From your description of the problem, it seems like you could just do:
int isEven(unsigned int number)
{
return !(number%2);
}
int main()
{
unsigned int first = 1, second = 1, next, sum = 0;
//we already have the first two numbers so start at 2
for(count = 2; count < MAX; count++)
{
next = first+second;
first = second;
second = next;
//we know the starting values are odd (1 & 1) and won't need to be summed so we can test the new value -
if (isEven(second)) //if even (no remainder when dividing by 2)
{ sum+=first;}
}
printf("Final even sum is: %f\n", sum);
}
Note, there is no need for double here (yet). The sum (at n=20) is still far too low to exceed what int can store. (although at this point it is growing quickly)
As for your actual questions:
note: when you don't need a pointer, it is recommended that you don't use one, as all you are going to do is make the code more complex than needed
Do I need a second double pointer in evenCount to pass the final value?
If the function is meant to keep track of the sum, then I'd do it like this:
unsigned int evenSum(unsigned int num = 0)
{
static unsigned int sum = 0; //initialised on first use of function. Value is retained between function calls.
//we test for even here - no longer need to test in calling code
// - making the algorithm simpler
if (isEven(num))
sum += num;
return sum;
}
which can then be called like this:
//adding values:
evenSum( new_value );
//retrieving sum
sum = evenSum();
//or do both:
sum = evenSum( new_value );
If you wanted to store the sum 'locally' though (i.e. as a variable in main, but modify it in the evenSum() function), then yes, you would then need to pass it into the funtion too as a pointer:
void evenSum(unsigned int num, unsigned int * sum)
{
if (isEven(num))
*sum += num;
}
It would be called like this:
sum = 0;
num = 56;
evenSum(num, &sum); //sum is now sum+num
As you pass the address of sum in, when the function de-references it, it modifies the value and not a copy. The number passed in does not need to be passed in as a pointer as it is a (forgetting correct word here, but it means 'basic') type, and passing it by value is actually slightly more efficient as at runtime it can just be loaded into a register, and doesn't rely on memory lookup. Plus, it is easier to read.
Does main() need a pointer so that pointer can reference evenCount pointer?
To be honest, I'm not 100% sure what you are asking here.
If you are asking:
Do I need to store a pointer to the sum in main() to pass into the evenSum() function?
then no.
You can pass a pointer to a 'thing' using the "address of" operator &. I've used it above in the second calling example in the above answer:
unsigned int * sum_pointer = ∑// <--- not needed
evenSum(num, &sum); //sum is now sum+num
^
This passes a pointer to sum
Edit: looking at your code again, is evenCount meant to find the next fibonachi number?
If so, you could do:
void next_fib(unsigned int *previous, unsigned int *current)
{
unsigned int next = *previous+*current;
*previous = *current;
*current = next;
}
And you would call this like so:
unsigned int val1 = 1, val2 = 1;
next_fib(&val1, &val2); //val2 is now the 3rd fib. #
next_fib(&val1, &val2); //val2 is now the 4th fib. #
To add this to my code from above, the program becomes:
int isEven(double number)
{
return !(number%2);
}
unsigned int evenSum(double num = 0)
{
static double sum = 0;
//we test for even here - no longer need to test in calling code
// - making the algorithm simpler
if (isEven(num))
sum += num;
return sum;
}
void next_fib(unsigned int *previous, unsigned int *current)
{
unsigned int next = *previous+*current;
*previous = *current;
*current = next;
}
int main()
{
unsigned int first = 1, second = 1;
//we already have the first two numbers so start at 2
for(count = 2; count < MAX; count++)
{
next_fib(&first, &second);
evenSum(second);
}
printf("Final even sum is: %f\n", evenSum());
}
Edit 2:
After reading your edit and some of your comments, and then taking a look at the actual task, you have interpreted the question incorrectly.
The question asks for the sum of all even numbers in the fibbonachi sequence, where the number is less than 4x106. This is thankfully easier and quicker to do than the sum of all the even Fibonacci numbers up to the 4x106th.
Obviously, we need to change the algorithm. Luckily, we split the main bits into functions already, so it's pretty simple, mainly just a change in the loops, though I made a couple more changes too:
bool isEven(unsigned long number)
{
return !(number%2);
}
void next_even_fib(unsigned long *previous, unsigned long *current)
{
do
{
unsigned int next = *previous+*current;
*previous = *current;
*current = next;
} while (!isEven( *current));
//we could just do 3 passes here without needing the isEven() function
//as the Fibonacci sequence is always O,O,E,O,O,E...
//but this is a more general form
}
int main()
{
//as there is less constraint on knowing which term we are on, we can skip straight to the first even number.
unsigned long first = 1, second = 2;
unsigned long sum = 0;
do
{
//with the sum calculation first, we can break out of the loop before the sum
//we've changed the algorithm so when we get here, second is always even
sum += second;
next_even_fib(&first, &second);
} while (second < 4000000);
printf("Final even sum is: %d\n", sum);
}
Note that I changed the types to unsigned long. This is still an integer value, but one that is guaranteed to be long ( :-P ) enough to store the numbers we need.
Passing of the value is correct but you can't do evenPoint = &tempOne; to return a value from the function. There are two problems in doing that: first is that C supports only pass by value, so when you pass a pointer you are in fact creating a copy of the pointer for the callee. Any modification of the data pointed will be visible to the caller but not modifications to the pointer argument itself. When you modify the pointer argument you are in fact modifying a stack variable that the caller has no access to.
What's the difference between passing by reference vs. passing by value?
You could change your code in the following way:
void evenCount (double** evenPoint){
double tempOne, tempTwo, tempThree;
tempOne = **evenPoint;
tempThree = tempOne + tempTwo;
tempTwo = tempOne;
tempOne = tempThree;
*evenPoint = &tempOne;
}
But that would mean that *evenPoint points to a variable allocated on the stack, precisely on the frame of evenCount. When evenCount returns the frame get popped out of the stack. Accessing that variable after it is outside the stack will cause undefined behavior.
Consider the following example where you call another function A() after evenCount before using evenPoint. A() function frame would be placed in memory at the same location of where evenCount frame was and its local variables might overwrite the value of evenPoint. When you subsequently read evenPoint you will find its value changed.
C++ Returning reference to local variable
Finally, you read the variable tempTwo which is an uninitialized automatic variable so you'll end up reading garbage.

understanding how to dynamically create an array of structure and access its elements

I need to pass the address of a pointer to a structure to a function, which inturn will dynamically allocate the memory for an array of structures and fill in the values.
Now from my calling method, once i return from the func1, i should be able to iterate through the array of structure and display the value of the structure variables.
Can someone explain how to pass the address of the pointer to the structure, also iterating through the array of structures created dynamically ?
my sample code looks like this:
struct test {
int a;
int b;
};
void func1(int *n,struct test **testobj)
{
n=5;
*testobj = (struct test*) malloc(n*sizeof(struct test));
for(i=0;i<n;i++)
{
(*testobj)[i].a=1;
(*testobj)[i].b=2;
}
}
int main()
{
struct test testobj;int n;
func1(&n,&testobj);
for(i=0;i<n;i++)
{
printf("%d %d",(*testobj)[i].a,*testobj)[i].b);
}
free(testobj);
}
In main() define a pointer to a test structure:
struct test *testPtr;
To take the address of that pointer use the & address-of operator:
&testPtr;
This returns the address of the pointer and has type struct test **
You can then pass this into your function func1, which does the correct allocation (although casting malloc() is generally considered bad practice - Do I cast the result of malloc?). Other than that func1() looks good... the line...
*testobj = malloc(n*sizeof(struct test));
... is correct. *testobj dereferences your double pointer that you got by doing &testPtr, and stores the address of the new memory in your pointer. You are also correct when you dereference your double-pointer using (*testobj)[i] because [] has higher precedence than * you needed to (as you've correctly done) surround the dereference with brackets to make sure that happens before you take the index.
Thus, when func1() returns the pointer testPtr should now point to the array of n test structures you allocated and can be accessed using testPtr[i].a etc.
EDIT: Your for loop should become
for(i=0;i<n;i++)
printf("%d %d", testobj[i].a, testobj[i].b);
Your original for loop should have given you compilation errors? In the original code testobj is not a pointer, therefore dereferencing it should not be possible.
So the summary answer is in main() declare testobj as a pointer and then access the array elements as testobj[n] :)
EDIT: As eric has pointed out, remove n=5; from func1(). I think you meant *n=5 perhaps as some kind of debugging step... You probably mean to use n as the input to the function to say how many objects you want in your structure array. Either initialise n or perhaps re-define func1() to be
void func1(int n,struct test **testobj) // n is no longer a poitner, just a number
create your array of pointers to structures in declaration step itself and simply pass it to the function
struct test *testobj[10];
func1(&n,testobj);
This passes the whole array of pointers to the function
It isn't entirely clear which version you're asking for, but one of these should cover it:
/* allocate some number of tests.
*
* out_n: out parameter with array count
* returns: an array of tests
*/
struct test* allocate_some_tests(int *out_n) {
int n = 5; /* hardcoded, random or otherwise unknown to caller */
*out_n = n
struct test *t = malloc(n * sizeof(*t));
while (n--) {
t[n].a = 1;
t[n].b = 2;
}
return t;
}
/* allocate a specific number of tests.
*
* n: in parameter with desired array count
* returns: an array of tests
*/
struct test* allocate_n_tests(int n) {
struct test *t = malloc(n * sizeof(*t));
while (n--) {
t[n].a = 1;
t[n].b = 2;
}
return t;
}
Note that you can just return the allocated array, you don't need a pointer-to-pointer here.
As for calling them, and iterating over the result:
void print_tests(struct test *t, int n) {
for (; n--; t++)
printf("{%d, %d}\n", t->a, t->b);
}
int main()
{
int count1; /* I don't know how many yet */
struct test *array1 = allocate_some_tests(&count1);
print_tests(array1, count1);
int count2 = 3; /* I choose the number */
struct test *array2 = allocate_n_tests(count2);
print_tests(array2, count2);
}
Your code appears pretty much ok to me.
only edit that should make it fine is--
in place of
struct test testobj;
put the following code
struct test *testobj;
and keep the remaining as it is..!
here's the working version of what's required, here the memory is allocated in the called function just as required
#include <stdlib.h>
#include <stdio.h>
struct tests {
int a;
int b;
};
void func1(int *n,struct tests **testobj)
{
int i;
*n=5;
*testobj = (struct tests*) malloc((*n)*sizeof(struct tests));
for(i=0;i<(*n);i++)
{
(*testobj)[i].a=1;
(*testobj)[i].b=2;
}
}
int main()
{
int i;
struct tests *testobj;int n;
func1(&n,&testobj);
for(i=0;i<(n);i++)
{
printf("%d %d",(testobj)[i].a,testobj[i].b);
}
free(testobj);
}

Resources