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;
}
}
Related
I am new to C and I have been stuck on this code for the whole moring.
It compiles without a problem, but fails when executed.
If you have any idea that would help me solve this, please leave me a comment. Any comment would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct phonebook {
char name[20];
char phoneNum[20];
} Phonebook;
int bookSize=1;
void load(Phonebook **book);
void insert(Phonebook **book);
void delete(Phonebook **book);
void search(Phonebook *book);
void print(Phonebook *book);
void save(Phonebook *book);
int main(void) {
Phonebook *book = (Phonebook *)calloc(sizeof(Phonebook), bookSize);
load(&book);
int menuInput=0;
while(menuInput != 5) {
puts("***** MENU *****");
puts("1. Insert");
puts("2. Delete");
puts("3. Search");
puts("4. Print All");
puts("5. Exit");
printf(">> ");
scanf("%d", &menuInput);
switch(menuInput) {
case 1 : insert(&book); break;
case 2 : delete(&book); break;
case 3 : search(book); break;
case 4 : print(book); break;
case 5 : break;
default : puts("enter correct command"); break;
}
}
save(book);
free(book);
puts("\nexit\n");
return 0;
}
void load(Phonebook **book) {
FILE *fp = fopen("phonebook.txt", "rt");
if(fp == NULL) {
FILE *fp = fopen("phonebook.txt", "wt");
fclose(fp);
puts("Welcome! It looks like you don't have an existing phonebook.");
puts("A new phonebook has been created.\n");
return;
}
else {
char temp[20];
int i=0;
while(fscanf(fp, "%s", temp) != EOF) {
strcpy(book[i]->name, temp);
fscanf(fp, "%s", temp);
strcpy(book[i]->phoneNum, temp);
i++;
bookSize++;
*book = (Phonebook *)realloc(*book, sizeof(Phonebook) * (bookSize));
}
fclose(fp);
printf("Loaded %d contacts\n", bookSize-1);
}
}
void insert(Phonebook **book) {
puts("\nCreate a new contact");
getchar();
char temp[20];
printf("Name : ");
fgets(temp, 20, stdin);
//temp[strlen(temp)-1]=0;
strcpy(book[bookSize-1]->name, temp);
//fgets(book[bookSize-2]->name, 20, stdin);
//book[bookSize-2]->name[strlen(book[bookSize-2]->name)-1]=0;
printf("Phone : ");
fgets(temp, 20, stdin);
//temp[strlen(temp)-1]=0;
strcpy(book[bookSize-1]->phoneNum, temp);
//fgets(book[bookSize-2]->phoneNum, 20, stdin);
//book[bookSize-2]->phoneNum[strlen(book[bookSize-2]->phoneNum)-1]=0;
puts("Done!\n");
bookSize++;
*book = (Phonebook *)realloc(*book, sizeof(Phonebook) * bookSize);
}
void delete(Phonebook **book) {}
void search(Phonebook *book) {}
void print(Phonebook *book) {
if(bookSize == 1) {
puts("\nempty\n");
return;
}
puts("");
for(int i=0; i<bookSize-1; i++) {
printf("Name : %-10s Phone : %s\n", book[i].name, book[i].phoneNum);
}
puts("");
}
void save(Phonebook *book) {
FILE *fp = fopen("phonebook.txt", "wt");
for(int i=0; i<bookSize-1; i++) {
fprintf(fp, "%s\n%s\n", book[i].name, book[i].phoneNum);
}
fclose(fp);
printf("\nSaved %d contacts", bookSize-1);
}
Segmentation fault (core dumped)
** sorry for removing parts of the code I thought was 'irrelevant'! I have added the whole code to the post. Thanks!
As your other answer indicates, you are tripping over the details of the double indirection.
You are maintaining your phone book as an array of structures. In main, variable book is a pointer to the first structure in that array. The second will immediately follow it in memory, and the third will immediately follow that, etc.. That's all perfectly fine.
Both insert() and load() accept as a parameter a pointer to the pointer to the first book. This also is right and proper, because these methods reallocate the memory for the array. Reallocation is not necessarily done in place -- the new space may be in a different location than the old. The original pointer passed into realloc must be considered invalid after the call, and the return value used in its place (supposing the call succeeds). You handle this correctly, too, updating main's pointer through the pointer argument:
*book = (Phonebook *)realloc(*book, sizeof(Phonebook) * (bookSize));
But your attempts to write phone book entries into the allocated space is incorrect. For example, in load(), this:
strcpy(book[i]->name, temp);
tries to access the ith Phonebook * in the array of pointers to which book points, and to write to the name member of the Phonebook to which it points. But there is only ever one Phonebook *, not an array of them. You are allocating and reallocating space for the Phonebooks to which it points.
Here's a crude diagram:
Actual layout:
[Phonebook **] ----> [Phonebook *] ----> [ Phonebook, Phonebook, Phonebook ... ]
Being accessed as if it were:
[Phonebook **] ----> [Phonebook *, Phonebook *, Phonebook *, ...]
| | |
V | |
[Phonebook] V |
[Phonebook] V
[Phonebook]
Solution:
Just as you assign the allocated pointer to *book, not to book, it is *book to which you should be applying the indexing operator:
strcpy((*book)[i].name, temp);
And since it's an array of Phonebooks, not an array of pointers to them, you use the direct member access operator (.), as shown, not the indirect access operator.
Beware, however, that you use the same name, book, in different functions to designate pointers with different degrees of indirection. Thus, whereas the above would be correct in load() and insert(), it would be wrong in main() and some of the other functions.
tl;dr: insert(&book) should just be insert(book), and define this to be the address you get from allocating memory in the heap for storing the address you get from calloc.
You define your argument for insert() as **book, and when you get a *book from your calloc() call, you reasonably "add on another *" with the address operator &. The catch is that the address of *book that you got from your calloc call is a location on the call stack of your main() function. So, when the argument of strcpy() goes to dereference this address with the array index notation, it attempts to get the value located at the pointer that's on your call stack + bookSize - 1. This is already in undefined behavior territory, since the stack isn't supposed to store memory dynamically, but you're getting the segfault because the stack is at the top of the memory layout (high address area), so adding a large enough value to the dereferenced value of book puts you in an illegal memory access zone.
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
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.
I am running Xcode 4.4.1 for this program.
Object:
Insert user-input string into queue by calling enqueue and take out inserted string by calling dequeue.
Test input:
aaa
What's not working:
On the line where I call dequeue(queue, &name), I am expecting to get the dequeued value of aaa. However, I get a garbage or NULL value.
// prototype declarations
int enqueue ( QUEUE *queue, void * dataInPtr ); // returns success
int dequeue ( QUEUE *queue, void **dataOutPtr ); // returns success
bool processQueue(QUEUE *queue, bool flag);
// function definitions (only processQueue is shown)
bool processQueue(QUEUE *queue, bool flag) {
char *name;
char usInput[MAX_LENGTH_INPUT + 1];
int success;
if(ENQUEUE == flag) {
do {
printf("Enter 3 letters for name: ");
fscanf(stdin, "%s", usInput);
} while(!validateInputName(usInput));
name = malloc(sizeof *name * 4);
name = usInput;
printf("usInput==\"%s\" and name==\"%s\"\n", usInput); // correctly shown
return enqueue(queue, name);
} else { // DEQUEUE == flag
if (!emptyQueue(queue)) {
dequeue(queue, &name); // I assume I have problem here??
printf("dequeued name == \"%s\"\n", name); // incorrectly shown. why???
// TODO: free(name);
return true;
} else {
return false;
}
}
}
// output:
usInput=="aaa" and name=="aaa"
dequeued name == "¿" // here, I am expecting aaa, not ¿
Any help is appreciated! Thanks!
I'm guessing this is the problem:
name = malloc(sizeof *name * 4);
name = usInput;
By resetting name to point to the temporary usInput, you're (a) leaking memory and (b) causing undefined behavior.
The error is because when probably enqueue() takes a pointer to a string and stores it in the queue. In the statement:
name = usInput;
you replace the pointer you pass to enqueue() with a pointer to the start of an automatic storage array; that is storage that is not valid after your function terminates, which is why you see garbage. Storing/using pointers to memory that has been deallocated invokes undefined behaviour.
You seem to be confused about dynamic memory allocation and string copying. Here's one way you can handle it:
/* First, allocate enough memory. Let's say 12 bytes is enough. */
name = malloc(12);
/* We'll need to copy our string to the memory we allocated and truncate it to 12 bytes */
if (snprintf(name, 12, "%s", usInput) < 0) {
printf("Output error encountered by snprintf\n");
return -1; /* error value */
}
/* Now enqueue NAME assuming that enqueue() does not copy it. */
return enqueue(queue, name);
Be careful to:
Always check for errors.
Always impose a maximum input size.
Do not leak memory - free() what you malloc().
The following code is shorten form, I have two structurs named struct INTERFACE and struct node.
For my purpose I have 2 nodes and first node have two interfaces and second node have three interfaces.
I have one config file from wher I need to read the information and store it in the above structures.
So in my main program while loop , I read the config file using strtok() fun, and store respectively.
In the if loop (if(strcmp((p,"IP_ADDR_ETH")==0), I compared the IP address token and retrive the ip address and store in the interfaces of each node. Why i am using switch case because if NODE-1 means first node, NODE-2 means second node.
Here I shown only for first node.
In the if loop I retrive the IP address of first node and store it in node structure's interface value.
by,
(node1[i].node_if[a].ip_addr)= p;
//strcpy((node1[i].node_if[a].ip_addr),p);
printf("Node[%d] interface-eth[%d] address=%s \n\n", i,a,(node1[i].node_if[a].ip_addr) );
Inside the while loop, for each node ,I can access the interface structure and get ipaddr value properly.
But out side the while loop, if I am printing the each nodes interface values, I am getting only the second node last interface value, I am not able to get each nodes interface ipaddress properly.
My part of the main code is as follows, sorry if the code length is more again, but I gave only nessary portion only,
/* Node information structure. */
typedef struct node {
char name[20];
char val[20];
char OS[10];
int vm_id;
int num_if;
//char *OS;
if_val1 node_if[10];
long int memsize;
}node1;
/* Interfaces definition structure. */
typedef struct INTERFACE {
char *ip_addr;
char *netmask;
char *gateway;
} if_val1,if_val2;
I have the above two structure.
/* File pointer .*/
FILE *f;
int main()
{
node1 nodeuse;
node1 node1[20];
//if_val1 if_val[10];
if_val1 zero_ifintf;
//int a;
f=fopen("test.config","r");
if(!f)
return 1;
while(fgets( string, sizeof(string)-1, f) != NULL)
{
/* Break into tokens. */
p = string;
p = strtok( string, seps ); /* Find first token*/
while( p != NULL )
{
if (strcmp(p,"NODE")==0)
{
a = atoi (strtok( NULL, seps )); /* Find next token*/
switch (a)
{
case 1:
{
int i=0;
if(strcmp(p,"IP_ADDR_ETH")==0)
{
printf("--------------hi1 \n");
int comp,a;
printf("------------hi2 \n");
a = atoi (strtok( NULL, seps )); /* Find next token*/
if(a < (node1[i].num_if))
{
printf("-------------hi3 \n");
p = strtok( NULL, seps ); /* Find next token*/
(node1[i].node_if[a].ip_addr)= p;
//strcpy((node1[i].node_if[a].ip_addr),p);
printf("Node[%d] interface-eth[%d] address=%s \n\n", i,a,(node1[i].node_if[a].ip_addr) );
}
printf("---------------------hi4 \n");
}
i++;
}
}} //end of while loop
//outside while loop printf 's
printf("NODE[%d] INTERFACE-ETH-[%d] ADDRESS: %s \n",1,0,(node1[0].node_if[0].ip_addr));
printf("NODE[%d] INTERFACE-ETH-[%d] ADDRESS: %s \n",1,1,(node1[0].node_if[1].ip_addr));
printf("NODE[%d] INTERFACE-ETH-[%d] ADDRESS: %s \n",2,0,(node1[1].node_if[0].ip_addr));
printf("NODE[%d] INTERFACE-ETH-[%d] ADDRESS: %s \n",2,1,(node1[1].node_if[1].ip_addr));
printf("NODE[%d] INTERFACE-ETH-[%d] ADDRESS: %s \n",2,2,(node1[1].node_if[2].ip_addr));
why the structure values not printed as expected.
also, I am trying to assign tokenized string value to other string using strcpy() function. But when compile segmentation fault came. Is it possible to declare char *string and assing value using strcpy()?.
my config file as follows,
[test.config]
TYPE VM vm1
TYPE PM pm1
NODES 2
APS 2
TYPE wired
NODE-1 NUM_IF 2
NODE-1 IP_ADDR_ETH-0 10.114.12.1
NODE-1 IP_ADDR_ETH-1 10.114.12.2
NODE-1 VM_ID 1
NODE-1 MEM_SIZE 512
NODE-1 OS FEDORA
NODE-2 NUM_IF 3
NODE-2 IP_ADDR_ETH-0 10.114.14.1
NODE-2 IP_ADDR_ETH-1 10.114.14.2
NODE-2 IP_ADDR_ETH-2 10.114.14.3
NODE-2 VM_ID 2
NODE-2 MEM_SIZE 1GB
NODE-2 OS CENTOS
NODE-2 10.114.12.7
[/test.config]
Thank you,
Arun
strcmp(p,"IP_ADDR_ETH")
will never match because at this time p points to "NODE". Once you fixed that, it should work.