I need to create dynamic array of Parents where lastname is dynamic.
But I receive an error about error reading characters of string.
parent ** getParents(){
parent parent_in;
parent** parentsArray=NULL;
char answer;
int i, numOfParents=0,fExit=0;
do
{
printf("Do you wan't to enter parent? Y/N\n");
flushall();
scanf("%c", &answer);
if (answer == 'N')
{
fExit = 1;
}
else
{
parent_in.lastname = (char*)malloc(20 * sizeof(char));
parentsArray = (parent**)realloc(parentsArray, 1 * sizeof(parent*));
parentsArray[numOfParents] = (parent*)calloc(1, sizeof(parent));
printf("Please enter the lastname and num of childrens\n");
scanf("%s %d", &parentsArray[numOfParents]->lastname, &parentsArray[numOfParents]->numOfChildren);
numOfParents++;
free(parent_in.lastname);
}
} while (fExit == 0);
return parentsArray;
}
Here is struct of parents:
struct Parents{
char *lastname;
int numOfChildren;
}typedef parent;
Your code is a bit wired, as you mix the use of data structure parent_in with the use of parentsArray and it's entries; you malloc on the one, and use it at the other (e.g. concerning parent_in).
But concerning your error, there are two main issues that I see immediately:
You scanf a string into a non-initialized pointer, i.e scanf("%s %d", &parentsArray[numOfParents]->lastname, .... Note that you might have reserved space for a parents structure; this structure has a pointer to lastname, which for itself does not get "malloced".
You (re)-allocate always to the same number of entries, i.e. 1 in
parentsArray = (parent**)realloc(parentsArray, 1 *
sizeof(parent*)). You probably meant realloc(parentsArray,
(numOfParents+1) * sizeof(parent*)).
I suppose that point 1 is responsible for your "error reading characters of string"; If you overcome this, I'm rather sure that point 2 will lead to the next memory corruption.
Related
I have created entry2_player helper function but I am looking for somebody that can verify if this is the correct responds to my given instructions below:
This expects a string entry, consisting of a name, space, and an int score.
When entry is "Sam 67", this function:
displays 'malloc() for "Sam 67" ...'
attempts malloc() for a Player:
if malloc() fails, the function displays: 'Failed! Returning NULL'
attempts to convert entry with *n = sscanf(...) to name and score of a
Player variable. If successful, (indicated by *n = 2) displays 'at address: 0x000....' and returns its address.
if entry is not valid, e.g. "Sam45", this function free the allocated memory,
and displays 'Invalid entry string! Returning NULL', and returns NULL.
REF: https://en.cppreference.com/w/c/io/fscanf
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
// Room for a short name string in Player:
#define NAME_SIZE 10
// Incremental number of memory, in units of pointers, by which to increase
// size of Player pointer array:
#define MALLOC_INCR 5
typedef struct {
char name[NAME_SIZE] ;
int score ;
} Player ;
Player * entry2_Player(char *entry, int *n) {
char name[10];
int score;
printf("\nmalloc() for %s ...", entry);
Player *pID = (Player *)malloc(sizeof(entry));
if (pID == NULL){
printf("Failed! Returning NULL");
return NULL;
}
*n = sscanf(entry, "%s %d", name, &score);
if (*n !=2){
printf("Invalid entry string!");
free(pID);
return NULL;
}
else{
printf("at address: 0x%p", &n);
return pID;
}
}
In my main function I am required to:
Create a single Player variable, using entry2_Player() with the string "Robin 78" and
display it with show_Player(). Store the Player in the array from part 2. Add a fifth Player
to the array directly from entry2_Player(). Display the Player array with show_Players()
I am looking to see if my return variables in entry2_player are correct in order for me to continue with this next instructions.
First, what you're actually doing:
You allocate a block of memory of size of pointer to char. On current systems, this could be 8 bytes. Then you're trying to read two items from the input string entry into the (locally - stack - allocated) variables name and score. If that succeeds, you're returning the 'untouched' allocated block of memory.
What you probably want to do:
Allocate a block of memory of size Player. Without knowing the system specs, sizeof(Player) > sizeof(char*). Then you want to read two items from the input string entry into the fields name and score of the allocated Player object. And if that succeeds, you'll return the 'properly initialized' Player object.
Btw.
printf("at address: 0x%p", &n);
What do you want to present here? n is a pointer, that means it contains the address of an int. The above statement prints the address of the pointer.
I think, the following was the intention:
printf("at address: %p", pID); //%p prints the address in hex format, preceded by '0x'
sizeof entry == sizeof(char*) will not return the length of the string entry, but the number of bytes required to store a pointer to char.
strlen(entry) will give you the length of the string entry.
Based on the comment below, here the formal explanation:
Player * entry2_Player(char *entry, int *n)
{
printf("\nmalloc() for %s ...", entry);
//alloc Player object
Player *pID = malloc(sizeof(Player));
if (pID == NULL){
printf("Failed! Returning NULL");
return NULL;
}
//parse entry into the fields of pID
*n = sscanf(entry, "%s %d", pID->name, &pID->score);
if (*n !=2){
printf("Invalid entry string!");
free(pID);
return NULL;
} else {
printf("at address: %p", pID); //address of allocated memory
return pID;
}
}
I am trying to write text to a file using loops, but when I make it like (ogrenci+i) using i and not like (ogrenci+0) I'm getting some weird numbers and text in txt file.
When writing like this (ogrenci+0) it works correctly. What am I doing wrong?
I attent pointer to struct in a different function.
this is the question
QUESTIONS
Assume that you are given the structure below
typedef struct StudentMark {
char name[20];
char surname[20];
int midterm;
int final;
}STUDENT_MARK;
1-) Write down a program which contains
a-) A function to get the user entered name, surname, and exam marks into
dynamically
allocated STUDENT_MARK structure (your function MUST check input validity
i.e
entered marks must between [0..100]).
b-) A function to write down the entered VALID structures into a file
named as
marks_YOUR_STUDENT_ID.txt.
2-) Write a program which contains
a-) A function to read a file named as marks_YOUR_STUDENT_ID.txt which contains
STUDENT_MARK structures’ data.
b-) A function to calculate the average of each student’s exam marks and writes the result
onto screen as
“The student NAME SURNAME’s midterm mark is MIDTERM, final mark is
FINAL and his/her average is AVERAGE”
void girme (int studentnum){
int i;
studentnum = 2;
STUDENT_MARK *ogrenci;
ogrenci = (STUDENT_MARK*) malloc(studentnum * sizeof(STUDENT_MARK));
if(ogrenci == NULL) { exit(1); }
for(i=0;i<studentnum;i++)
{
printf("Enter the student's name, surname, midterm and final respectively: \n");
scanf("%s %s %d %d",(ogrenci+i)->name, (ogrenci+i)->surname, &(ogrenci+i)->midterm, &(ogrenci+i)->final);
if((ogrenci+i)->midterm > 100 || (ogrenci+i)->midterm < 0 || (ogrenci+i)->final > 100 || (ogrenci+i)->final < 0)
{
printf("midterm or final can not be higher than 100 or lower than 0 \n");
exit(1);
}
}
}
void yazma (int studentnum){
int i;
STUDENT_MARK *ogrenci;
FILE *dosya;
dosya = fopen("marks_190704033.txt","w");
if{ (dosya == NULL)
{
printf("Could not open file");
exit(1);
}
else
{
for(i=0;i<studentnum;i++)
{
fprintf(dosya, "%s %s %d %d", (ogrenci+0)->name, (ogrenci+0)-
>surname, (ogrenci+0)->midterm, (ogrenci+0)->final);
}
}
fclose(dosya);
}
int main()
{
int n =2;
girme(n);
yazma(n);
return 0;
}
STUDENT_MARK *ogrenci;
ogrenci = (STUDENT_MARK*) malloc(studentnum * sizeof(STUDENT_MARK));
ogrenci is a single pointer to the structure STUDENT_MARK to space allocated for several objects of struct STUDENT_MARK.
When using, f.e.:
(ogrenci+i)->name
in the for loop, you attempt to access not existing struct pointers to not existing structure objects.
Note: The compiler do not associate the allocated space with several pointers!
If you want to use pointer arithmetics like (ogrenci + i) you need to either define ogrenci as an array of pointers to STUDENT_MARK:
int studentnum = 5;
STUDENT_MARK *ogrenci[studentnum];
and initialize each pointer by the address of an existing structure object for which were each allocated space individually, f.e. like:
int studentnum = 5;
STUDENT_MARK *ogrenci[studentnum];
for(int i = 0; i < studentnum; i++)
{
ogrenci[i] = malloc(sizeof(*ogrenci));
}
or you define ogrenci as a pointer to pointer to STUDENT_MARK:
int studentnum = 5;
STUDENT_MARK **ogrenci;
ogrenci = malloc(sizeof(*ogrenci) * studentnum);
*ogrenci = malloc(sizeof(**ogrenci) * studentnum);
"When writing like this (ogrenci+0) it works correctly."
However, It "works" with 0 because ogrenci + 0 = ogrenci. There is no difference to ogrenci.
Side note: As you mabe have already seen, I omitted the cast of the returned pointer from malloc. This is because it is unnecessary and it might "add clutter" to your code: Do I cast the result of malloc
In my code I have 2 structs named villa and apartment. They have members of type char*. When in my void record I get other parts of the structs like villa1.price (which is float) from user,It works ,but when it comes to the char*,I cannot read strings using scanf("%s",&villa1.city) and so I used another array of chars named v1 to get info from users and then assign it to villa1.city using villa1.city=a1.
This worked for the first time, but I want to make a linked list. The first time I send villa1.city to insertFirstVilla to add this to linked list it works, but when I add second node ,the villa1.city in first node is lost and it keeps happening every time I add a new node.
How can I get data from user like villa1.price or if it is not possible how to copy it in way that data remains safe when I add second node to my list.
I post a part of my code for villa, but the code is the same for apartment.
struct villa
{
float built;
float garden;
float price;
int floors;
char* city;
char* ST;
char* alley;
char* postal_code;
}villa1;
struct nodev
{
villa info;
nodev* next;
}*headv = NULL;
void insertFirstvilla(float built, float garden,float price,int floor, char*city) {
nodev* link = (nodev*)malloc(sizeof(nodev));
link->info.built = built;
link->info.garden = garden;
link->info.price = price;
link->info.floors = floor;
link->info.city = city;
link->next = headv;
headv = link;
}
void record()
{
char a;
printf("is the building apartment? (y/n):");
scanf("%c", &a);
char a1[100];
char v1[100];
if (a == 'y')
{
/* printf("enter apartment features:");
printf("\nenter built area:");
scanf("%f", &apart.built);
printf("\nenter basic price:");
scanf("%f", &apart.price);
printf("\nenter floors number:");
scanf("%d", &apart.floor_no);
printf("\ndoes apartment have elavator(if there is no elavotor enter zero else enter one):");
scanf("%d", &apart.elevator);
printf("\nenter city:");
scanf("%s", &a1);
apart.city = a1;
insertFirstapartment(apart.built, apart.price, apart.floor_no, apart.elevator,apart.city);
writetofilea(apart.built, apart.price, apart.floor_no, apart.elevator, apart.city);*/
}
else if (a == 'n')
{
printf("enter villa features:");
printf("\nenter built area:");
scanf("%f", &villa1.built);
printf("\nenter garden area:");
scanf("%f", &villa1.garden);
printf("\nenter basic price:");
scanf("%f", &villa1.price);
printf("\nenter floors number:");
scanf("%d", &villa1.floors);
printf("\nenter city:");
scanf("%s", &v1);
apart.city = v1;
insertFirstvilla(villa1.built, villa1.garden, villa1.price, villa1.floors, villa1.city);
writetofilev(villa1.built, villa1.garden, villa1.price, villa1.floors, villa1.city);
}
getchar();
}
int main()
{
int t = 0;
while (t<4)
{
record();
t++;
}
}
As an example reading the city:
char a1[100];
scanf("%99s", a1); // an array will be passed as an address, so no need for &
apart.city = malloc(strlen(a1)+1); // ask for memory
strcpy(apart.city, a1); // copy it
or use strdup, which does this for you:
char a1[100];
scanf("%99s", a1); // an array will be passed as an address, so no need for &
apart.city= strdup(a1); // get memory and copy it
The basic problem is deep copying versus shallow copying.
struct villa
{
int floors;
char* city;
};
villa V1, V2;
char buffer[10];
strcpy(buffer, "Venice");
V1.city = buffer; /* This copies nothing. V1.city now points to buffer. */
V2 = V1; /* This is a shallow copy. V2.city now points to buffer. */
strcpy(buffer, "Moscow");
printf("%s\n", V2.city); /* prints Moscow */
Do you see the problem? If you want each villa to have a buffer of its own, you must write code to allocate and manage that memory, and if you want the copies to be deep copies, you must write an assignment operator.
so as the question says I get a segmentation fault every time I try to enter in a name for the customer. This program does compile and works until it gets to the customer name part. I'm not sure if the problem is with malloc. Could anyone show me what I am doing wrong? I've been trying to figure this out for awhile now with no luck. Thanks
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define END_OF_STRINGS '\0'
#define NEWLINE '\n'
#define MAX_CUSTOMERS 100
#define MIN_CUSTOMERS 2
#define MAX_NAME_LENGTH 20
#define DB_ALLOC_ERR 1
#define QUIT 0
struct customer
{
char *p_last_name[MAX_NAME_LENGTH + 1];
float amount_owed;
int priority;
};
void print_instructions();
int number_of_customers();
void get_accounts(struct customer *p_customer_start, int
customer_amount);
void clean_names(struct customer *p_customer_start, int
customer_amount);
void sort_names(struct customer *p_customer_start, int
customer_amount);
void print_results(struct customer *p_customer_start, int
customer_amount);
int main()
{
struct customer *p_customer;
int customer_amount;
while (print_instructions(), (customer_amount =
number_of_customers()) != QUIT)
{
if ((p_customer = (struct customer *)malloc(sizeof(*p_customer) *
MAX_NAME_LENGTH)) == NULL)
{
printf("\nError #%d occurred in main()", DB_ALLOC_ERR);
printf("\nCannot allocate memory for database of customer ");
printf("\naccountable records");
printf("\nThe program is aborting");
exit (DB_ALLOC_ERR);
}
get_accounts (p_customer, customer_amount);
clean_names (p_customer, customer_amount);
sort_names (p_customer, customer_amount);
print_results(p_customer, customer_amount);
printf("%c", NEWLINE);
free(p_customer);
}
return 0;
}
void print_instructions()
{
printf("\n\nThis program allows you to input customers which owe");
printf("\nyou money (your accounts receivable), and manage these");
printf("\naccounts in a database. You will enter the following:");
printf("\n Customer last name (1-20 characters)");
printf("\n Amount the customer owes (to the exact cent)");
printf("\n Customer priority (1=VIP, 2=Important, 3=Regular)");
printf("\nFrom 2 to 100 customers may be processed.");
return;
}
int number_of_customers()
{
int user_choice;
printf("\n\nGet the customers for the database");
printf("\n--------------------------------------------------");
do
{
printf("\nHow many customers do you have (%d to %d, %d=quit): ", MIN_CUSTOMERS, MAX_CUSTOMERS, QUIT);
scanf ("%d", &user_choice);
} while ((user_choice < MIN_CUSTOMERS ||
user_choice > MAX_CUSTOMERS) && user_choice != QUIT);
return user_choice;
}
void get_accounts(struct customer *p_customer_start, int
customer_amount)
{
struct customer *p_customer;
for (p_customer = p_customer_start; (p_customer - p_customer_start)
< customer_amount; p_customer++)
{
printf("\nCustomer number %d", (int)(p_customer -
p_customer_start + 1));
printf("\n Enter the customer's last name: ");
scanf ("%20s", p_customer->p_last_name[MAX_NAME_LENGTH + 1]);
getchar();
do
{
*p_customer->p_last_name[MAX_NAME_LENGTH] = getchar();
p_customer->p_last_name[MAX_NAME_LENGTH]++;
} while (!NEWLINE);
p_customer->p_last_name[MAX_NAME_LENGTH + 1] = END_OF_STRINGS;
printf("\n Enter the amount owed: ");
scanf ("%f", &p_customer->amount_owed);
do
{
printf("\n Enter the customer's priority (1-3): ");
scanf ("%d", &p_customer->priority);
} while (p_customer->priority < 1 || p_customer->priority > 3);
}
return;
}
void clean_names(struct customer *p_customer_start, int
customer_amount)
{
char *p_fast = p_customer_start->p_last_name[MAX_NAME_LENGTH],
*p_slow = p_customer_start->p_last_name[MAX_NAME_LENGTH];
if (tolower(*p_fast))
*p_slow++ = toupper(*p_fast);
while (*p_fast != END_OF_STRINGS)
{
if (!isspace(*p_fast) || isalpha(*p_fast))
*p_slow++ = tolower(*p_fast);
p_fast++;
}
*p_slow = END_OF_STRINGS;
return;
}
void sort_names(struct customer *p_customer_start, int
customer_amount)
{
char *p_inner[MAX_NAME_LENGTH],
*p_outer[MAX_NAME_LENGTH],
temp[MAX_NAME_LENGTH];
for (p_outer[MAX_NAME_LENGTH] = p_customer_start ->
p_last_name[MAX_NAME_LENGTH]; (p_outer - p_customer_start ->
p_last_name)
< customer_amount; p_outer[MAX_NAME_LENGTH]++)
{
for (p_inner[MAX_NAME_LENGTH] = p_outer[MAX_NAME_LENGTH + 1];
(p_inner - p_customer_start ->
p_last_name) < customer_amount; p_inner[MAX_NAME_LENGTH]++)
{
if (strcmp(p_outer[MAX_NAME_LENGTH],
p_inner[MAX_NAME_LENGTH]))
{
temp[MAX_NAME_LENGTH] = *p_outer[MAX_NAME_LENGTH];
*p_outer[MAX_NAME_LENGTH] = *p_inner[MAX_NAME_LENGTH];
*p_inner[MAX_NAME_LENGTH] = temp[MAX_NAME_LENGTH];
}
}
}
return;
}
void print_results(struct customer *p_customer_start, int
customer_amount)
{
char last_name[MAX_NAME_LENGTH];
float amount_owed = p_customer_start->amount_owed;
printf("\n Here is the accounts receivable customer database");
printf("\n=====================================================");
printf("\n Customer Name Amount Priority");
printf("\n-------------------- --------- -------------");
printf("\n %s $ %.2f ", last_name,
amount_owed);
switch (p_customer_start->priority)
{
case 1:
printf("1 (VIP)");
break;
case 2:
printf("2 (Important)");
break;
case 3:
printf("3 (Regular)");
break;
}
printf("\n\n******* End Of Customer Database Processing *******");
return;
}
i believe a start of your problem is here:
struct customer
{
char *p_last_name[MAX_NAME_LENGTH + 1];
float amount_owed;
int priority;
};
with that code you create 21 pointers to char.
What you want is character pointer to space that will hold MAX_NAME_LENGTH + 1 characters
Therefore you would want something simply like:
struct customer
{
char last_name[MAX_NAME_LENGTH + 1];
float amount_owed;
int priority;
};
I also changed p_last_name to just last_name so to the eyes it reads more logically, but you may call it whatever you like, but to say p_last_name is to imply it's a pointer which is not needed, and it reads poorly
When declaring or defining variables, you read from right to left,
it would then be an array because of [] which is 21 big, called last name and it's an array of the char data type.
Now the thing with C is that arrays and pointers have something in common, or can often be confused... because they are technically the same thing. Any array that you define, which in turn allocates space in memory, is nothing more than a pointer to the beginning of the array, that's it!
when you do something like last_name[7] then the 7 is how many jumps from the beginning of the array, which is always known as last_name in your case. The size of the jump is solely dependent upon the data type of the array when it was defined. In your case it is char which is 1 byte, so a jump of last_name[7] would be 7 bytes away from where last_name points to.
For example if the contents in memory where `last_name` points to is abcdefghijklmnopqrst
then char last_name[MAX_NAME_LENGTH + 1]; would define a variable called last_name which is technically a character pointer to contiguous chunk of memory that is MAX_NAME_LENGTH + 1 bytes because of data type char and it is a pointer to the beginning of that chunk of memory.
*last_name is the same as last_name[0] which deferences the character pointer last_name such that it returns the contents of memory which is a
*(last_name+2) is the same as last_name[2] which is c
Also, in
int main()
{
struct customer *p_customer;
int customer_amount;
this statement struct customer *p_customer; creates one pointer called p_customer that is a pointer which will point to some chunk of memory (hasn't happened yet) that is of the data type struct customer which is defined above. Ok to there. Then at
if ((p_customer = (struct customer *)malloc(sizeof(*p_customer) *
MAX_NAME_LENGTH)) == NULL)
where you use malloc to reserve some chunk of memory for what you are doing, you are really doing sizeof( a pointer )
what you should be doing is (struct customer *) malloc( sizeof( struct customer )) in addition to correctly defining a 21 byte array of characters called last_name in struct customer.
It should read out in English logically, oftentimes from right to left, if it does not then suspect a problem. Also when compiling learn to use -W it can be your friend and alert you to problems like this.
your original code is likely not allocating or reserving a large enough chunk of memory for the number of characters you type in to store in p_last_name.
The part that is bothering me is the last for loop which I used just to test whether the data is entered correctly and that it is printed using printf properly. The three access methods used to print the data which I entered aren't quite clear to me.
In access method #1 I managed to print data properly using only one arrow operator to access name. The part I can't wrap my head around is why am I able to access the data without an error? I only used index to access each production_plant_employees structure. I know the brackets do the dereferencing, but I still don't understand what's happening there. I tried writing that part like this : *(production_plant_employees + i), but it didn't work.
Access method #2 is fully clear to me.
Now the access method #3, that's the one I assumed would work, but it refuses to. When written, IDE shows no errors, but when I run the program, it stops.
I am supposed to first access data in first pointer (which is production_plant_employees), and then then access data in second pointer (which is pointer basic_info which is in struct employee), and then, when I've gone through the 2 pointers, access the very data I am after (name, age, etc...), right?
Also, could you please show me any other possible ways of accessing the data I'm after?
typedef struct basicdata{
char name[15];
char last_name[15];
char gender[2];
int age;
char birthplace[15];
char address[15];
} BASICDATA;
typedef struct job_info {
int employment_year;
char job_position[20];
char employee_pay_grade[10];
int employee_grade;
} JOB_INFO;
typedef struct employee{
BASICDATA *basic_info;
JOB_INFO *job_info;
} EMPLOYEE;
int main () {
int i;
int choice = 0;
EMPLOYEE *production_plant_employees;
printf("Enter number of employees : \n");
scanf("%d", &choice);
production_plant_employees = (EMPLOYEE*)calloc(choice, sizeof(EMPLOYEE));
if (production_plant_employees == NULL) {
printf("An error occured during memory allocation\n");
}
for(i = 0; i < choice; ++i) {
production_plant_employees[i].basic_info = (BASICDATA*)calloc(choice, sizeof(BASICDATA));
if(production_plant_employees[i].basic_info == NULL) {
printf("An error occured during memory allocation\n");
}
production_plant_employees[i].job_info = (JOB_INFO*)calloc(choice, sizeof(JOB_INFO));
if(production_plant_employees[i].job_info == NULL) {
printf("An error occured during memory allocation\n");
}
printf("production_plant_employees[%d].basic_info = %d\t%x\n", i, production_plant_employees[i].basic_info, production_plant_employees[i].basic_info);
printf("production_plant_employees[%d].job_info = %d\t%x\n", i, production_plant_employees[i].job_info, production_plant_employees[i].job_info);
}
for(i = 0; i < choice; ++i) {
fflush(stdin);
printf("Enter name : \n");
fgets(production_plant_employees[i].basic_info->name, 15, stdin);
printf("Name of %d. employee : %s", i, production_plant_employees[i].basic_info->name) //access method#1
printf("Name of %d. employee : %s", i, (production_plant_employees + i)->basic_info->name); //access method #2
printf("Name of %d. employee : %s", i, *(*(production_plant_employees +i)).basic_info->name); //access method #3 ---> why isn't this working?
printf("\n\n");
}
return 0;
}
The right way to do it is (for access method 3):
printf("Name of %d. employee : %s", i, (*(*(production_plant_employees +i)).basic_info).name);
First we start by dereferencing pointer production_plant_employees +i, now, we access member basic_info which is also a pointer & needs to get dereferenced using the second * to access local member name.
ptr1 = production_plant_employees +i
ptr2 = (*ptr1).basic_info
data = (*ptr2).name
And thus (substituting ptr2 in data:
data = (*(*ptr1).basic_info).name
& finally by substituting ptr1 :
data = (*(*(production_plant_employees +i)).basic_info).name