How to use array of pointers to print structure entities? - c

I wrote a program in C which has a structure named ak.
There is an array of pointers s which stores the address of array p of ak type. After inputting the values, only str is getting printed.
How can I print both str and id using array of pointers?
set 1:
#include<stdio.h>
typedef struct
{
char str[10];
int id;
}ak;
int main()
{
printf("Hey\n");
int i;
ak *s[5],p[5];
for(i=0;i<5;i++)
{
s[i]=&p[i];
printf("Input string:");
scanf("%s",&p[i].str);
printf("Input id:");
scanf("%d",&p[i].id);
}
i=0;
while(i<5)
{
printf("%s\n",s[i].id);
++i;
}
return 0;
}
set 2:
#include<stdio.h>
typedef struct
{
char str[10];
int id;
}ak;
int main()
{
printf("Hey\n");
int i;
ak *s[5],p[5];
for(i=0;i<5;i++)
{
s[i]=&p[i];
printf("Input string:");
scanf("%s",&p[i].str);
printf("Input id:");
scanf("%d",&p[i].id);
}
i=0;
while(i<5)
{
printf("%s\n",s[i]);
++i;
}
return 0;
}
So when I tried set1 code,it gave me error saying:
C:\CPP\c\Prototypes>gcc -o ct structure.c
structure.c: In function 'main':
structure.c:22:32: error: request for member 'id' in something not a structure or union
printf("%s\n",*s[i].id);
^
Screenshot is here:
https://imageshack.com/a/img921/3084/j1rHig.png
When I tried set2 code, it only printed str values.
screenshot is here:
https://imageshack.com/a/img922/614/JHSGZ9.png

Concerning set1 and your problems with printf("%s\n",*s[i].id);.
*s[i].id is equivalent to *(s[i].id), not to (*s[i]).id as you probably supposed. Because the type of s[i] is ak * you cannot get its field id through s[i].id.
You can write (*s[i]).id but a more readable way is to use s[i]->id.
Your printf has an other problem, the format cannot be "%s" because s[i]->id is an int, not a char *
Concerning set2
You do printf("%s\n",s[i]);, and you are surprised because only the string is printed, how can you expect that print the string and the int ?
You request to print a string (format %s) but s[i] is not a string. By chance the struct starts by the field str being a string, so yes you write it, but this is not the right way.
You have to explicitly print each attributes, for instance doing printf("%s %d\n",s[i]->str, s[i]->id);

Related

Error while printing the given inputs

This code:
#include<stdio.h>
struct my_structure {
char name[20];
int number;
int rank;
};
int main()
{
int n,i;
scanf("%d",&n);
struct my_structure variable[n];
struct my_structure *ptr;
ptr = &variable;
for(i=0; i<n; i++)
{
scanf("%s",ptr->name);
scanf("%d",&ptr->number);
scanf("%d",&ptr->rank);
}
for(i=0; i<n; i++)
{
printf("NAME: %s\n", ptr->name);
printf("NUMBER: %d\n", ptr->number);
printf("RANK: %d", ptr->rank);
}
return 0;
}
It is not printing correctly. I want to print the 1st input first and then the second. But I'm getting the output like printing only the second input two times.
Two changes you need to do:-
ptr = variable ;
Then you can increase ptr in loop.(The use of scanf is not robust - how to do it better is shown in the end of the answer).
for(i=0;i<n;i++)
{
scanf("%s",ptr->name);
scanf("%d",&ptr->number);
...
ptr++;
}
After that again do the assignment ptr = variable;.
You can also do this (Illustration on the users code)
..
scanf("%s",ptr[i].name);
scanf("%d",&ptr[i].number);
...
printf("%s",ptr[i].name);
printf("%d",ptr[i].number);
Earlier you have type mismatch in assignment. You were assigning a struct my_structure (*)[n] to struct my_structure*. Check the return value of scanf and also check the value n (n>1).
You can do it on your way also:(Illustration on the users code)
struct my_structure (*ptr)[n] = &variable;
for(i=0;i<n;i++)
{
scanf("%s",(*ptr)[i].name);
scanf("%d",&((*ptr)[i].number));
scanf("%d",&((*ptr)[i].rank));
}
...
printf("%s",(*ptr)[i].name);
printf("%d",((*ptr)[i].number));
Correct way to use scanf would be:-(Notice that here 19 is used - otherwise there is a chance of buffer overrun - and this is being checked using this.This is one less than the size of the array because of the \0 character ) (Correct way)
if(scanf("%19s",ptr[i].name) != 1){
/* error in input */
fprintf(stderr,"Error in input\n");
exit(EXIT_FAILURE);
}
Compile your program with all warnings enabled. gcc -Wall -Werror progname.c.
Clearly you don't even need to use this pointer - why would you do that? You can simply use the array itself in the scanf or printf.

Why am I getting garbage value after displaying the data

I am getting garbage value when I display the records.
I have to create a database of students in C using array of structures and without pointers.
Is there any other way of doing this?
How to use array of structures?
#include <stdio.h>
struct student {
char first_name[10],last_name[10];
int roll;
char address[20];
float marks;
};
void accept(struct student);
void display(struct student);
void main() {
struct student S[10];
int n, i;
printf("Enter the number of records to enter : ");
scanf("%d", &n);
for (i = 0; i < n; i++) {
accept(S[i]);
}
for (i = 0; i < n; i++) {
display(S[i]);
}
}
void accept(struct student S) {
scanf("%s", S.first_name);
scanf("%s", S.last_name);
scanf("%d", &S.roll);
scanf("%s", S.address);
scanf("%f", &S.marks);
}
void display(struct student S) {
printf("\n%s", S.first_name);
printf("\n%s", S.last_name);
printf("\n%d", S.roll);
printf("\n%s", S.address);
}
Everything in C is pass-by-value. Which means you are modifying variable copy in stack frame, while real variable passed as parameter remains untouched.
You have to pass an pointer to variable which you want to modify in function.
// Function declaration
void accept(struct student *);
// Call
accept(&S[i]);
// Usage in function via dereference operator
scanf("%s",S->first_name);
If you would like to enter unknown amount of records, you should use VLA (since c99) or dynamically allocate structures.
VLA
scanf("%d",&n);
struct student S[n];
Dynamic callocation
scanf("%d",&n);
struct student * S = malloc(sizeof(struct student) * n);
Because in your case, if user input more that 9 records you are touching outside of bounds, which has undefined behavior.
There are multiple issues in your code:
The standard prototype for main without arguments is int main(void)
You should allocate the array dynamically with calloc.
you should pass structure pointers to the accept and display functions instead of passing structures by value. Passing the destination structure by value is incorrect as the accept function cannot modify the structure in the main function, which remains uninitialized and causes garbage to be displayed. Note that it is actually undefined behavior to access uninitialized data so the program could behave in even worse ways.
You should provide scanf() with the maximum number of arguments to store into character arrays to avoid potential buffer overflows.
you should verify the return values of scanf() to avoid undefined behavior on invalid input.
you could use the %[^\n] scan set to allow embedded spaces in the address field.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
struct student {
char first_name[10], last_name[10];
int roll;
char address[20];
float marks;
};
void accept(struct student *sp);
void display(const struct student *sp);
int main(void) {
struct student *S;
int n, i, j;
printf("Enter the number of records to enter : ");
if (scanf("%d", &n) != 1)
return 1;
S = calloc(sizeof(*S), n);
if (S == NULL) {
return 1;
}
for (i = 0; i < n; i++) {
accept(&S[i]);
}
for (i = 0; i < n; i++) {
display(&S[i]);
}
free(S);
return 0;
}
void accept(struct student *sp) {
if (scanf("%9s%9s&d %19[^\n]%f",
sp->first_name, sp->last_name, &sp->roll,
sp->address, &sp->marks) != 5) {
printf("missing input\n");
exit(1);
}
}
void display(const struct student *sp) {
printf("%s\n", sp->first_name);
printf("%s\n", sp->last_name);
printf("%d\n", sp->roll);
printf("%s\n", sp->address);
printf("%f\n", sp->marks);
printf("\n");
}

Handling struct functions in C - Can enter an array but not an int

I'm having a bit of trouble with using structs inside functions.
The program is meant to:
Create an array containing five structures of type Person
Allow the user to enter the datatypes through use of functions.
Print the five entered people one by one.
While point 1 and 3 work fine, it's point 2 that I'm having issues with. The name will enter and print just fine, but regardless of what I enter into scanf it returns and prints '-858993460'.
int calls = 0;
typedef struct person {
char name[20];
int bYr;
}Person;
int main(int argc, char** argv) {
Person psn[5];
for (int i = 0; i < 5; i++) {
printf("Please enter the name and birthyear of person %d.", i+1);
personName(psn[i].name);
personBirthyear(psn[i].bYr);
}
for (int i = 0; i < 5; i++) {
printPerson(psn[i]);
}
getchar();
return 0;
}
int personBirthyear(int birthyear) {
printf("\nBirthyear: ");
scanf("%d", &birthyear);
getchar();
return birthyear;
}
char* personName(char* pername) {
printf("\nName: ");
fgets(pername, 20, stdin);
return pername;
}
void printPerson(Person prsn) {
printf("Person %d:\nBirthyear: %d\nName: %s\n", calls+1, prsn.bYr, prsn.name);
calls++;
}
Easy enough: you are not updating a Person' year, but you are passing it as a copied argument (you copy an int in personBirthyear and a pointer to a char in personName).
Thus:
personName(psn[i].name); // works
personBirthyear(psn[i].bYr); // fails
You need to pass the address of year, and work with pointers here:
int personBirthyear(int* birthyear) {
printf("\nBirthyear: ");
scanf("%d", birthyear);
getchar();
return *birthyear;
}
Or, you could also remove the birth year:
int personBirthyear() {
int birthyear;
printf("\nBirthyear: ");
scanf("%d", &birthyear);
getchar();
return birthyear;
}
Then: psn[i].bYr = personBirthyear();
In any case, you don't check the result of scanf; thus you don't know if you actually read a number. You should check it:
int n = scanf("%d", &birthyear);
getchar();
if (n != 1) return -1;
return birthyear;
The getchar is still mandatory to "clear" away the character that made scanf fail (otherwise, it would be reread again and again...).
you have some problems in your code :
You are not receiving a output while returning from function.
Without function declaration compiler will confuse about function return type.
you should know if you want to accept modified data between function call, data should provide as pass by reference. in your program, you give data to personBirthyear() function as call by value.

C: Using strcpy to transfer one struct element to an array

Okay, so we're supposed to prompt a user to enter 25000 lines of text.
Each line contains three integers each. We are then to pass the third integer in that line to another struct, and connect each integer until you have 25000 interconnected integers.
Here's what I've tried:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct graph{
int begin;
int end;
int cost;
} PathEdge;
int comp_fcn(const void *a, const void *b) {
return ((PathEdge *) a)->cost - ((PathEdge *) b)->cost;
}
int main(void)
{
int nlines,i;
char r;
int ecost,ebegin,eend;
scanf("%d",&nlines);
PathEdge edges[nlines+1];
for(i=0;i<nlines;i++)
{
scanf("%d, %d, %dn",&ebegin, &eend, &ecost);
edges[i].begin = ebegin;
edges[i].end = eend;
edges[i].cost = ecost;
struct town
{
struct town *north;
int name[25000];
};
struct town *root, *current;
root = malloc(sizeof(struct town));
root->north = NULL;
strcpy (root->name,ecost);
current = malloc(sizeof(struct town));
current->north = root;
strcpy (current->name,ecost);
}
printf("Please enter a node that you want to examine. If you want to exit, please press 'X'.n");
scanf("%c",&r);
switch(r)
{
case 'X':
case 'x':
printf("You entered a wrong value. Gomen. Try againn.");
break;
default:
if((0<r)&&(r<25000))
{
printf("You have accessed node %dn",r);
printf("Its neighboring nodes are %dn",edges[r].cost);
printf("Its neighboring nodes are %dn",edges[i].cost);
}
else
{
printf("Invalid input again. Please do try again. Thanksn");
}
break;
}
return 0;
}
And there are warnings...
"passing argument 1 of strcpy from incompatible pointer type"
"passing argument 2 of strcpy makes pointer from integer without a cast"
expected char*__ restrict __ but argument is of type 'int'
plus when I inputted that 25000 lines of text, segmentation fault happens. Please help. Thank you!
strcpy is for copying strings (i.e. zero terminated byte char "arrays"), you maybe should use memcpy instead.
Or if you just want to assign a single integer to one element in the array, use plain assignment:
current->name[someIndex] = ecost;
Or, maybe you intend that thename member should be a string? Then you should be using an array of characters and not integers. And you need to convert integer values to strings, using e.g. sprintf:
sprintf(current->name, "%d", ecost);
you can convert the integer to string using itoa and copy the string into root->name.
char str[20];
itoa(ecost, str, 10);
strcpy(root->name, str);
You did not state your exact issue so I am assuming you are overwhelmed and in that case you should try partitioning your implementation into functions so that you can work on isolated problems instead of a web of interconnected problems.
Here is one example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct graph {
int begin;
int end;
int cost;
} PathEdge;
const char * GenerateInput()
{
static char local[2000];
static int last = 0;
int a, b, c;
a = last++;
b = last++;
c = last++;
sprintf_s(local, 2000, "%i %i %i", a, b, c);
return local;
}
void PathEdgeInitializeFromString(PathEdge * edge, const char * str)
{
sscanf_s(str, "%d %d %dn", &edge->begin, &edge->cost, &edge->end);
}
void QueryAndPrint(PathEdge * edges, int edges_n)
{
printf("Enter a number from 1 to %i: ", edges_n);
int index = 0;
scanf_s("%i", &index);
--index;
if (index < 0 || !(index < (edges_n)))
printf("Error");
else
printf("%i, %i, %i\n", edges[index].begin, edges[index].cost, edges[index].end);
}
int main() {
PathEdge edges[25000];
for (int i = 0; i < 25000; ++i)
{
const char * line = GenerateInput();
PathEdgeInitializeFromString(edges + i, line);
}
QueryAndPrint(edges, 25000);
return 0;
}

How to accept character array input into a structure in C?

I've got this structure, a simple one that holds student name and marks. When I'm trying to read user input into the name(char array), I get a warning indicating something on the lines of :
format %s expects char *, but has char*[20]
I know this is because char arrays cannot be assigned in C, so strcpy has to be used. This question on SO has a good reasoning. However,how do I fix the warning in my program? Don't think I can use strcpy here.
#include <stdio.h>
typedef struct _student
{
char name[20];
unsigned int marks;
} student;
void read_list(student list[], int SIZE);
void print_list(student list[], int SIZE);
int main()
{
const int SIZE=3;
student list[SIZE];
//function to enter student info.
read_list(list, SIZE);
//function to print student info
print_list(list, SIZE);
return 0;
}
void read_list(student list[], int SIZE)
{
int i;
char nm[20];
for (i=0;i<SIZE;i++)
{
printf("\n Please enter name for student %d\n", i);
scanf("%s",&list[i].name);
printf("\n Please enter marks for student %d\n", i);
scanf("%u", &list[i].marks);
}
}
void print_list(student list[], int SIZE)
{
int i;
printf("\t STUDENT NAME STUDENT MARKS\t \n");
for(i=0;i<SIZE;i++)
{
printf("\t %s \t %u\n", list[i].name, list[i].marks);
}
}
The program does give a correct output, but the warning remains.
Try this code:
for (i=0;i<SIZE;i++)
{
printf("\n Please enter name for student %d\n", i);
scanf("%s",list[i].name);
printf("\n Please enter marks for student %d\n", i);
scanf("%u", &list[i].marks);
}
This is because & used in scanf statement is to get the address.
In your case you use array name i.e. name and array name itself is providing the address. Remember array name gives the base address of an array.
change scanf("%s",&list[i].name); to scanf("%s",list[i].name);. Delete &. Because basically array name represents base address. No need to mention address of array for scanning the string.
Remove the & in the scanf that scan in a string using %s to eliminate the warning. So change
scanf("%s",&list[i].name);
to
scanf("%s",list[i].name);
This is because the name of the char array decays to a pointer to its first element
line 33:
scanf("%s",&list[i].name);//wrong
scanf("%s",list[i].name);//right
The name of an array is synonym for the location of the initial element , thus in your code, variable 'name' is the address of name[0]. You don't need to use & on 'name' to get the address of the array.Just use 'name' itself.

Resources