I have the following program in C:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
typedef struct str{
char * s;
int len;
}string;
typedef struct stud{
unsigned int id;
string name;
char gender;
}student;
student* addstud(const int id, const char name[64], const char gender);
student* addstud(void){
char buf[64];
struct stud *sb;
sb = (struct stud*)malloc(sizeof(struct stud));
printf("Enter student ID:\n");
scanf("%d",&sb->id);
printf("Enter student name:\n");
scanf("%s", buf);
sb->name.s = buf;
sb->name.len = (int)strlen(buf);
printf("Enter student gender:\n");
scanf(" %c", &sb->gender);
printf("Student ID: %d, name: %s, gender: %c\n", sb->id, sb->name.s, sb->gender);
return sb;
}
int main(){
student *mystudent;
mystudent=addstud();
printf("Student ID: %d, name: %s, gender: %c\n", mystudent->id, mystudent->name.s, mystudent->gender);
getchar();
return 0;
}
In the addstud() function, everthing is fine but in main() when I try to print out the student name from mystudent->name.s it just garbage data. I don't understand why this could happened as it was clearly fine in addstud() function and both pointers point to the same memory address :( Could anyone please shred some light what I did wrong here, please? Thank you!
you can duplicate the buf.
sb->name.s = strdup(buf);
char buf[64];
Here buf is local to function addstud() so once you exit the function this array is out of scope and accessing it will lead to undefined behavior.
sb->name.s = buf;
In this, buf is a local variable to the function addstud(). So, when the function exits, accessing the variable is UB.
You have 2 options,
1)Either allot memory for buf using malloc()
2) Use strcpy() to copy the contents of the variable buf to sb->name.s
Related
I want the program to extract data from the user through the console, by scanning stdin with the scanf() and fgets() and assign the values to named structs, to eventually print them out.
Right the following code is not working. The problem is the code does not recognize the scanned input and the array corona and fails to assign it into that array at index "0".
Here's the code.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
char name[100];
char phone[100];
} Person;
typedef struct {
char location[100];
char time[100];
} Event;
typedef struct {
Person person;
Event event;
} Corona;
int main() {
/*help variables*/
char* name2;
char* number2;
char* location2;
char* date2;
Corona corona[28]; //creating list with 28 objects just because. it could be 5 or x too.
printf("Name");
fgets(name2, 50, stdin); //user input for name
printf("Nummer/location/date");
scanf("%s %s %s", number2, location2, date2); //user input for phone number, location and date
corona[0]= *(Corona*)malloc(sizeof (Corona)); //allocating memory for array
corona[0]={{("%s",name2),("%s", number2)}, {("%s", location2),("%s", date2)}};
/*printing out the information of array "corona" with index 0"*/
printf("Name: %s\n", corona[0].person.name);
printf("Phone: %s\n", corona[0].person.phone);
printf("Location: %s\n", corona[0].event.location);
printf("Time: %s\n", corona[0].event.time);
return 0;
}
lets fix one part of this and see if you can fix the rest
printf("Nummer/location/date");
scanf("%s %s %s", corona[0].person.phone,
corona[0].event.location,
corona[0].event.time);
no need for any mallocs, fancy casts or whatever that assignment line is tryong to do
ie these lines
corona[0]= *(Corona*)malloc(sizeof (Corona)); //allocating memory for array
corona[0]={{("%s",name2),("%s", number2)}, {("%s", location2),("%s", date2)}};
I have two structures. A pointer is assigned to one.
Now I would like to output data previously entered via scanf via a function (outputAddress) with a pointer as a parameter.
It works with the variables via the pointer. But how do I do that with the values from the other structure? How can I output this in the function?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct structPerson
{
char name[30];
char forename[50];
int age;
};
struct structAddress
{
int zip;
char location[35];
char street[40];
int hNumber;
struct structPerson *ptrPerson;
};
void outputAddress(struct structPerson *ptrPerson)
{
printf("\n\nOutput Address: \n");
printf("ptrPerson->name: %s", ptrPerson->name);
printf("\nptrPerson->forename: %s", ptrPerson->forename);
return;
}
int main()
{
struct structPerson person1;
struct structAddress address1;
address1.ptrPerson = &person1;
printf("Location: ");
scanf("%s", &address1.location);
printf("Zip: ");
scanf("%d", &address1.zip);
printf("\nName: ");
scanf("%s", &address1.ptrPerson->name);
printf("Forename: ");
scanf("%s", &address1.ptrPerson->forename);
printf("\nOutput: %d %s %s\n", address1.zip, address1.location, address1.ptrPerson->name);
// strcpy( address1.location, "");
// printf("structAddress1: %d %s\n", address1.zip, address1.location);
outputAddress(&person1);
return 0;
}
In your data model structAddress is associated with a person via the personPtr field. As a result, Address is a main data struct. If I understand your intention correctly, you want to print info about the person and then his/her address.
For this you need to do a couple of changes. Firstly, you should pass the Address struct to the print function, because it has all information available, including the pointer to the person. Secondly, you should access your person information using the pointer: ptrAddress->ptrPerson-><field>. Here is an example.
void outputAddress(struct structAddress *ptrAddress)
{
printf("\n\nOutput Address: \n");
// use ptrAddress->ptrPreson to accesss person information
printf("ptrPerson->name: %s", ptrAddress->ptrPerson->name);
printf("\nptrPerson->forename: %s", ptrAddress->ptrPerson->forename);
// use ptrAddress-> to access address fields.
printf("\nptrAddress->zip: %d", ptrAddress->zip);
...
return;
}
int main() {
...
outputAddress(&address1); // << use address1 here.
...
}
Your datamodel is probably broken anyway. The address struct has a pointer to a person, but it often makes more sense to have it the other way around.
This question already has answers here:
How can I correctly assign a new string value?
(4 answers)
Closed 3 years ago.
I created a linked list that contains a char array. Then I tried to print it using %s and it would not print. I know I have to transform the char by adding in '\0' so that it can print using '/0'. But I'm not sure why.
For example if I input:
Bob 20
It should print:
New student created: Bob is 20 years old.
BUT: it's printing (without "Bob"):
New student created: is 20 years old.
#include <stdio.h>
#include <stdlib.h>
struct student {
char name[50];
int age;
struct student *next;
};
struct student *createStudent(char studentName[], int studentAge);
int main(void) {
struct student *studptr;
int myAge;
char myName[50];
scanf("%s %d", myName, &myAge);
studptr = createStudent(myName, myAge);
printf("New student created: %s is %d years old.\n", studptr->name, studptr->age);
free(studptr);
return 0;
}
struct student *createStudent(char studentName[], int studentAge){
struct student * ptr;
ptr = (struct student *)malloc(sizeof(struct student));
ptr->name[50] = studentName[50];
ptr->age = studentAge;
ptr->next = NULL;
return ptr;
}
NOTE: I understand the code below will work and print the correct name, where I add an additional method to change the char array called copyStr(), but I'm not sure why....
#include <stdio.h>
#include <stdlib.h>
struct student {
char name[50];
int age;
struct student *next;
};
struct student *createStudent(char studentName[], int studentAge);
void copyStr(char *source, char *target);
int main(void) {
struct student *studptr;
int myAge;
char myName[50];
scanf("%s %d", myName, &myAge);
studptr = createStudent(myName, myAge);
printf("New student created: %s is %d years old.\n", studptr->name, studptr->age);
free(studptr);
return 0;
}
struct student *createStudent(char studentName[], int studentAge){
struct student * ptr;
ptr = (struct student *)malloc(sizeof(struct student));
//we need to translate the char into a string
copyStr(studentName, ptr->name);
ptr->name[50] = studentName[50];
ptr->age = studentAge;
ptr->next = NULL;
return ptr;
}
void copyStr(char *source, char *target){
int i = 0;
while(source[i] != '\0')
{
target[i] = source[i];
i++;
}
target[i] = '\0';
}
Arrays do not have the assignment operator.
This statement
ptr->name[50] = studentName[50];
tries to assign the non-existent element with the index 50 of the array pointed to by the pointer studentName to the non-existent element of the array ptr->name.
Instead you should use the standard C function strcpy declared in the header <string.h>.
For example
strcpy( ptr->name, studentName );
Adding to #Vlad's answer, Right way to copy arrays is by iterating over them, thereby, picking each element in char array and copying it to new location. strncpy does exactly that along with buffer overflow checks, which makes it better than strcpy.
Please have a look at strcpy documentation, which says : "ensure size of the array pointed by destination shall be long enough to contain the same C string as source (including the terminating null character), and should not overlap in memory with source"
On a completely different side note, if you're looking for one-liner assignment, you're allowed to do this:
char sample[] = {"randomText"};
char sample2[11] = {"randomText"};
When I run the program and give values to the id, name, surname it gives them all the value of the last student. For instance if the last students name is Anna then all the other names of the array are Anna. With the grades it works well! I tried and without the 'constructor' function and happenden the same thing.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student{ /*struct for student info*/
char *id;
char *name;
char *surname;
int grade;
};
struct Student* Student_new(char* id, char* name, char* surname, int grade);
/*fuction: Student 'constructor'*/
int main(int argc, char *argv[]) {
int no; /*number of students*/
printf("Welcome! \n\nNumber of students: ");
scanf("%d", &no);
struct Student *studentArray[no]; /*arary of struct students*/
int i; /*counter*/
for(i=0; i<no; i++){
char id[10], name[10], surname[10];
int grade;
printf("\n\nStudent(%d)\n", i+1);
printf("id: ");
scanf("%s", id);
printf("name: ");
scanf("%s", name);
printf("surname: ");
scanf("%s", surname);
printf("grade: ");
scanf("%d", &grade);
studentArray[i] = Student_new(id, name, surname, grade); /*using Student
'constructor' to initialize the array*/
}
for(i=0; i<no; i++){
printf("%s %s %s %d \n", studentArray[i]->id, studentArray[i]-
>name, studentArray[i]->surname, studentArray[i]->grade);
}
return 0;
}
struct Student* Student_new(char* id, char* name, char* surname, int grade)
{
struct Student* st = malloc(sizeof(struct Student));
st->id = id;
st->name = name;
st->surname = surname;
st->grade = grade;
return st;
}
PLEASE HELP!!
The issue is that the loop variables go out of scope after each iteration, and you're left with dangling pointers in the Student instances. What you're seeing is the result of undefined behavior.
What's probably happening is that the same char array is being passed into every student instance. Then you modify the same char array, overwriting the previous values.
You'll need to make copies of the strings. Remember to create a function like Student_free where you free the dynamically allocated copies.
struct Student* Student_new(char* id, char* name, char* surname, int grade)
{
struct Student* st = malloc(sizeof(struct Student));
st->id = strndup(id, 10);
st->name = strndup(name, 10);
st->surname = strndup(surname, 10);
st->grade = grade;
return st;
}
You should reserve memory for the string attributes. As a hint, use a struct similar to:
#define MAX_LEN 32
struct Student{ /*struct for student info*/
char id[MAX_LEN];
char name[MAX_LEN];
char surname[MAX_LEN];
int grade;
};
Define MAX_LEN to something that is reasonable for you, and check that the entered values aren't any longer. Also make sure to strcpy the input values to the struct variables.
The student structure only holds pointers to char arrays.
Now the actual space in memory for the strings is allocated in your for cycle an its lifetime is limited by the scope of the for cycle, accessing it afterwards is undefined behaviour. In your case the space where the strings are has not been reused and overridden yet, so coincidentally you are able to get the last value stored (cases like this can also raise segmentation fault).
You should have a look on some basic tutorial about pointers and c memory model. Allocating the arrays in the struct is a good solution (nucleon's answer). Also the scanf function can overflow you should limit the number of retrieved characters to match the size of allocated array.
I have the following code. In the struct definition, I try to ask user to enter employee's first and last name. But when I run this exe, it exit after the title is entered. Any suggestions?
#include<stdio.h>
#include<string.h>
#define NUMEMPS 10
struct Employee {
char *firstname;
char *lastname;
char *title;
int salary;
};
int main()
{
struct Employee* stuff = malloc(NUMEMPS* sizeof *stuff);
int n,i;
for (n=0; n<NUMEMPS;n++)
{
printf("Please enter number %d Employee's Last name:", n);
fflush(stdout);
gets(stuff[n].lastname);
if (strlen(stuff[n].lastname) == 0)
break;
printf("Please enter number %d Employee's first name:", n);
fflush(stdout);
gets(stuff[n].firstname);
printf("Please enter number %d Employee's title:", n);
fflush(stdout);
gets(stuff[n].title);
printf("Please enter number %d Employee's salary:", n);
fflush(stdout);
scanf("%d", &stuff[n].salary);
getchar();
}
for (i = 0;i<n;i++)
{
printf("{%s,%s,%s,%d}\n",
stuff[i].lastname,
stuff[i].firstname,
stuff[i].title,
stuff[i].salary);
}
return 0;
}
The three char* members of the structure are pointers, so no space is allocated to hold any data.
With the current struct you'd have to do three more allocs for the data:
struct Employee* stuff = malloc(NUMEMPS* sizeof *stuff);
stuff->firstname = malloc(101);
stuff->lastname = malloc(101);
stuff->title = malloc(101);
What you probably want is something like:
struct Employee {
char firstname[101];
char lastname[101];
char title[101];
int salary;
};
Also, though as an aside, you must check your malloc calls for a NULL return.
This code:
struct Employee {
char *firstname;
char *lastname;
char *title;
int salary;
};
...
struct Employee* stuff = malloc(NUMEMPS* sizeof *stuff);
only allocates enough room to store a single struct Employee, that is: three pointers and an integer. There's no storage for the character strings pointed to.
Instead, consider malloc()ing each of the constituent character data and assigning to stuff->firstname (et al), or modify the declaration of struct Employee to include character arrays.