I have a problem writing a code that should read usernames and put them in list. Every username should be connected to the number of times it has been entered. The problem occurs when entering the second username, my code places that username in the variable called first (where the first is kept). I guess I've done something wrong with the pointers, but I cannot find what. I am confused, in the end of one while loop the first one is the real first one, and when the program enters while again, variable first changes. How could that be? Please help me.
Thank you :)
typedef struct _user
{
char *name;
int counter;
struct _user *next;
} user;
int main() {
char userName [10];
int found = 0, go_on = 1;
user *first = NULL, *temp, *new;
while (go_on == 1) {
printf ("Username: ");
scanf("%s", userName);
if (first) {
// printf ("The first one in list: %s\n", first->name); - this prints the name of last username entered
for (temp = first; temp; temp = temp->next) {
if (strcmp (temp->name, userName) == 0) {
temp->counter++;
found = 1; }
if (found== 1) break;}
if (!found) {
new = (user*) malloc (sizeof(user));
new->name = userName;
new->counter = 1;
temp = new;
temp->next = NULL; } }
else {
new = (user*) malloc (sizeof(user));
new->name = userName;
new->counter = 1;
first = new;
first->next = NULL; }
printf ("Go on? (1/0)");
scanf("%d", &go_on);
printf ("Current list: ");
for (temp=first; temp; temp = temp->next)
printf("%s %d\n", temp->name, temp->counter);
//printf ("The first one in list: %s\n", first->name); - this prints the correct first
}
}
Your error, I think, is the userName array. You should allocate a new one for each element in your linked list. When you write new->name = userName;, you are not copying the name to the struct, you are making the struct point to your userName[10] array. As such every struct's actual "name" is storing only the single last name scanf-ed. That being said...
I generally prefer to write that kind of code with dedicated tools instead of logically embedding them in a loop construct:
Keeping your struct:
typedef struct _user
{
char *name;
int counter;
struct _user *next;
} user;
I would create a function that, given a properly constructed Sll returns a matching element:
function user *user_match_name(user *user_head, const ch *name)
{
user *cur_user = NULL;
/* look for a match */
for (cur_user = user_head ; cur_user ; cur_user = cur_user->next)
if(!strcmp(name,cur_user->name) return cur_user;
/* no match */
return NULL;
}
Then I usually prefer to have an Sll element builder:
function user *create_user(const ch *name)
{
user *new_user;
if(!(new_user = malloc(sizeof(user))))
printf("Error in allocation"); /* or better malloc error handling */
/* IMPORTANT: PROVIDE MEMORY FOR THE NAMES!!! */
if(!(new_user->name = malloc(sizeof(char)*256))) /* sizeof(char) is useless but I like to explicit it like that. And 256 should be enough a buffer could be better made */
printf("Error in allocation"); /* or better malloc error handling */
strncpy(new_user->name, name,256); /* not sure if I got the argument order right... */
new_user->counter = 0; /* or 1 depending on your prefered convention */
new_user->next = NULL;
return new_user;
}
It ease the debugging like you wouldn't believe! Then it's just a matter of rewriting your main function:
int main() {
char userName [10];
int found = 0, go_on = 1;
user *user_head = NULL, *new_user,*temp;
while (go_on == 1) {
printf ("Username: ");
scanf("%s", userName);
if( (new_user = user_match_name(user_head,userName)) )
++new_user->counter
else
new_user = create_user(userName);
/* Here we push on the Sll */
if(user_head){
new_user->next = user_head;
user_head = new_user;
} else {
user_head = new_user;
}
printf ("Go on? (1/0)");
scanf("%d", &go_on);
printf ("Current list: ");
for (temp = user_head; temp; temp = temp->next)
printf("%s %d\n", temp->name, temp->counter);
//printf ("The first one in list: %s\n", first->name); - this prints the correct first
}
}
Ahhhhhh! Much easier to read. Be mindful of: 1) I didn't compile check the code. The important ideas are there, leverage them. 2) Even in your previous implementation, you are white space vulnerable but that's somewhat another topic.
Or you could cimply fix it by doing:
typedef struct _user
{
char name[10];
int counter;
struct _user *next;
} user;
and strncpy(new->name,userName,10) instead of assigning the pointer.
Related
My first problem is that I have problem to make that for loop and implement it into the code and somehow finish my program.
My second problem is compiler showing problem in this: memset(database,0,SIZE*sizeof(struct student)); type specifier missing, defaults to 'int'
And at the end of program i have problem with memcpy(database.name,name,size_of_name); member reference base type 'struct student [100]' is not a structure or union
There are my structure and functions:
#define SIZE 100
struct student {
char name[SIZE];
int votes;
};
struct student database[SIZE];
memset(database,0,SIZE*sizeof(struct student));
int size = 0;
int find_student(struct student* students,int size, const char* name){
// for loop,which take all entries in database
// if it find same name, then reutrn his index
//otherwise reuturn -1;
int i;
for(i=0; i<SIZE;i++){
// how to make that loop
}
return -1;
}
int compare(const void* p1, const void* p2){
struct student* s1 = (struct student*)p1;
struct student* s2 = (struct student*)p2;
// s1->votes
// s1->name
return 0;
}
And there is my code what I already did( sorry for my grammar):
char line[SIZE];
memset(line,0,SIZE);
char* r = fgets(line,SIZE,stdin);
if (r == NULL){
printf("End of input");
return (-1);
}
char* end = NULL;
int value = strtol(line,&end,10);
if (value == 0){
printf("Convertion was not sucessful");
return (-1);
}
// helping array
char name[SIZE];
// set on zero
memset(name,0,SIZE);
// get begining of a name = one position after space
char* beginning_name = end + 1;
// Size of name is number of signs to end of string
// minus end of line
int size_of_name = strlen(beginning_name) - 1;
if (size_of_name > 0){
// copy
memcpy(name,beginning_name,size_of_name);
// At the end is saved string with name
// without end of line and with zero at the end
}
else {
// failed to read a name
printf("Failed to read a name");
return (-1);
}
int id = find_student(database,size,name);
if (id< 0){
// copy it to last place in array
memcpy(database.name,name,size_of_name);
// increase number of entries
size+=1;
}
else {
// there I need add to votes,something like votes++;
}
}
Sorry for formating but I am new at stackoverflow.
with following code I can store one string only.
Main problem is how to store several. If i want to enter another string after the first one it wont do it.
I didnt write it in code but when I type("KRAJ") it should get out of while loop.
typedef struct{
char Objekat[20+1];
char Mjesto[20+1];
char velicina [20];
int cijena;
char kn[3];
char stanje[20];
}Apartmani;
int main()
{
Apartmani *apartmani=(Apartmani*)malloc(sizeof(Apartmani)*50);
while(scanf("%[^,\n],%[^,],%[^,],%d%[^,],%[^\n]", &apartmani[i].Objekat,&apartmani[i].Mjesto,&apartmani[i].velicina,
&apartmani[i].cijena,&apartmani[i].kn, &apartmani[i].stanje )==6)
{
i++;
}
for(p=0;p<i;p++)
{
printf("%s %s %s %d %s %s",apartmani[p].Objekat,apartmani[p].Mjesto,apartmani[p].velicina,apartmani[p].cijena,
apartmani[p].kn, apartmani[p].stanje);
}
}
For example:
string 1: Apartman, Novalja, 100.00 m2, 750000kn, dobro ocuvano.
string 2: Kuca, Ivanbregovia, 20m2, Imtoski, 21252RH, vrijednost-neprocjenjiva.
You should use fgets() plus sscanf().
You should not cast malloc[Do I cast the result of malloc?][1]. Remember to check the return value of malloc, since it can be failed.
change the line of allocating apartmani to:
Apartmani *apartmani= malloc(sizeof(Apartmani)*50);
if(!apartmani) {return -1;}
Do not use & for the input of string.
Check the value of i because its value is limited to 50.
Your code is missing the declaration of i (should be: int i = 0), and the declaration of p also.
Your while loop can be as below:
int i = 0;
char line[100];
while(i < 50 && fgets(line,sizeof(line),stdin))
{
line[strcspn (line, "\n" )] = '\0'; // trip the enter character at the end of line.
int err = sscanf(line,"%20[^,],%20[^,],%19[^,],%d,%2[^,],%19[^\n]", apartmani[i].Objekat,apartmani[i].Mjesto,apartmani[i].velicina,&apartmani[i].cijena,
apartmani[i].kn, apartmani[i].stanje);
if(err != 6)
break;
i++;
}
If I understand you correctly, you want to store several 'Apartmani' structures.
In this case, you have 2 main possibilites :
Using array of structures (Fastest to write but less efficient)
Use linked-list (More efficient but more complex to use)
Examples
1: Using array of structures
#define MAX_APARTMANI 50
int main(void) {
int i = 0;
/* Create Apartmani array */
Apartmani *apartmani_tab[MAX_APARTMANI];
do {
/* loop by using malloc on a single element */
apartmani_tab[i] = (Apartmani *) malloc(sizeof(Apartmani));
/* While check using scanf */
} while (scanf("%[^,\n],%[^,],%[^,],%d%[^,],%[^\n]", apartmani_tab[i]->Objekat, apartmani_tab[i]->Mjesto, apartmani_tab[i]->velicina,
apartmani_tab[i]->cijena, apartmani_tab[i]->kn, apartmani_tab[i]->stanje) == 6 && ++i < MAX_APARTMANI)
/* good pratice: don't forget to free memory ! */
while (--i > 0) {
free(apartmani_tab[i]);
}
return (0);
}
2: Using linked-list
typedef struct Apartmani {
char Objekat[20+1];
char Mjesto[20+1];
char velicina [20];
int cijena;
char kn[3];
char stanje[20];
struct Apartmani *next;/* add pointer to next item in the list */
} Apartmani_t;
Apartmani_t *new_item(void) {
Apartmani_t *new_element = NULL;
new_element = (Apartmani_t *) malloc(sizeof(Apartmani));
if (!new_element)
return (NULL);
memset(new_element, 0, sizeof(*new_element));
new_element->next = NULL;
return (new_element);
}
int main(void) {
/* Initialize Apartmani list*/
Apartmani *apartmani_list = NULL, *current = NULL;
do {
if (!apartmani_list) { /* if empty list */
apartmani_list = new_item(); /* add first item */
if (!apartmani_list) /* prevent malloc errors */
break;
current = apartmani_list; /* link current pointer to list */
} else {
current->next = new_item();
if (!current->next) /* if malloc fails */
break;
current = current->next; /* update current pointer */
}
} while (scanf("%[^,\n],%[^,],%[^,],%d%[^,],%[^\n]", current->Objekat, current->Mjesto, current->velicina, current->cijena, current->kn, current->stanje) == 6) /* While check using scanf */
/* good pratice: don't forget to free memory ! */
while (apartmani_list) {
current = apartmani_list->next;
free(apartmani_list);
apartmani_list = current;
}
}
NB: I have not tried this code but the final version is probably very close to that.
I have these challenges:
Define a struct containing 4 data types
Write a program in C that uses the rand() function to create 1000 instances of these structs
Inserts them in the linked list and prints out the first 10 to the console.
Modify the linked list code provided in the file code.c
so that it works for inserting structs of type given in your answer to Question 1.
#include <stdio.h>
#include <stdlib.h>
#include<malloc.h>
//#include "users.h"
int i;
//Stime = srand(time(0));
typedef struct users
{
int UserID;
char FullName[50];
int Age;
//double Height;
float Weight;
}users;
typedef struct node
{
//Stime = srand(time(0));
users data;
struct node *next;
} node;
node* insert(node *ptr, users data)
{
node *entry = (node*)malloc(sizeof(node));
//printf("enter the data item\n");
//scanf("%d",*node-> next);
if(entry == NULL)
{
printf("No Free Memory!\n");
exit(0);
}
else
{
entry->data = data;
entry->next = NULL;
if(ptr == NULL)
{
ptr = entry;
}
else
{
node *temp = ptr;
while(temp->next != NULL)
{
temp = temp->next;
}
temp->next = entry;
}
}
return ptr;
}
/
obviously U[i] is not the correct way to do this.
if I wanted to have unique constructors o-n (max 1000) how would I do it?
int main()
{
int i= 0;
node *first = NULL;
srand(time(0));
users U[i] = {
(U[i].UserID = 600000+rand()% 33331),
(strcpy( U[i].FullName , " Nathanial Rivers")),
(U[i].Age = 18+rand()% 82),
(U[i].Weight = 40+rand()% 99)
};
//users U1 = {600000,"Martin Toomey",19,76.6};
users U2 = {(U2.UserID = 600000+rand()% 33331),"bob boby",21,77.7};
users U3 = {600002,"abcdefg ",17,79.1};
printf(" Name: %s \n",U1.FullName);
printf(" User ID: %d \n Age is: %d \n Weight is: %f \n \n",U1.UserID, U1.Age, U1.Weight );
for (i=0; i<10; i++){
srand(time(0));
first = insert(first, U[i]);
/first = insert(first, U2);
//first = insert(first, U3);
//printf(" User ID: %d \n Age is: %d \n Weight is: %f \n \n",U1.UserID, U1.Age, U1.Weight );}
printf(" User ID: %d \n", U[i].UserID);
printf(" Age %d \n", U[i].Age);
printf(" User ID: %d \n", U[i].UserID);
printf(" Age %d \n", U2.Age);
}
//printf(U1);
first = insert(first, U2);
//printf(*U2);
first = insert(first, U3);
return 0;
}
In main() function, I'm trying to generate 100 unique users using rand
I have thought that if I have a print function or param in first and every time I call first in the loop in prints the user info with C I'm not sure if that possible
Any pointers on how to improve my code greatly appreciated I know U1 U2 U3.... shouldn't be used as var names its bad practice.
There are many problems in your posted code:
struct users[] user[i] = new users [100]:
Semicolon ; missing at end of the line
by using a typedef you don't have to specify the type via struct
if you want to use an array you should create it above the for-loop
in C you allocate dynamic memory with malloc: user* tmp = malloc(sizeof(user))
printf(user):
Semicolon ; missing at end of line
printf doesn't know the internal structure of the struct. So you have ot print have to declare it like with: printf(" User ID: %d \n Age is: %d \n Weight is: %f \n",Nathan.UserID, Nathan.Age, Nathan.Weight );
struct users Nathan;
by using a typedef you don't have to specify the type via struct.
Use user Nathan; instead
I would recommend you to use online resources or books and start with easier challenges.
I don't know why I can read the Linked list without problems in LABEL : 1 ; but the program just crashes and print grabage in the LABEL : 0 ;
In other terms, why the linked list works fine inside the lecture function , but not outside it ?
Here is my code :
/* including libraries */
#define V 20
typedef struct DATA{
char* NomP;char* NomA;
struct DATA *Next;
}DATA;
// Prototypes .
int main(void)
{
char FileName[V];
puts("Data file ? : ");gets(FileName);
FILE* fs = fopen(FileName,"r"); // Check if fs is NULL
DATA *HEAD = MALLOC(sizeof (DATA)); int len = lecture_data(fs,HEAD);
print_data(HEAD,len); //LABEL : 0
return 0;
}
int lecture_data(FILE *fs,DATA *ROOT)
{
char cNom[V],cArticle[V];
int eofs=0;int i=0;
while(!eofs)
{
DATA *Data = MALLOC(sizeof (DATA));
fscanf(fs,"%s %s",cNom,cArticle);
Data->NomA = MALLOC(strlen(cArticle)+1);
Data->NomP = MALLOC(strlen(cNom)+1);
strcpy(Data->NomA,cArticle);
strcpy(Data->NomP,cNom);
if( i==0 )
{
Data -> Next = NULL ;
ROOT = Data ;
}
else
{
DATA* Ptr = ROOT ;
while( (Ptr->Next) != NULL )
{
Ptr = (Ptr -> Next);
}
Data -> Next = NULL ;
Ptr -> Next = Data ;
}
i++;
eofs = feof(fs) ;
// check ferror(fs) here
}
puts("Start of reading :");
print_data(ROOT,len); // LABEL : 1
puts("End Of Reading ");
fclose(fs);
return i;
}
Here is the printing function :
void print_data(DATA *L_ROOT,int len)
{
int i = 0 ;
DATA* LINK;
LINK = L_ROOT;
while( LINK != NULL )
{
printf("%d : DATA->NomA : %s\n",i,LINK->NomA);
printf("%d : DATA->NomP : %s\n",i,LINK->NomP);
LINK = LINK -> Next ;
i++;
}
}
You're allocating data for the root of the list in the main function, and pass that to the function so that it may populate the list, but the first time you allocate an element you overwrite the ROOT pointer value.
this makes you lose the only connection between the function and the outside world (since the return value is just a number), so the HEAD value in main() is left pointing at nothing meaningful (because your function never uses it), while the list remains allocated in some memory location that no one outside is pointing to, which means it's lost. Running valgrind would have been able to identify this.
You can fix that by changing the (i==0) case from -
ROOT = Data ;
into
ROOT->next = Data ;
but make sure you're ignoring the data of the root node later on.
p.s. - using capitalized variables and types is not considered a good idea (it's mostly reserved for macros). It also makes your code look like you're shouting :)
The (main) problem is that lecture_data doesn't use it's input parameter (ROOT) for storage of the linked list, nor does it return the internal generated list. The correct way to handle this is to have ROOT reference the calling scope's parameter so that it can update it's reference as necessary.
int main(void)
{
char FileName[V];
puts("Data file ? : ");gets(FileName);
FILE* fs = fopen(FileName,"r"); // Check if fs is NULL
DATA *HEAD = NULL;
int len = lecture_data(fs, &HEAD);
print_data(HEAD); //LABEL : 0
return 0;
}
int lecture_data(FILE *fs,DATA **ROOT)
{
char cNom[V],cArticle[V];
int i=0;
DATA *current = *ROOT; // grab the passed in reference
while(!feof(fs))
{
if(fscanf(fs,"%s %s",cNom,cArticle) <= 0) // This call is only successful if the return value is > 0
{
// check ferror(fs) here
continue; // Can also "break;" here, essentially, it's eof already
}
DATA *Data = MALLOC(sizeof (DATA));
Data->NomA = MALLOC(strlen(cArticle)+1);
Data->NomP = MALLOC(strlen(cNom)+1);
strcpy(Data->NomA,cArticle);
strcpy(Data->NomP,cNom);
if(NULL == current) // ROOT was uninitialized before the call
{
Data -> Next = NULL;
*ROOT = Data;
}
else
{ // We don't need to iterate the list in every step.
Data->Next = current->Next; // This part allows the function to insert nodes in the middle / end of an existing list
current->Next = Data;
current = Data;
}
i++;
}
puts("Start of reading :");
print_data(ROOT); // LABEL : 1
puts("End Of Reading ");
fclose(fs);
return i;
}
Note: print_data didn't do anything with the len parameter, so no need passing it in at all.
This solution is not wasteful in terms of "empty" nodes in the list (as opposed to having an empty head to ignore), and is suitable both for initializing the list from scratch AND for cases where you need to append / insert into an existing list.
It seems at least weird to me... The program runs normally.But after I call the enter() function for the 4th time,there is a segmentation fault!I would appreciate any help.
With the following function enter() I wanna add user commands' datas to a list.
[Some part of the code is already posted on another question of me, but I think I should post it again...as it's a different problem I'm facing now.]
/* struct for all the datas that user enters on file*/
typedef struct catalog
{ char short_name[50];
char surname[50];
signed int amount;
char description[1000];
struct catalog *next;
}catalog,*catalogPointer;
catalogPointer current;
catalogPointer head = NULL;
void enter(void) //user command: i <name> <surname> <amount> <description>
{
int n,j=2,k=0;
char temp[1500];
char *short_name,*surname,*description;
signed int amount;
char* params = strchr(command,' ') + 1; //strchr returns a pointer to the 1st space on the command.U want a pointer to the char right after that space.
strcpy(temp, params); //params is saved as temp.
char *curToken = strtok(temp," "); //strtok cuts 'temp' into strings between the spaces and saves them to 'curToken'
printf("temp is:%s \n",temp);
printf("\nWhat you entered for saving:\n");
for (n = 0; curToken; ++n) //until curToken ends:
{
if (curToken)
{ short_name = malloc(strlen(curToken) + 1);
strncpy(short_name, curToken, sizeof (short_name));
}
printf("Short Name: %s \n",short_name);
curToken = strtok(NULL," ");
if (curToken)
{ surname = malloc(strlen(curToken) + 1);
strncpy(surname, curToken,sizeof (surname)); }
printf("SurName: %s \n",surname);
curToken = strtok(NULL," ");
if (curToken)
{ //int * amount= malloc(sizeof (signed int *));
char *chk;
amount = (int) strtol(curToken, &chk, 10);
if (!isspace(*chk) && *chk != 0)
fprintf(stderr,"Warning: expected integer value for amount, received %s instead\n",curToken);
}
printf("Amount: %d \n",amount);
curToken = strtok(NULL,"\0");
if (curToken)
{ description = malloc(strlen(curToken) + 1);
strncpy(description, curToken, sizeof (description));
}
printf("Description: %s \n",description);
break;
}
if (findEntryExists(head, surname,short_name) != NULL) //call function in order to see if entry exists already on the catalog
printf("\nAn entry for <%s %s> is already in the catalog!\nNew entry not entered.\n",short_name,surname);
else
{
printf("\nTry to entry <%s %s %d %s> in the catalog list!\n",short_name,surname,amount,description);
newEntry(&head,short_name,surname,amount,description);
printf("\n**Entry done!**\n");
}
// Maintain the list in alphabetical order by surname.
}
catalogPointer findEntryExists (catalogPointer head, char num[],char first[])
{ catalogPointer p = head;
while (p != NULL && strcmp(p->surname, num) != 0 && strcmp(p->short_name,first) != 0)
{ p = p->next; }
return p;
}
catalogPointer newEntry (catalog** headRef,char short_name[], char surname[], signed int amount, char description[])
{
catalogPointer newNode = (catalogPointer)malloc(sizeof(catalog));
catalogPointer first;
catalogPointer second;
catalogPointer tmp;
first=head;
second=NULL;
strcpy(newNode->short_name, short_name);
strcpy(newNode->surname, surname);
newNode->amount=amount;
strcpy(newNode->description, description);
while (first!=NULL)
{ if (strcmp(surname,first->surname)>0)
second=first;
else if (strcmp(surname,first->surname)==0)
{
if (strcmp(short_name,first->short_name)>0)
second=first;
}
first=first->next;
}
if (second==NULL)
{ newNode->next=head;
head=newNode;
}
else //SEGMENTATION APPEARS WHEN IT GETS HERE!
{ tmp=second->next;
newNode->next=tmp;
first->next=newNode;
}
}
UPDATE:
SegFault appears only when it gets on the 'else' loop of InsertSort() function.
I observed that segmentation fault appears when i try to put on the list names that are after it.
For example, if in the list exists:
[Name:b Surname:b Amount:6 Description:b]
[Name:c Surname:c Amount:5 Description:c]
[Name:d Surname:d Amount:4 Description:d]
[Name:e Surname:e Amount:3 Description:e]
[Name:g Surname:g Amount:2 Description:g]
[Name:x Surname:x Amount:1 Description:x]
and i put: " x z 77 gege" there is a segmentation
but if i put "x a 77 gege" it continues normally....
Can't post into comment, so here it goes:
while (first!=NULL) { //-> this loop can exit ONLY with 'first' being NULL
if (strcmp(surname,first->surname)>0)
second=first;
else if (strcmp(surname,first->surname)==0) {
if (strcmp(short_name,first->short_name)>0)
second=first;
}
first=first->next;
}
if (second==NULL) {
newNode->next=head;
head=newNode;
}
else {
tmp=second->next;
newNode->next=tmp;
first->next=newNode; // first used (but it's NULL!)
}
In other words, your program will crash if it finds any entry that satisfy conditions inside the loop and set 'second'. (This triggers intended addition "inside" the list).
Ok ~ no time to wait for answer :o), in a case you want to enter "after" the 'second' change code to this:
if (second==NULL) {
newNode->next=head;
head=newNode;
}
else {
newNode->next=second->next;
second->next=newNode;
}
explanation (S is 'second', N a 'newNode', A B just some exisiting entries in the list):
initial:
N
A -> S -> B
first assignment:
N ---\
|
v
A -> S -> B
second assignment:
N ---\
^ |
| v
A -> S B
and thus:
A-> S -> N -> B
Not sure what's causing the bug, but I did see this bad pattern:
char *short_name;
short_name = malloc(strlen(curToken) + 1);
strncpy(short_name, curToken, sizeof (short_name));
sizeof(short_name) will be always the same thing (usually 4 for 32 bit platforms and 8 for 64 bit platforms) so is not the correct value to use here. You should be doing:
strncpy(short_name, curToken, strlen(curToken) + 1);
Use something like valgrind to find problems like this.
Falling out of your while loop requires first to be null. In the else statement you attempt to access first.