0

I have a program that has to use ShowMe (int *p) and from the main function when it is called it needs to pull the values out of typedef Pyramid A. this is the typedef struct declaration

typedef struct _Pyramid
{
double element [N][N];
} Pyramid;

I have gotten incompatible errors, I understand they're not the same type. I have tried casting and have been told I can't do that. I have tried every-way I'm currently aware of to get this to work. So how would I call the function ShowMe (int *p) in main and pass it the values of Pyramid A? I will post the code if asked. But I'm tired of being told what I'm doing wrong (which I mostly had already figured out from the errors) without any direction on what to do right. I will emphasize again. I'm new to C and I'm very tired and have worked on something for more than a couple of days before I post.

#include <stdio.h>
#include <stdlib.h>

#define N 8

typedef struct _Pyramid{
double stone [N][N];
} Pyramid;



int data[N*N];



Pyramid ShowMe(int *p)  // pass in data and return Pyramid
 {
      int i;
      int j; 
        for (i=0; i<N; i++)
        {
            for (j=0; j<N; j++)
            {
                printf("%g ", a.stone[i][j]);
            }//Inner for
            printf("\n");
        }//Outer For
 }//IZZ




int main(int argc, char **argv)
{
    // special case that allows us to initialize this way
    Pyramid A =    {10,  4, 2,  5, 1, 0, 0, 0,
                    3,  9, 1,  2, 1, 0, 0, 0,
                   -7, -5, 1, -2, -1, 0, 0, 0,
                   -3, -5, 0, -1, 0, 0, 0, 0,
                   -2,  1, 0,  0, 0, 0, 0, 0,
                    0,  0, 0,  0, 0, 0, 0, 0,
                    0,  0, 0,  0, 0, 0, 0, 0,
                    0,  0, 0,  0, 0, 0, 0, 0};





    ShowMe(int *A);


}//main
  • 2
    What is `ShowMe` supposed to do? Why does it have an `int*` parameter? – aschepler Sep 30 '18 at 01:03
  • For question such as this, you should provide a [Minimal Complete Verifiable Example](https://stackoverflow.com/help/mcve). Additionally, it appears your requirement to use `ShowMe` is a part of an exercise for some class. In that case, you should show the exercise statement, or at least enough of it to show the details of the requirements about `ShowMe`. Your statement that “I have tried casting and have been told I can’t do that” is puzzling. Were you told that by a compiler or by an instructor? It is unlikely an exercise would expect you to pass a `struct *` to a routine expecting `int *`. – Eric Postpischil Sep 30 '18 at 01:19
  • @EricPostpischil I provided the code if it helps. I was told by another person on StackOverflow I can't cast with pointers in C ... So I'm lost at this point – Tyreese Davis Sep 30 '18 at 02:04
  • @TyreeseDavis: It is false that you cannot cast pointers in C. You can, although certain rules must be followed. The person who said you cannot may have been referring to a specific situation. However, I doubt you need to cast pointers for this assignment. Unfortunately, you have not provided enough information about the assignment to know what is intended. If the assignment does not explicitly say that `ShowMe` must be declared with `ShowMe(int *)`, then you are probably allowed to declare it as `void ShowMe(Pyramid *)`. You should answer aschelper’s questions above. – Eric Postpischil Sep 30 '18 at 02:27

2 Answers2

0

Casting the type Pyramid* as an int* will violate the strict aliasing rule and could cause some undefined behaviors. Passing a char* instead of an int* for ShowMe() is a possible workaround, since char pointers are an exception to the strict aliasing rule. For more information and workarounds, check this post.

ttamiya
  • 101
  • 4
  • Merely casting a pointer to another pointer type does not violate the aliasing rule. Dereferencing the converted pointer may violate the aliasing rule. Presumably `ShowMe` would dereference the pointer, but we should be clear about what causes the actual violation when explaining to people. – Eric Postpischil Sep 30 '18 at 01:14
  • The statement “Passing a `char*` instead of an `int*` for ShowMe() is a possible workaround” seems incorrect. If `ShowMe` is changed to take a `char *`, it would violate the specification stated in the question. If `ShowMe` is not changed, this is suggesting one could workaround the problem by converting a `Pyramid *` to `char *` and then to an `int *` to be passed to `ShowMe`. Presumably `ShowMe` then dereferences it as an `int *`, which violates the aliasing rule. So this workaround does not work. – Eric Postpischil Sep 30 '18 at 01:22
  • I have added the code I have come up with so far. I had something like this in the previous assignment. However it was easier because everything was the same type. – Tyreese Davis Sep 30 '18 at 01:45
0

Your stumbling block is more about handling the struct as a parameter. A struct is simply a data type in C. It is passed as a parameter just as any other data type (int, long, char, etc...) and follows the same rules.

The convenience of a typedef allows you to specify the parameter as Pyramid var rather than having to use the full struct Pyramid var as you would without it. In fact, you don't even need the _Pyramid name for the struct when using a typedef, e.g.

typedef struct {    /* you can simply typedef a struct */
    double stone [N][N];
} pyramid_t;

Above, the typedef simply aliases an unnamed struct containing an array of doubles to the pyramid_t name, which you can use in declaring instances of the struct, e.g.

    /* explicit way to initilize 2D array as 1st member of struct */
    pyramid_t a = {{{10,  4, 2,  5,  1, 0, 0, 0},
                    { 3,  9, 1,  2,  1, 0, 0, 0},
                    {-7, -5, 1, -2, -1, 0, 0, 0},
                    {-3, -5, 0, -1,  0, 0, 0, 0},
                    {-2,  1, 0,  0,  0, 0, 0, 0},
                    { 0,  0, 0,  0,  0, 0, 0, 0},
                    { 0,  0, 0,  0,  0, 0, 0, 0},
                    { 0,  0, 0,  0,  0, 0, 0, 0}}};

Whether you include _Pyramid or not is up to you. (without it, you simply lose the ability to refer to struct _Pyramid as a declared type).

Your declaration of int data[N*N]; is a red-herring, a distraction of no consequence that isn't relevant to what you are attempting to do. You initialize an instance of your struct in main(). You simply need to pass the struct (or better, a pointer to your struct) to your showme[1] function in order to have the values available for printing there.

For example, including the typedef to specify you are passing the struct as a parameter (where the function receives a copy of the struct) you output the values using the dot '.' operator as you have in your function, e.g.

/* function type is void if it returns no value */
void showme (pyramid_t p)
{
    int i, j; 

    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++)
            printf("%3g ", p.stone[i][j]);
        putchar('\n');  /* use putchar() to output single char */
    }
}

You would then call your function in main() as:

    showme (a);     /* passing a copy of the struct to showme() */

(note: the function receives a copy of the struct -- so try changing some of the array values and then print the contents again back in main() ... any changes made are lost)

A more efficient way of passing the struct would be to pass a pointer to the struct, so that all that is being passed is the address of where the structure is stored in memory. Not only does that avoid making a copy of the struct, but by passing the address, any changes you make to the structure values are then preserved (because you are directly changing the values of the original struct in memory -- not simply making changes to a copy). When you pass a pointer to a struct (or anytime you are accessing values of a struct through a pointer), you use the arrow operator (->) to access the struct members. For example, you could have just as easily have declared showme() to take a pointer to pyramid_t instead of a struct, e.g.

/* function type is void if it returns no value */
void showme (pyramid_t *p)
{
    int i, j; 

    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++)
            printf("%3g ", p->stone[i][j]);
        putchar('\n');  /* use putchar() to output single char */
    }
}

To pass a pointer to your struct in main(), you simply use the unary '&' operator (address of) to pass the address of a, e.g.

    showme (&a);    /* pass pointer to prevent duplicating struct */

Now if you made changes to the array values in the function, the changes would be visible back in main() because you changed the values where they were stored in memory rather than operating on a copy passed to the function.

Look at both examples and understand the differences both in declaring the showme() function and how it is called in main(). The first example passing a copy of the struct and using the dot-operator to access the member would be:

#include <stdio.h>
#include <stdlib.h>

#define N 8     /* good job - if you need a constant, #define one (or more) */

typedef struct {    /* you can simply typedef a struct */
    double stone [N][N];
} pyramid_t;

/* function type is void if it returns no value */
void showme (pyramid_t p)
{
    int i, j; 

    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++)
            printf("%3g ", p.stone[i][j]);
        putchar('\n');  /* use putchar() to output single char */
    }
}

int main (void) {   /* unless using argc, argv, use void */

    /* explicit way to initilize 2D array as 1st member of struct */
    pyramid_t a = {{{10,  4, 2,  5,  1, 0, 0, 0},
                    { 3,  9, 1,  2,  1, 0, 0, 0},
                    {-7, -5, 1, -2, -1, 0, 0, 0},
                    {-3, -5, 0, -1,  0, 0, 0, 0},
                    {-2,  1, 0,  0,  0, 0, 0, 0},
                    { 0,  0, 0,  0,  0, 0, 0, 0},
                    { 0,  0, 0,  0,  0, 0, 0, 0},
                    { 0,  0, 0,  0,  0, 0, 0, 0}}};

    showme (a);     /* passing a copy of the struct to showme() */

    return 0;       /* main() is type 'int' and returns a value */

}

To pass a pointer containing the address of the original struct, you would simply change the declaration of showme() and the operator used to access the struct members:

/* function type is void if it returns no value */
void showme (pyramid_t *p)
{
    ...
            printf("%3g ", p->stone[i][j]);
    ...
}

And, as explained above, you would simply call showme() with the address of a, e.g.

    showme (&a);    /* pass pointer to prevent duplicating struct */

In either case the output would be the same, e.g.

Example Use/Output

> bin\pyramid-struct.exe
 10   4   2   5   1   0   0   0
  3   9   1   2   1   0   0   0
 -7  -5   1  -2  -1   0   0   0
 -3  -5   0  -1   0   0   0   0
 -2   1   0   0   0   0   0   0
  0   0   0   0   0   0   0   0
  0   0   0   0   0   0   0   0
  0   0   0   0   0   0   0   0

Look things over and understand the differences, and let me know if you have further questions.

footnotes:

[1] While not an error, C style generally avoids the use of MixedCase or camelCase variables and the use of all-uppercase names (reserving all uppercase names for constants or macros), instead using variables names of all lowercase. While this is an issue of style, and completely up to you, it can lead to the wrong first-impressions in some settings.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • There is no general “C style”, nor is there any general avoidance of camel case in C. – Eric Postpischil Sep 30 '18 at 11:17
  • Thank you. I think I got hung up on the int *p more than I should have. I will try making changes and see if I can get it working and see what I'm told later. I was understanding that I had to use the int pointer, however there's no way to point it to the Pyramid type correctly then I may have misunderstood something. I greatly appreciate yours and everyones responses. I will keep checking back in case you or anyone wants to add more for me to read and digest. – Tyreese Davis Sep 30 '18 at 20:08
  • Ok so as I'm moving along I see int* ReverseOrder(Pyramid x) given. And this one I got working with no issues without changing it.... So why would this one be ok with accepting a pyramid type but I can't do , what looks like to me the reverse with Pyramid ShowMe(int *p) – Tyreese Davis Sep 30 '18 at 20:14
  • @TyreeseDavis I'm trying to following along. You have an `int* ReverseOrder(Pyramid x)` function. Recall, `int *` is a pointer to `int` which can be a pointer to the first element in an array. Now there is also an aspect of a struct, that the address for the struct is also the address of the first member of the struct. If that function were intending to (through slight of hand) return a pointer to the beginning of the array, there would be two problems (1) it would be returning an address to a local copy, and (2) may violate the strict aliasing rules. Hard to tell without seeing. – David C. Rankin Oct 01 '18 at 00:50