简体   繁体   中英

Pass a string in a struct to a function and return it

I want to return the name of the smallest city population-wise, if it is the second city. (Please don't mind the if statement, I know it's bland), the missing return is what bothers me.

I assume I should declare a pointer inside the function rSmallestCity , like *rtrn but I guess the source variable is destroyed before it is used?

typedef struct Coordinate{
    int x,y;
}Coordinate;

typedef struct city{
    char name[20];
    int population;
    Coordinate coordinates;
}city;

char *rSmallestCity(city **cl, int n)
{
     char *rtrn = NULL;
     if(cl[n-2]->population>cl[n-1]->population)
     {
         rtrn = &cl[n-1]->name;
     }
     return rtrn;
}

int main()
{
    city c1 ={.name="Mumbai", .population=310, .coordinates.x=3, .coordinates.y=4};
    city c2 ={.name="Delhi", .population=300, .coordinates.x=3, .coordinates.y=2};
    city *clist[2];
    clist[0]=&c1;
    clist[1]=&c2;
    printf("\n%s is smallest\n",rSmallestCity(clist,2));
}

warning: assignment to 'char ' from incompatible pointer type 'char ( )[20]' [-Wincompatible-pointer-types]|

I assume I should declare a pointer inside the function rSmallestCity, like *rtrn but I guess the source variable is destroyed before it is used?

A good question. And your assumption is correct. Creating a variable inside a function it's existence ends upon leaving the function. But in this case, because the struct member name is already a char * you do not need to create another variable. Just return c1.name . (see code example below.)

A few other suggestions:

In the struct declaration:

typedef struct Coordinate{
    int x,y;
}Coordinate;

You've used the same symbol ( Coordinate ) for the struct name, and for it's typedef. This is not a good practice. If you need both a struct name and a typedef, pick different symbols. BTW, in this this example, only one or the other is needed. Say you pick the typedef, then the struct is completely defined by:

typedef struct {
    int x,y;
}Coordinate;

That suggestion applies to both struct declarations in your example code.

The signatures for the main function do not include int main(){...} rather
int main(void){..., return 0;} and int main(int argc, char *argv[]){..., return 0;}

The following code example illustrates some of the other suggestions for improvements in comments under your post,

typedef struct {
    int x,y;
}Coordinate;

typedef struct {
    char name[20];
    int population;
    Coordinate coordinates;
}city;

//return char * rather than char to allow for full null terminated char array (string)
char * rSmallestCity(city c1[],int cityCount)//generisize function prototype to 
{                                            //to easily accommodate bigger arrays if needed
    long long size, sizeKeep = 8e9; //index and population. initialize larger than possible population
    int indexKeep = 0;
    //note you do not need to define a char *, the struct already contains one

    for(int i=0; i<cityCount; i++)//use a loop rather than a single comparison, keep the smalles
    {
        size = c1[i].population; 
        sizeKeep = (size < sizeKeep) ? indexKeep = i, size  : sizeKeep;
    }

    printf("\n%s\n",c1[indexKeep].name);
    return c1[indexKeep].name;
};

int main(void)//use minimum signature for main, and call return before leaving.
{
        //combining your original declarations and assignments for struct
        //into a single declaration/definition.
        city c1[] = {{.name="Mumbai", .population=310, .coordinates.x=3, .coordinates.y=4},
                    {.name="Delhi",  .population=300, .coordinates.x=3, .coordinates.y=2}};
        int cityCount = sizeof(c1)/sizeof(c1[0]);

        printf("\n%s is smallest",rSmallestCity(c1, cityCount));

        return 0;
};

The solution that I originally left in comment under OP (remove & in the line &cl[n-1]->name; ) needs some explanations to avoid problems later.

(It is an educational answer not a full answer on pointers, array decay, ... And many examples can be found on stackoverflow. I tried to simplify)

Try this simple code.

int main()
{
    char myString1[25]="Toulouse" ; // French City
    printf("%p\n",myString1);
    printf("%p\n",&myString1);
}

The output is the same, but an array name and the address of an array name are not the same. The array name is evaluated to the address of its first element. So it works in your case but a warning is issued during compilation and it is very important. Firstly, do not remove compilation warnings.

Now, try this code :

int main()
{
    char myString1[25]="Toulouse" ; // French City
    printf("%p\n",myString1+1);
    printf("%p\n",&myString1+1);
}

The outputs are different. Because myString1 is evaluated to char* and &myString1 to char [25] . So +1 , in the first, case adds one ( sizeof char ) to the pointer and in the other case, it adds 25.

Delete the "&" in the line: rtrn = &cl[n-1]->name;

To extremely simplify, you assigned an "address of char[] " to a char* , but array syntax makes it work regardless.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM