how do i get values stored in struct? - c

I am trying to retrieve values from an array of structs. I do not know the correct ways to retrieve them.
Here is my struct:
struct entry{
char name[NAME_SIZE];
int mark;
};
typedef struct entry Acct;
Acct dism2A03[MAX_ENTRY];
How i assigned values:
void add_new(char *name,int mark){
printf("%s,%d",name,mark);
int v=0;
v=entry_total;
strcpy(dism2A03[v].name,name);
dism2A03[v].mark = mark;
}
What i tried (DOES NOT WORK):
int m=0;
for(m=0;m<MAX_ENTRY;m++){
char name[NAME_SIZE] = dism2A03[m].name;
line 75 >> int mark = dism2A03[m].mark;
printf("\nEntry %d",m);
printf("%s",name);
printf("%d",mark);
}
ERROR:
p9t2.c: In function ‘main’:
p9t2.c:75:5: error: invalid initializer

Your first attempt implies existence of getfield function that takes a struct and a multicharacter char literal and gets the field; there is no such function in C.
Your second attempt is much closer: rather than trying to assign the name to an array, assign it to a char pointer, like this:
int m=0;
for(m=0;m<MAX_ENTRY;m++){
// Since you aren't planning on modifying name through pointer,
// you can declare the pointer const to make your intentions clear.
const char *name = dism2A03[m].name;
int mark = dism2A03[m].mark;
printf("\nEntry %d",m);
printf("%s",name);
printf("%d",mark);
}

Related

Why are pointers expected in structures?

I was just testing structures using C. The code is:
#include <stdio.h>
struct {
int age;
char name[]; //just an array
char gender; //just a character (M for male and F for female)
}person;
int main()
{
person.age=10;
person.name="John";
person.gender="M";
printf("Person's age: %d", person.age);
printf("Person's name: %s", person.name);
printf("Person's gender: %c", person.gender);
return 0;
}
However, what the compiler returns is:
warning: initialization of 'char' from 'char *' makes integer from
pointer without a cast [-Wint-conversion]|
I have no idea what this means or why it appears.
This code has multiple issues.
First:
person.name="John";
You cannot assign a char* to a char array. The two types are not compatible.
You must either change your struct to:
char* name; //just an char pointer
Or use strcpy() to copy the name to this array.
strcpy(person.name, "John");
Also, you need to specify the size of this array in your struct. Depending on your compiler, funny things can happen with an undefined array size like this.
Second:
person.gender="M";
You also cannot assign a char* to a char.
Either change gender to be of type char*, or change your assignment to use a char.
person.gender = 'M';
Why are pointers expected in structures?
Pointers are not expected, nor are they dis-allowed.
"warning: initialization of 'char' from 'char *' makes integer from pointer without a cast [-Wint-conversion]|"
person.gender="M"; errantly attempts to take a pointer (the address of the stirng literal "M") and assign it to a char (.gender). Pointers do not fit in a char.
OP's code is invalid. OP is relying on a code extension.
A member like char name[]; must be the last member in a struct. There it is a flexible array member.
struct {
int age;
// char name[]; // move to the end
char gender;
char name[];
}person;
There are no pointers in OP's struct. With repair, member .name[] is an array.
Example usage
#include <stdio.h>
#include <stdlib.h>
// Define a type
typedef struct {
int age;
char gender;
char name[]; // last member
} person;
// Allocate and populate data
person* person_initialize(int age, const char *name, char gender) {
size_t len = strlen(name);
// Size needed is for the `person` and the name as a _string_.
person *p = malloc(sizeof *p + len + 1);
// If successful ....
if (p) {
p->age = age;
p->gender = gender;
strcpy(p->name, name);
}
return p;
}
int main(void) {
person *p = person_initialize(10, "John", 'M'); // Note 'M', not "M".
if (p) {
printf("Person's age: %d", p->age);
printf("Person's name: %s", p->name);
printf("Person's gender: %c", p->gender);
free(p);
}
return 0;
}
"Why are pointers expected in structures?"
They are not. They are also not unexpected.
This construction is however:
struct {
int age;
char name[]; //just an array <- A BOMB
char gender; //just a character (M for male and F for female)
} person;
You here have an instance (person) of an anonymous struct with a flexible array. Old-school structs with this setup had their last member declared as type identifier[1];.
[1] was historically used because a zero element array has never been valid in standard C (although accepted as a language extension by some compilers).
The C99 standard made char name[] legal by allowing indexing such an array if it's made the last element in a struct. The name[] member in your struct is not.
The purpose of the flexible array was to let writing to such an array be legal to let the programmer (or a called function) pre-allocate memory and have functions return an unknown amount of elements by writing their result in that memory.
If your struct is accepted by a compiler, a funcion using it will overwrite gender when writing more than zero chars to name as an answer.
This would be a definition (and typedef) with the potential of being used properly:
typedef struct person_ {
int age;
char gender;
struct person_ *next; // points somewhere after the '\0' in name[] or NULL
char name[]; // Pre C99 "char name[1];" was often seen
} person; // a typedef, not an instance here

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.

Dynamic struct in C

I am trying to read the inputed name, save it in a dynamic struct, add a number at the end if it and count it up. I managed to do the first part, but i cant seem to pass the struct address to the function that should count, nor make the function work.
struct ime_dadoteke
{
unsigned char *ime;
unsigned char velikost;
//this is the struct im working with
};
This is the main:
struct ime_dadoteke *ime;
ime = ime_init();
int i=1;
do
{
naslednje_ime(ime, i); /*here is the problem with passing the
address. I also tried &ime with parameter
struct ime_dodoteke **ptr.
I get error cannot convert argument 1
from 'ime_dadoteke *' to 'ime_dodoteke *' */
i++;
} while (i <= st_korakov);
This is the first function which works:
struct ime_dadoteke* ime_init()
{
int i;
struct ime_dadoteke *rtn = (struct ime_dadoteke*)malloc(sizeof(struct ime_dadoteke));
printf_s("Vnesi ime slike.\n");
rtn->ime =(unsigned char*)malloc(sizeof(unsigned char));
for (i=0; rtn->ime[i-1]!=10; i++)
{
scanf("%c", &rtn->ime[i]);
rtn->ime = (unsigned char*)realloc(rtn->ime, (i+2)*sizeof(unsigned char));
};
rtn->ime[i]='\0';
rtn->velikost = i;
fseek(stdin, 0, SEEK_END);
return rtn;
};
And this is the skeleton of the function that should count the number at the end of the name. I didnt build it yet because i get a problem: pointer to incomplete class is not allowed.
void naslednje_ime(struct ime_dodoteke *ptr, int i)
{
struct ime_dadoteke *ime = ptr;
ptr /*ptr is underlined (error) */->ime[ptr /*ptr is underlined (error) */->velikost - 1] = '0';
};
Also note i created the struct with size of string in it because strlen() doesnt wanna take a non const char. Is there a way around this?
The error message pointer to incomplete class is not allowed means the structure (you told us that referencing members of the struct ime_dadoteke via pointer struct ime_dadoteke *ptr caused the error message) is not defined in the source unit where naslednje_ime is defined. You need to put the struct definition in a header file and include it wherever you use it, also in the file where you define naslednje_ime.

display a specified index of a pointer char*

I am trying to point on a specified character in a string contained on a structure
here my code
typedef struct{
char *name;
int age;
}PERSON, *person;
int main(){
person serenity;
serenity = (person)malloc(sizeof(PERSON));
strcpy(&(serenity->name),"Serenity");
printf("%c",*(&(serenity->name)+1));
}
here i wanted to display the second character which is 'e' but it shows 'n' instead
anyone can explain me what is wrong with this,
thank you
You have not allocated memory for name
typedef struct{
char *name;
int age;
}PERSON, *person;
int main(){
person serenity;
serenity = malloc(sizeof(PERSON));
serenity->name = malloc(sizeof("Serenity")); //<< Missing
strcpy((serenity->name),"Serenity");
printf("%c",*((serenity->name)+1)); // << Also you want the value in pointer name NOT its address
return 0;
}
Outputs e. Also since you tagged C there is no need to cast the return type of malloc.
Okay, okay... All of those answers aside, if you do not aim to change the characters inside the string "Serenity" in the future, you could just do the following:
#include <stdio.h>
typedef struct{
const char *name; // <-- added const
int age;
}PERSON, *person;
int main( ){
person serenity;
serenity = (person) malloc( sizeof( PERSON ) );
serenity->name = "Serenity"; // <-- simply assigned the pointer with the
// address to the array of constant characters
printf( "%c", *( serenity->name + 1 ) ); // <-- changed this
}
This statement
serenity = (person)malloc(sizeof(PERSON));
allocates the structure
typedef struct{
char *name;
int age;
}PERSON
however name is kept uninitialized and points somewhere in memory causing a crash when you copy to it.
So instead of
strcpy(&(serenity->name),"Serenity");
write
serenity->name = strdup("Serenity");
which is the same as
serenity->name = malloc(strlen("Serenity")+1);
strcpy(serenity->name,"Serenity");
don't forget to free that string as well later.
Try printf("%c",*(serenity->name+1));, also do strcpy(serenity->name,"Serenity");.
If you have a pointer char* name; you access the second element by doing name[1] or *(name+1). &name will give you the address where the pointer address of name is stored. This is not what you want here.
Another issue in your program is that you never allocate memory for the variable name. You need a serenity->name = (char*)malloc(128);. But using an arbitrary length like 128 is very dangerous in combination with strcpy. Use strncpy instead of strcpy to work around this.

syntax error before '[' token

Here is the code
#include<stdio.h>
#include<sys/types.h>
#include<stdlib.h>
#include<pthread.h>
typedef struct std_thread
{
char name[20];
int hallno;
int empid;
char dept[5];
}std[5];
void *print(void *args)
{
struct std_thread *data=(struct std_thread *)args;
printf("My thread id is %ld\n",pthread_self());
printf("Thread %d is executing\n",args);
printf("Name\tHall No\tEmployee ID\tDepartment\n");
printf("--------------------------------------------------------");
printf("%s\t%d\t%d\t%s\n",data->name,data->hallno,data->empid,data->dept);
}
int main()
{
pthread_t th[5];
int empid=2020;
int hall=1;
char dept[2]="IT";
char *names[]={"dinesh","vignesh","pradeep","prasath","mohan"};
int t;
int i;
int status;
for(i=0;i<5;i++)
{
std[i].name=names[i]; //Getting error from this line
std[i].hallno=hall; //Error at this line
hall++;
std[i].empid=empid; //Error at this line
empid++;
std[i].dept=dept; //Error at this line
status=pthread_create(&th[i],NULL,print,(void *)&std[i]);
if(status)
{
printf("Error creating threads\n");
exit(0);
}
}
pthread_exit(NULL);
}
While compiling this code, I'm getting "syntax error before '[' token". What is the reason for this?
This declaration does not do what you think it does:
typedef struct std_thread
{
...
}std[5];
This declares a struct named std_thread, and then it creates a typedef named std to mean "an array of 5 struct std_thread objects".
You probably wanted one of these two definitions, in order to declare a global object named std as an array of 5 struct std_thread's:
typedef struct std_thread
{
...
} std_thread;
std_thread std[5];
// OR
struct std_thread
{
..
} std[5];
In the first case, we also create the typedef named std_thread as an alias for struct std_thread; in the second case, we do not.
Furthermore, as others have stated, you cannot copy character arrays by assignment. You must copy them using a function such as strcpy(3) or strncpy(3). When using strcpy, you must ensure that the destination buffer is large enough to hold the desired string. Also keep in mind that strncpy does not necessarily null-terminate its destination string, so use it with caution.
I don't think you mean to typedef up the top.
What you've written there makes std an equivalent type as five of the structs in an array, but then you use std as though it is itself an array.
Remove the word typedef from line five and it should be closer to working.
Use string copy function instead of assigning char array.
You are trying to copy a string using assignment:
std[i].name=names[i];
and
std[i].dept=dept;
that does not work. Use a strcpy or better strncpy instead.
You have a typo in:
std[i].empid=empdid; //Error at this line
You don't have a var named empdid.
This code:
typedef struct std_thread
{
char name[20];
int hallno;
int empid;
char dept[5];
} std[5];
declares the type std to be an array of 5 struct std_thread structures.
This code:
int main()
{
[...]
int i;
int status;
for (i = 0; i < 5; i++)
{
std[i].name = names[i];
assumes that std is a variable with array or pointer type.
You need to remove the keyword typedef to make the code consistent with the use of the variable.
Then you can start running into problems with string assignments where you need to use string copy functions, etc.

Resources