Im a little bit confused about passing structs into functions. I understand pointers and everything.
But for instance:
struct stuff
{
int one
int two
};
int main{
stuff fnc;
fnc.two = 2;
fnc.one = 1;
multiply(&fnc);
}
void multiply(const stuff * pm){
cout << pm->one * pm->two;
}
First of all....am i even doing this right.
And second of all, why do we use the address operator when we pass the function, but use the * pointer operator in the actual function call?
Im confused?
Yes, your code is compilable other than the missing semicolons in the defintion of struct stuff. I'm not quite sure exactly what you're asking about passing the function and the actual function call, but I think you're wondering why the function call uses &fnc, but the parameter is stuff *pm? In that case, the fnc variable declared is a plain stuff. It is not a pointer, it refers to the actual instance of that struct.
Now the multiply function is declared as taking a stuff* -- a pointer to a stuff. This means that you can't pass fnc directly -- it's a stuff and multiply expects a *stuff. However, you can pass fnc as a stuff* by using the & operator to take the address, and &fnc is a valid stuff* that can be passed to multiply.
Once you're in the multiply function, you now have a stuff* called pm. To get the one and two variables from this stuff*, you use the pointer to member operator (->) since they are pointers to a stuff and not a plain stuff. After obtaining those values (pm->one and pm->two), the code then multiples them together before printing them out (pm->one * pm->two).
The * and & operands mean different things depending on whether they describe the type or describe the variable:
int x; // x is an integer
int* y = &x; // y is a pointer that stores the address of x
int& z = x; // z is a reference to x
int a = *y; // a in an integer whose value is the deference of y
Your pm variable is declared as a pointer, so the stuff type is modified with *. Your fnc variable is being used (namely for its address), and thus the variable itself is marked with &.
You can imagine the above examples as the following (C++ doesn't actually have these, so don't go looking for them):
int x;
pointer<int> y = addressof(x);
reference<int> z = x;
int a = dereference(y);
It the difference between describing a type and performing an operation.
In
void multiply(const stuff * pm){
cout << pm->one * pm->two;
}
The stuff * pm says that pm is an address of a stuff struct.
The
&fnc
says "the address of fnc".
When a variable is declared like:
stuff *pm;
it tells us that pm should be treated like an address whose underlying type is stuff.
And if we want to get the address of a variable stuff fnc, we must use
&fnc
You need the address of operator so you can get the address of the object, creating a pointer, which the function expects. The '*' in the parameter list is not a pointer operator, it simply says that the variable is a pointer.
Your code is correct. In the main, you successfully create a 'stuff' object and set its values. Then, you pass a constant address to the object into the function multiply. The multiply function then uses that address to access the two variables of the structure to output the multiplication of the variables.
The * in "const stuff * pm" means that it takes a constant pointer to a stuff object.
Here is a working example of what you would like to see.
#include <iostream>
using namespace std;
struct stuff
{
int one;
int two;
};
void multiply(stuff* pm)
{
cout << pm->one * pm->two;
}
int main()
{
stuff* fnc = new stuff;
fnc->two = 1;
fnc->one = 2;
multiply(fnc);
delete fnc;
cin.ignore(1000, 10);
return 0;
}
Sure, this would work, aside from your erroneous main function definition.
The reason why this works is because when you use the unary & operator, it essentially returns a pointer to the operand, so in your case, fnc, which is of type stuff, if you did &fnc, that would return a stuff *. This is why the multiply function must take in a stuff *.
struct stuff
{
int one, two;
};
int main(int argc, const char* argv[]) {
stuff fnc;
fnc.two = 2;
fnc.one = 1;
multiply(&fnc); //passes a pointer to fnc
}
void multiply(const stuff * pm){
//the "*" operator is the multiplication operator, not a pointer dereference
cout << pm->one * pm->two; //->one is equivalent to (*pm).one
}
You have a couple of syntactic errors in your program, but other than that, the basic idea is fine. Here are the syntax problems I had to fix before your program would compile:
#include <iostream>
using namespace std;
struct stuff
{
int one;
int two;
};
void multiply(const stuff * pm) {
cout << pm->one * pm->two;
}
int main() {
stuff fnc;
fnc.two = 2;
fnc.one = 1;
multiply(&fnc);
}
To answer your questions about difference between the '&' (address of) operator and the '*' (pointer dereference) operator though, we just need to think about the types you're passing in to the function.
Take the function multiply:
void multiply(stuff *fnc) {
...
}
In the definition of this function, you are describing something that takes a pointer to a stuff struct. In that first line, you aren't saying you are dereferencing that object, just that you are expecting a pointer to a stuff object.
Now when you call multiply:
stuff fnc;
multiply(&fnc);
You are using the '&' (address of) operator to get a pointer to the object. Since the multiply function expects a pointer, and you have the plain old object, you need to use the & operator to get a pointer to give to the multiply function.
Perhaps it is clearer to think call it like this:
stuff fnc; //The actual object
stuff* fnc_ptr = &fnc; //A pointer to a stuff object, initialized to point at fnc created above
multiply(fnc_ptr); //Call the function with the pointer directly
Following code will tell you about the pointer illustration
A struct address is passed into the function named multiply and this
function perform some operations with the element of the passed
structure and store the result in the result variable.
you can see here clearly that the result variable is previously zero then after passing the address of the structure to the function multiply the result variable value gets updated to value 6. this is how pointer works.
#include <iostream.h>
struct stuff
{
int one;
int two ;
int result;
};
void multiply(stuff *pm);
int main(){
stuff fnc;
fnc.two = 2;
fnc.one = 3;
fnc.result = 0;
multiply(&fnc);
cout<<fnc.result;
return 0;
}
void multiply(stuff *pm)
{
pm->result = pm->one * pm->two;
}
Related
I got this declaration from https://en.cppreference.com/w/cpp/language/scope, but don't know how to parse this declaration even there is a comment below.
my questions is
how to parse the declaration statement (I see it as a function pointer to a function protocol like "int[3] foo(int n)" or "int foo(int n)[3] --- they are illegal in C++ )? Then, how can I construct a concrete function which can be assigned to this function pointer? Thanks.
const int n = 3;
int (*(*f2)(int n))[n]; // OK: the scope of the function parameter 'n'
// ends at the end of its function declarator
// in the array declarator, global n is in scope
// (this declares a pointer to function returning a pointer to an array of 3 int
It's a pointer to a function taking an int and returning a pointer to an int array of size three.
All the comment is saying is that there are two n identifiers in play here. The [n] (in array declarator) is using the const int 3, not the parameter to the function (which is in the function declarator).
Starting in the middle, with each segment being included in the subsequent bullet point as ...:
f2 is a pointer, (*f2).
It's a pointer to a function taking an integer, ...(int).
It returns a pointer to an int array of size three, int (*...)[3].
You can form a concrete function for it as per the following complete program, which output the first element, 42:
#include <iostream>
const int n = 3;
int (*(*f2)(int n))[n];
int (*g2(int))[n] {
static int x[::n] = { 42 }; // Use outer n, not the parameter.
return &x; // since C++ has no VLAs. This
// means parameter is not actually
// needed in this test case, though
// it may be in more complicated
// tests.
}
int main() {
f2 = &g2; // Assign concrete function to pointer.
auto y = f2(3); // Call via pointer, get array.
std::cout << *(y[0]) << '\n'; // Deref first element to get 42.
}
Having said that, I would be rather curious if one of my colleagues submitting something like that for a code review, at least without a large comment explaining it. Although seasoned developers may be able to work it out, those less experienced may have trouble.
And, in fact, even seasoned developers shouldn't have to work it out, especially given it took me a few minutes.
C++ has a very expressive type system which can easily build something like this up in parts, so you don't have to experience migraines trying to work it out. For something like this, I'd be using std::vector (or std::array) unless there was a compelling case for the added complexity caused by more basic types.
You can create a type for pointer to an array of 3 int
typedef int (*array_with_size_n)[n];
and then use it as return type
const int n = 3;
int (*(*f2)(int n))[n];
int arr[n];
array_with_size_n func(int n)
{
return &arr;
}
int main()
{
f2 = &func;
return 0;
}
I am getting 3 errors:
line 12:-invalid conversion from int* to int
line 17:-x was not declared in this scope
line 16:- expected primary expression before',' token
Please help me to fix this. Here is the code:
#include<iostream>
int power(int x[5])
{
x[0]=12;
x[1]=23;
x[2]=234;
x[3]=344;
x[4]=232;
return x;
}
int main()
{
int action[5]={1,2,3,,4,5};
std::cout<<x[0]<<std::endl;
x();
std::cout<<x[0]<<std::endl;
return 0;
}
your help would be appreciated!
First of all, the errors are pretty self explanatory.
invalid conversion from int* to int
Your function is declared in such a way it is expected to return an int. Not an array of ints, just an int. Furthermore, you cannot return an array from a function. You can, however, return a pointer to the first element, which in your case is unnecessary.
Guessing that you want your function to simply set values in an array, you can achieve that by declaring the function as void returning:
void power(int x[5])
{
x[0]=12;
x[1]=23;
x[2]=234;
x[3]=344;
x[4]=232;
}
x was not declared in this scope
Well, given your main:
int main()
{
int action[5]={1,2,3,,4,5};
std::cout<<x[0]<<std::endl;
// ^
...
}
Here you attempt to use a variable x, which was never declared inside main or as global variable, thus the compiler has no idea what you are referring to. Simply aliasing an argument as x in some unrelated function won't make it visible to all the code. Your can't use it like this.
expected primary expression before',' token
Take a close look at your main function and at action declaration. The part:
int action[5]={1,2,3,,4,5};
// ^^
is illegal. Notice the ,,. You either should put an integer inbetween them, or delete one of them.
What you probably wanted to achieve, was to first declare the array, print out the first element, apply the power() function and print the first element again, hoping it to change. Given the declaration of power() that I have written, you could achieve it by doing it like so:
#include <iostream>
void power(int x[5])
{
x[0]=12;
x[1]=23;
x[2]=234;
x[3]=344;
x[4]=232;
}
int main()
{
int x[5] = {1,2,3,4,5};
std::cout << x[0] << ' ';
power(x);
std::cout << x[0] << std::endl;
}
That outputs: 1 12.
The first error is a simple mis-declaration: The function receives a pointer and returns a pointer, so the return type is int *, not simply int. By the way, I like it that the function returns the pointer because it allows for function nesting like in the code below (the result of a function call can be the direct argument for another).
Note that the parameter x you declare is a pointer, despite appearances. One can declare a pointer parameter in two ways:
f ( int *p );
or
f2( int p[] );
The two are completely identical; it is impossible to pass arrays to functions. They always are "adjusted" to pointers to the first element.
In fact, one could even write
f2( int p[100] );
which I demonstrate in the code below. The number is irrelevant and ignored. In particular, the compiler does not think there is an array, and it does no type or index checking of the actual arguments.
Now the original function you present is unsafe; it's entirely up to the caller to provide an array with 5 elements.
C++ has the possibility to pass references, and even true references to arrays. Arrays of different sizes have different types, even if the elements are of the same type. This makes normal functions taking references to arrays pretty useless (unless you have an application like a screen buffer where all arrays are of the same size, known at coding time).
But C++ has also templates, which are a facility to construct functions at compile time from a provided pattern, depending on type and int parameters provided by the caller at compile time (but not necessarily at template coding time!). For functions these template parameters can be inferred by the compiler from the function arguments which makes template functions handy to use: The compiler creates the proper one almost magically.
A function iterating over all elements of a fixed-size array is a prime candidate for a template. Check out the last function in the code below.
#include<iostream>
using namespace std; // for brevity in the example
/** An unsafe function based on passing pointers
without element counts.
*/
int *power_5_elems(int x[100]) {
// This is somewhat scary.
// There is no way to check whether the array
// starting at x has indeed 5 elements. It's
// like writing assembler: All is up to the caller.
// Another thing: It would be nice to use a loop.
// We know there are 5 elements, right?
x[0] = x[0] * x[0];
x[1] = x[1] * x[1];
x[2] = x[2] * x[2];
x[3] = x[3] * x[3];
x[4] = x[4] * x[4];
return x;
}
// A reference to an int array with 5 elements.
// Remember, a typedef is written like a variable declaration; the
// type name takes the syntactic place of the variable.
// To decipher it, solve the expression in the parentheses first:
// "I must first de-reference the variable".
// The next operator is the square brackets index operator:
// "I must index the result of the dereferencing" (i.e. it is an array).
// There are 5 indices (0..4).
// The last information is: "The resulting type is int."
// Summed up: This is a reference to an array with 5 elements of type int.
typedef int(&intArr5)[5];
/** This is a nicer way to declare the function below. */
intArr5 power_ref5Arr(intArr5 arrRef);
/** A safe function with very limited usability.
It works only for int arrays with 5 elements.
This is the raw declaration of the same function.
*/
int (&power_ref5Arr( int (&x)[5] ))[5] {
// This is not scary at all.
// Only arrays with 5 ints can be supplied.
for (int i = 0; i < 5; i++)
{
x[i] = x[i] * x[i];
}
return x;
}
/** A versatile function which squares arrays
of arbitrary length of any type that isn't on
a tree on the count of three. It's very similar to the
function above with 5 int elements.
*/
template<int N, typename T>
T(&refPower( T (&arr)[N] ))[N]
{
// Note the use of the template parameter N
// in place of the "5" above.
for (int i = 0; i < N; i++)
{
arr[i] = arr[i] * arr[i];
}
return arr;
}
int main() {
int x[5] = { 2,3,4,5,6 };
int *p = &x[0]; // make clear: this is a pointer
power_5_elems(power_5_elems(power_5_elems(x)));
cout << x[0] << endl;
// The function actually expects a pointer!
// The pointer points to x.
power_5_elems(p);
cout << x[0] << endl;
int y[2] = { 2,3 };
refPower(refPower(refPower(y)));
cout << y[0] << endl;
double z[2] = { 0.2 , 0.3 };
refPower(refPower(refPower(z)));
cout << z[0] << endl;
return 0;
}
I am reading a book called "Teach Yourself C in 21 Days" (I have already learned Java and C# so I am moving at a much faster pace). I was reading the chapter on pointers and the -> (arrow) operator came up without explanation. I think that it is used to call members and functions (like the equivalent of the . (dot) operator, but for pointers instead of members). But I am not entirely sure.
Could I please get an explanation and a code sample?
foo->bar is equivalent to (*foo).bar, i.e. it gets the member called bar from the struct that foo points to.
Yes, that's it.
It's just the dot version when you want to access elements of a struct/class that is a pointer instead of a reference.
struct foo
{
int x;
float y;
};
struct foo var;
struct foo* pvar;
pvar = malloc(sizeof(struct foo));
var.x = 5;
(&var)->y = 14.3;
pvar->y = 22.4;
(*pvar).x = 6;
That's it!
I'd just add to the answers the "why?".
. is standard member access operator that has a higher precedence than * pointer operator.
When you are trying to access a struct's internals and you wrote it as *foo.bar then the compiler would think to want a 'bar' element of 'foo' (which is an address in memory) and obviously that mere address does not have any members.
Thus you need to ask the compiler to first dereference whith (*foo) and then access the member element: (*foo).bar, which is a bit clumsy to write so the good folks have come up with a shorthand version: foo->bar which is sort of member access by pointer operator.
a->b is just short for (*a).b in every way (same for functions: a->b() is short for (*a).b()).
foo->bar is only shorthand for (*foo).bar. That's all there is to it.
Well I have to add something as well. Structure is a bit different than array because array is a pointer and structure is not. So be careful!
Lets say I write this useless piece of code:
#include <stdio.h>
typedef struct{
int km;
int kph;
int kg;
} car;
int main(void){
car audi = {12000, 230, 760};
car *ptr = &audi;
}
Here pointer ptr points to the address (!) of the structure variable audi but beside address structure also has a chunk of data (!)! The first member of the chunk of data has the same address than structure itself and you can get it's data by only dereferencing a pointer like this *ptr (no braces).
But If you want to acess any other member than the first one, you have to add a designator like .km, .kph, .kg which are nothing more than offsets to the base address of the chunk of data...
But because of the preceedence you can't write *ptr.kg as access operator . is evaluated before dereference operator * and you would get *(ptr.kg) which is not possible as pointer has no members! And compiler knows this and will therefore issue an error e.g.:
error: ‘ptr’ is a pointer; did you mean to use ‘->’?
printf("%d\n", *ptr.km);
Instead you use this (*ptr).kg and you force compiler to 1st dereference the pointer and enable acess to the chunk of data and 2nd you add an offset (designator) to choose the member.
Check this image I made:
But if you would have nested members this syntax would become unreadable and therefore -> was introduced. I think readability is the only justifiable reason for using it as this ptr->kg is much easier to write than (*ptr).kg.
Now let us write this differently so that you see the connection more clearly. (*ptr).kg ⟹ (*&audi).kg ⟹ audi.kg. Here I first used the fact that ptr is an "address of audi" i.e. &audi and fact that "reference" & and "dereference" * operators cancel eachother out.
struct Node {
int i;
int j;
};
struct Node a, *p = &a;
Here the to access the values of i and j we can use the variable a and the pointer p as follows: a.i, (*p).i and p->i are all the same.
Here . is a "Direct Selector" and -> is an "Indirect Selector".
I had to make a small change to Jack's program to get it to run. After declaring the struct pointer pvar, point it to the address of var. I found this solution on page 242 of Stephen Kochan's Programming in C.
#include <stdio.h>
int main()
{
struct foo
{
int x;
float y;
};
struct foo var;
struct foo* pvar;
pvar = &var;
var.x = 5;
(&var)->y = 14.3;
printf("%i - %.02f\n", var.x, (&var)->y);
pvar->x = 6;
pvar->y = 22.4;
printf("%i - %.02f\n", pvar->x, pvar->y);
return 0;
}
Run this in vim with the following command:
:!gcc -o var var.c && ./var
Will output:
5 - 14.30
6 - 22.40
#include<stdio.h>
int main()
{
struct foo
{
int x;
float y;
} var1;
struct foo var;
struct foo* pvar;
pvar = &var1;
/* if pvar = &var; it directly
takes values stored in var, and if give
new > values like pvar->x = 6; pvar->y = 22.4;
it modifies the values of var
object..so better to give new reference. */
var.x = 5;
(&var)->y = 14.3;
printf("%i - %.02f\n", var.x, (&var)->y);
pvar->x = 6;
pvar->y = 22.4;
printf("%i - %.02f\n", pvar->x, pvar->y);
return 0;
}
The -> operator makes the code more readable than the * operator in some situations.
Such as: (quoted from the EDK II project)
typedef
EFI_STATUS
(EFIAPI *EFI_BLOCK_READ)(
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
OUT VOID *Buffer
);
struct _EFI_BLOCK_IO_PROTOCOL {
///
/// The revision to which the block IO interface adheres. All future
/// revisions must be backwards compatible. If a future version is not
/// back wards compatible, it is not the same GUID.
///
UINT64 Revision;
///
/// Pointer to the EFI_BLOCK_IO_MEDIA data for this device.
///
EFI_BLOCK_IO_MEDIA *Media;
EFI_BLOCK_RESET Reset;
EFI_BLOCK_READ ReadBlocks;
EFI_BLOCK_WRITE WriteBlocks;
EFI_BLOCK_FLUSH FlushBlocks;
};
The _EFI_BLOCK_IO_PROTOCOL struct contains 4 function pointer members.
Suppose you have a variable struct _EFI_BLOCK_IO_PROTOCOL * pStruct, and you want to use the good old * operator to call it's member function pointer. You will end up with code like this:
(*pStruct).ReadBlocks(...arguments...)
But with the -> operator, you can write like this:
pStruct->ReadBlocks(...arguments...).
Which looks better?
#include<stdio.h>
struct examp{
int number;
};
struct examp a,*b=&a;`enter code here`
main()
{
a.number=5;
/* a.number,b->number,(*b).number produces same output. b->number is mostly used in linked list*/
printf("%d \n %d \n %d",a.number,b->number,(*b).number);
}
output is 5
5 5
Dot is a dereference operator and used to connect the structure variable for a particular record of structure.
Eg :
struct student
{
int s.no;
Char name [];
int age;
} s1,s2;
main()
{
s1.name;
s2.name;
}
In such way we can use a dot operator to access the structure variable
If I have a function that takes int *&, what does it means? How can I pass just an int or a pointer int to that function?
function(int *& mynumber);
Whenever I try to pass a pointer to that function it says:
error: no matching function for call to 'function(int *)'
note: candidate is 'function(int *&)'
It's a reference to a pointer to an int. This means the function in question can modify the pointer as well as the int itself.
You can just pass a pointer in, the one complication being that the pointer needs to be an l-value, not just an r-value, so for example
int myint;
function(&myint);
alone isn't sufficient and neither would 0/NULL be allowable, Where as:
int myint;
int *myintptr = &myint;
function(myintptr);
would be acceptable. When the function returns it's quite possible that myintptr would no longer point to what it was initially pointing to.
int *myintptr = NULL;
function(myintptr);
might also make sense if the function was expecting to allocate the memory when given a NULL pointer. Check the documentation provided with the function (or read the source!) to see how the pointer is expected to be used.
Simply: a reference to a pointer.
In C, without references, the traditional way to "relocate" a pointer, is to pass a pointer to a pointer:
void c_find(int** p, int val); /* *p will point to the node with value 'val' */
In C++, this can be expressed by the reference syntax, to avoid the awkward double dereference.
void cpp_find(int*& p, int val); // p will point to the node with value 'val'
It means a reference to a pointer to an int. In other words, the function can change the parameter to point to something else.
To pass a variable in, just pass an int*. As awoodland points out, what's passed in must be an l-value.
Edit:
To build on awoodland's example:
#include <iostream>
void foo(int*& var)
{
delete var;
var = new int;
}
int main(int argc, char* argv[])
{
int* var = NULL;
std::cout << var << std::endl;
foo(var); // this function can/will change the value of the pointer
std::cout << var << std::endl;
delete var;
return 0;
}
function takes a single parameter, mynumber which is a reference to a pointer to an int.
This is useful when you need to pass a pointer to a function, and that function might change the pointer. For example, if you function is implemented like this:
function(int*& mynumber)
{
if( !mynumber )
mynumber = new int;
*mynumber = 42;
}
...Then something like this might happen in the calling code:
int main()
{
int* mynumber = 0;
function(mynumber); // function will change what "mynumber" points to
cout << *mynumber;
return 0;
}
This is a reference to a pointer to int - you would have to pass in the address of an int to this function, and be aware that the function could change the pointer through the reference.
Dumb example:
void func(int*& iref)
{
iref = new int;
}
int main()
{
int i(0);
int* pi(&i);
func(pi);
// pi no longer equal to &i
return 0;
}
How can we access variables of a structure? I have a struct:
typedef struct {
unsigned short a;
unsigned shout b;
} Display;
and in my other class I have a method:
int NewMethod(Display **display)
{
Display *disp=new Display();
*display = disp;
disp->a=11;
}
What does **display mean? To access variables of struct I have used ->, are there other methods too?
As Taylor said, the double asterisk is "pointer to pointer", you can have as many levels of pointers as you need.
As I'm sure you know, the arrow operator (a->b) is a shortcut for the asterisk that dereferences a pointer, and the dot that accesses a field, i.e.
a->b = (*a).b;
The parentheses are necessary since the dot binds tighter. There is no such operator for double asterisks, you have to first de-reference to get to the required level, before accessing the fields:
Display **dpl = ...;
(*dpl)->a = 42;
or
(**dpl).a = 42;
Think of it as *(*display). When you want to pass the address of an integer to a function so that you can set the integer, you use:
void setTo7 (int *x) {
*x = 7;
}
: : :
int a = 4;
setTo7 (&a);
// a is now 7.
It's no different from what you have except that you want to set the value of a pointer so you need to pass the pointer to that pointer. Simple, no?
Try this out:
#include <stdio.h>
#include <string.h>
static void setTo7 (int *x) { *x = 7; }
void appendToStr (char **str, char *app) {
// Allocate enough space for bigger string and NUL.
char *newstr = malloc (strlen(*str) + strlen (app) + 1);
// Only copy/append if malloc worked.
if (newstr != 0) {
strcpy (newstr, *str);
strcat (newstr, app);
}
// Free old string.
free (*str);
// Set string to new string with the magic of double pointers.
*str = newstr;
}
int main (void) {
int i = 2;
char *s = malloc(6); strcpy (s, "Hello");
setTo7 (&i); appendToStr (&s, ", world");
printf ("%d [%s]\n",i,s);
return 0;
}
The output is:
7 [Hello, world]
This will safely append one string value to another, allocating enough space. Double pointers are often used in intelligent memory allocation functions, less so in C++ since you have a native string type, but it's still useful for other pointers.
**display is just a double pointer (a pointer to a pointer of type Display).
The ** means that its a pointer-to-a-pointer. Basically it points to another pointer that then points to something else, in your case a Display structure.
If you called the function with only the object you can access the members with the . operator.
int NewMethod(Display display)
{
Display disp = display;
disp.a=11;
}
But this way you are not modifying directly the Display display object but a local copy. Your code suggests that the changes to the object are needed outside of the function so your only option is the one you described (well, maybe passing the argument by refference but the syntax then would more or less the same (->)).
Since disp is a Pointer you have to use ->
If you just have a "normal" variable (i.e. on the stack)
Display d;
you can write d.a
A struct is the same as a class. The only difference (I am aware of) is that all members are public by default.
You can do (*disp).a=11;
it is called dereferencing