Most effective way to print the info of a entire structure C? - c

I want to know if there is a more effective way (less lines, less memory) to print the information contained in the string. I was thinking in a cycle with the funtion argument. For example if you need to print the info(name, group and birthdate) of 100 students, I guess there is a better way that write printstudent( studentn) a hundred times.
The thing is that I dont know how to create a cycle so calls from student1 to student100. I cannot call it student[i] or can I?.
I am open to any kind of suggestions or ideas Thanks!
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
void printstudents(struct st student);
struct st {
char familia[1000];
char imia[1000];
char otchestvo[1000];
int gruppa;
int grozhdenia;
};
int main() {
struct st student1;
struct st student2;
struct st student3;
//Информация студентов:
strcpy(student1.familia, "Putin");
strcpy(student1.imia, "Vladimir");
strcpy(student1.otchestvo, "Vladimirovich");
student1.gruppa = 40040;
student1.grozhdenia = 1952;
strcpy(student2.familia, "Gordon");
strcpy(student2.imia, "Dymitro");
strcpy(student2.otchestvo, "Aleksandrovich");
student2.gruppa = 50050;
student2.grozhdenia = 1953;
strcpy(student3.familia, "Emelianenko");
strcpy(student3.imia, "Fedor");
strcpy(student3.otchestvo, "Olegovich");
student3.gruppa = 60060;
student3.grozhdenia = 1950;
printstudents(student1);
printstudents(student2);
printstudents(student3);
return 0;
}
void printstudents(struct st student) {
printf("Student: %s %s %s, %d, %d \n", student.imia, student.otchestvo,
student.familia, student.gruppa, student.grozhdenia);
}

#include <stdio.h>
#include <string.h>
struct st;
void printstudents(const struct st *student);
struct st {
char familia[1000];
char imia[1000];
char otchestvo[1000];
int gruppa;
int grozhdenia;
};
int
main(void)
{
struct st student[3] = {
{ "Putin", "Vladimir", "Vladimirovich", 40040, 1952 },
{ "Gordon", "Dymitro", "Aleksandrovich", 50050, 1953 },
{ "Emelianenko", "Fedor", "Olegovich", 60060, 1950}
};
for( int i = 0; i < 3; i ++ ){
printstudents(student + i);
}
return 0;
}
void
printstudents(const struct st * student)
{
printf("Student: %s %s %s, %d, %d\n",
student->imia,
student->otchestvo,
student->familia,
student->gruppa,
student->grozhdenia
);
}

If we are talking actual performance in terms of execution speed and memory use, then here are the most obvious bottlenecks:
printf with its format string parsing is slow. It is likely quite a bit faster to use repeated puts calls than a single printf.
Obviously you shouldn't be passing your huge structs by value to the function. struct st student leads to a several kb large struct getting copied to the stack, in case your compiler fails to inline the function call. As a rule of thumb, never pass structs by value. Use pointers.
You make hard copies of constant string literals. You could have just used const char* familia and then do student2.familia = "Gordon"; which is much faster than strcpy. The down-side is that you only get read-only memory if you do like this.

Here's a reworking of your code to use a statically stack-allocated array of 3 student structures (and a helper function to initialize students).
You will need to read up on how pointers work to make sense of it, but that's C for you.
#include <stdio.h>
#include <string.h>
struct st {
char familia[1000];
char imia[1000];
char otchestvo[1000];
int gruppa;
int grozhdenia;
};
static void assign_student(struct st *student, const char *familia, const char *imia, const char *otchestvo, int gruppa, int grozhdenia) {
// TODO: use strncpy
strcpy(student->familia, familia);
strcpy(student->imia, imia);
strcpy(student->otchestvo, otchestvo);
student->gruppa = gruppa;
student->grozhdenia = grozhdenia;
}
static void print_student(struct st *student) {
printf("Student: %s %s %s, %d, %d \n", student->imia, student->otchestvo,
student->familia, student->gruppa, student->grozhdenia);
}
int main() {
struct st students[3];
assign_student(&students[0], "Putin", "Vladimir", "Vladimirovich", 40040, 1952);
assign_student(&students[1], "Gordon", "Dymitro", "Aleksandrovich", 50050, 1953);
assign_student(&students[2], "Emelianenko", "Fedor", "Olegovich", 60060, 1950);
for (int i = 0; i < 3; i++) {
print_student(&students[i]);
}
return 0;
}

Related

Automatic generation of struct printing function in C

I have many programs where structs are defined. And each time, I have to create a function to print the members. For example,
typedef struct {
char name[128];
char address[1024];
int zip;
} myStruct;
void printMyStruct(myStruct myPeople) {
printf("%s\n",myPeople.name);
printf("%s\n",myPeople.address);
printf("%d\n",myPeople.zip);
}
int main()
{
myStruct myPeople={"myName" , "10 myStreet", 11111};
printMyStruct(myPeople);
}
I know that reflection is not supported in C. And so, I write these printing functions for each struct I defined.
But, I wonder if it exists any tricks to generate automatically these printing functions. I would understand that I have to modify a little bit these functions. But, if a part of the job is done automatically, it would be great.
(This example is simple, sometimes struct are nested or I have array of structs or some fields are pointers, ...)
You can of-course print structs, but expect a lot of non-readable output:
#include <stdio.h>
#include <ctype.h>
struct example {
int x;
int y;
char c;
};
#define NOT_PRINTABLE "Not Printable"
void print_structure(const char *structure, size_t size) {
for (size_t i = 0; i < size; i++) {
printf("%ld)\t%.2X: %.*s\n", i, structure[i],
(isprint(structure[i]) ? 1 : sizeof(NOT_PRINTABLE) - 1),
(isprint(structure[i]) ? &structure[i] : NOT_PRINTABLE));
}
}
int main(int argc, char **argv) {
struct example a;
a.x = 5;
a.y = 6;
a.c = 'A';
print_structure((char *)&a, sizeof(struct example));
return 0;
}
But the issue is that, it will print the structs as it is represented in memory. So 4 byte (32 bit) integer 1 will be represented with 4 bytes, not the char '1'.
And due to the way pointers work, you cannot make out if a member is a pointer or a non-pointer.
Another issue is that structures have padding to help with alignment, and better/efficent use of memory. So you would see a lot of 0x00 in the middle.
Remember that C is a compiled language.
let's consider to use https://copilot.github.com/. it's great.
this is what i have with copilot
typedef struct {
char name[128];
char address[1024];
int zip;
} myStruct;
//print struct myStruct >> auto generate by codepilot after you type a comment `print struct myStruct`
void printStruct(myStruct *s) {
printf("name: %s\n", s->name);
printf("address: %s\n", s->address);
printf("zip: %d\n", s->zip);
}

Can't more than two strings compare?

If we compared integers we would assign one of them as the largest/smallest one.
However, when I try comparing more than two strings, I can't manage assaigment.
In my code "for loop" compares two of the strings. This is good method but I need to compare one of them to the others individually. (I can predict that I need to use two for loop, but also I can't implement) What is your suggestions?
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct wordSorting
{
char name[15];
int i = 0;
};
int main()
{
wordSorting *wordElement = (wordSorting *)malloc(sizeof(wordSorting));
wordElement = (wordSorting *)malloc(sizeof(wordSorting));
printf("-- Enter three person name --\n\n");
for (wordElement->i = 0; wordElement->i < 3; wordElement->i++)
{
printf("Enter %d. person name: ", wordElement->i + 1);
scanf("%s", wordElement[wordElement->i].name);
}
printf("\n");
for (wordElement->i = 0; wordElement->i < 3; wordElement->i++)
{
if ((strcmp(wordElement[wordElement->i].name, wordElement[wordElement->i + 1].name))<0)
{
printf("%s", wordElement[wordElement->i].name);
}
}
}
First
typedef struct wordSorting
{
char name[15];
int i = 0;
};
Members of typedef/struct cannot be initied.
That is not the way to define a typedef, change it as:
typedef struct
{
char name[15];
int i;
}wordSorting;
Second:
wordElement = (wordSorting *)malloc(sizeof(wordSorting));
makes no sense. malloc returns void pointer, and you already init your variable at the first element in the first line of code.
And, as someone edited: do not cast malloc return, please.
Third, :
wordSorting *wordElement = (wordSorting *)malloc(sizeof(wordSorting));
wordElement = (wordSorting *)malloc(sizeof(wordSorting));
printf("-- Enter three person name --\n\n");
for (wordElement->i = 0; wordElement->i < 3; wordElement->i++)
{
printf("Enter %d. person name: ", wordElement->i + 1);
scanf("%s", wordElement[wordElement->i].name);
}
You are allocating space for one element, no array are defined then wordElement[wordElement->i].name is undefined Behaviour.
Finally
I don't know what compiler are you using, but gcc cannot compile such a bad code full of errors...
Suggestion.
What I think you need is to use array, but you must allocate the number of member you need, by:
wordSorting *wordElement = malloc(sizeof(wordSorting)*num_of_elements);
or simply, using a local array:
wordSorting wordElement[num_of_elements];

scanf doesn't take all in inputs

I supposed to perform a project which allocate N bytes of memory of struct person
and scanning f every person's name initial_money and some other variables
the problem for me when i run the code is that it is terminating at some point of taking input process and i don't why
also this problem faced me yesterday in code forces contest
#include <stdio.h>
#include <stdlib.h>
struct person
{
char name[15];
int initial_money;
int g;
int final_money;
int money;
};
int main()
{
int NP,i,j;
char target1[15];
scanf("%d",&NP);
struct person *p=malloc(NP*sizeof(struct person));
for(i=0;i<NP;i++)
{
scanf("%s",(p+i)->name);
}
for(i=0;i<NP;i++)
{
scanf("%s",target1);
for(j=0;j<NP;j++)
{
if((p+j)->name==target1)
{
scanf("%d%d",(p+j)->initial_money,(p+j)->g);
(p+j)->final_money=(p+j)->initial_money%(p+j)->g;
}
}
}
for(i=0;i<NP;i++)
{
printf("%s %d %d %d",(p+i)->name,(p+i)->initial_money,(p+i)->g,(p+i)->final_money);
}
return 0;
}
The scanf function need pointers for inputed values.
The line:
scanf("%d%d",(p+j)->initial_money,(p+j)->g);
Should be:
scanf("%d %d",&(p+j)->initial_money,&(p+j)->g);
When comparing strings you usually can't compare pointers directly:
if((p+j)->name==target1)
shoul be:
if(strcmp((p+j)->name, target1) == 0)

C structure; overcoming passing a string to a char

I am trying to print a simple structure, which does not work because I am trying to pass a string into a char (I know this is illegal). Yet I cannot figure out how to overcome this. I know there's a way with strcpy and without strcpy, how can I correct this? I have searched the forum and found similar questions, but was unable to apply them to my problem.
#include <stdio.h>
struct article
{
int number;
int quantity;
char description[21];
};
void print(struct article *p)
{
printf("Article Number: %d\nQuantity: %d\nDescription: %s", p->number, p->quantity, p->description);
}
int main()
{
struct article *mydata;
mydata->number = 333;
mydata->quantity = 465;
mydata->description = "Wall Street Journal\n";
print(mydata);
return 0;
}
struct article mydata = {
333,
465,
"Wall Street Journal\n"
};
print(&mydata);
struct article mydata;
mydata.number = 333;
mydata.quantity = 465;
strcpy(mydata.description, "Wall Street Journal\n");
print(&mydata);
First off, you are declaring a pointer to a struct article. You need to allocate memory for that pointer. It won't be allocated on the stack automatically for you. Using malloc you allocate dynamic memory to the heap.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
struct article *mydata = malloc(sizeof(struct article));
if(article == NULL) {
exit(1);
}
mydata->number = 333;
mydata->quantity = 465;
char *description = "Wall Street Journal\n";
size_t len = strlen(description);
memcpy(mydata->description, description, len);
mydata->description[len] = '\0';
print(mydata);
free(mydata);
return 0;
}
You can also do this. But why do you need alternative ways if you have a function that can do the job for you.
char mydescription[]="Wall Street Journal\n";
int count =0 ;
for( count =0 ; mydescription[count] != '\0' ; count++)
{
mydata->description[count] = mydescription[count] ;
}

How to allocate memory with different type in C?

I have the following code in C:
typedef struct
{
int age;
int phoneNumber;
} Student;
typedef struct
{
int id;
int student[1];
} People;
#define NUM_OF_PEOPLE
void *p = malloc(sizeof(People) + sizeof(int) * NUM_OF_PEOPLE + sizeof(Student) * NUM_OF_PEOPLE);
How could I find the pointer to the memory point to the first element of struct Student in the memory?
I try to do it in the following way:
int i = 0;
for(i = 0; i < NUM_OF_PEOPLE; i++)
{
Student * student_p = p.student[NUM_OF_PEOPLE];
}
It does not work, so can we allocate memory in the way?
And how to find the first element of struct Student in the memory?
What you have is an ancient way of having a flexible array member, which was technically also undefined behavior.
You are looking for this.
First, you need to define your struct like this (I don't know what the ints before the Students are, so let's just call it id):
typedef struct
{
int age;
int phoneNumber;
} Student;
typedef struct
{
int id;
Student student;
} StudentAndId;
typedef struct
{
int id;
StudentAndId students[];
} People;
Note the lack of size in the array inside People. Now you do this:
People *p = malloc(sizeof(People) + sizeof(StudentAndId[NUM_OF_PEOPLE]));
Then you can access students inside p as if it was an array of NUM_OF_PEOPLE elements.
Remember to compile with C99 (or C11) support. With gcc that would be -std=c99 or -std=gnu99.
This will allocate memory for storing the date but how you access it depends on how you store date. using C pointers you can store and access data using this structure and allocation but accessing the members will not be direct. it will involve pointer arithmetic. So better to use other structure if possible. If using this way of allocation then you need to do pointer arithmetic to get the next elements.
Try this:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int age;
int phoneNumber;
} Student;
typedef struct
{
int id;
int student[1];
} People;
#define NUM_OF_PEOPLE 10
int main()
{
People *p = malloc(sizeof(People) + sizeof(int) * NUM_OF_PEOPLE + sizeof(Student) * NUM_OF_PEOPLE);
int* id = (int*)(p+1);
Student* s = (Student*)(id+NUM_OF_PEOPLE);
printf("Size of People : %d\n", sizeof(People));
printf("p points to : %p\n", p);
printf("id points to : %p\n", id);
printf("s points to : %p\n", s);
}
Here's a sample output:
Size of People : 8
p points to : 0x80010460
id points to : 0x80010468
s points to : 0x80010490
You may want to add the id field to your Student data structure, e.g.:
typedef struct {
int id;
int age;
int phoneNumber;
} Student;
Then, you can define a structure having a fixed header (in this case, this can be the number of students), followed by a variable-sized array of Students:
#define ARRAY_OF_ANY_SIZE 1
typedef struct {
int count;
Student students[ARRAY_OF_ANY_SIZE];
} People;
This blog post explains this technique of having "arrays of size 1", including a discussion of the alignment problem.
I won't repeat the original blog post code here. Just consider that you can use the portable offsetof() instead of the Windows-specific FIELD_OFFSET() macro.
As a sample code, you may want to consider the following:
#include <stdio.h> /* For printf() */
#include <stddef.h> /* For offsetof() */
#include <stdlib.h> /* For dynamic memory allocation */
typedef struct {
int id;
int age;
int phoneNumber;
} Student;
#define ARRAY_OF_ANY_SIZE 1
typedef struct {
int count;
Student students[ARRAY_OF_ANY_SIZE];
} People;
int main(int argc, char* argv[]) {
People* people;
const int numberOfStudents = 3;
int i;
/* Dynamically allocate memory to store the data structure */
people = malloc(offsetof(People, students[numberOfStudents]));
/* Check memory allocation ... */
/* Fill the data structure */
people->count = numberOfStudents;
for (i = 0; i < numberOfStudents; i++) {
people->students[i].id = i;
people->students[i].age = (i+1)*10;
people->students[i].phoneNumber = 11000 + i;
}
/* Print the data structure content */
for (i = 0; i < people->count; i++) {
printf("id: %d, age=%d, phone=%d\n",
people->students[i].id,
people->students[i].age,
people->students[i].phoneNumber);
}
/* Release the memory allocated by the data structure */
free(people);
return 0;
}
Output:
id: 0, age=10, phone=11000
id: 1, age=20, phone=11001
id: 2, age=30, phone=11002

Resources