collect string in loop and printout all the string outside loop - c

I'm newbie here and there is some question that I want have some lesson from you guys.
For example:
#include <stdio.h>
#include<stdlib.h>
#include<ctype.h>
void main()
{
char name[51],selection;
do
{
printf("Enter name: ");
fflush(stdin);
fgets(name,51,stdin);
printf("Enter another name?(Y/N)");
scanf("%c",&selection);
selection=toupper(selection);
}while (selection=='Y');
//I want to printout the entered name here but dunno the coding
printf("END\n");
system("pause");
}
As I know when the loops perform will overwrite the variable then how I perform a coding that will printout all the name user entered?
I have already ask my tutor and he is ask me to use pointer, can anyone guide me in this case?

You've basically got two options, create a list of all the names, looping through each of them at the end, or concatenate all the names into a string as you read them, and print that whole buffer at the end. The first goes roughly like this:
char ch[2]="Y", names[100][52]; //store up to 100 50-char names (leaving space for \n and \0)
int x, nnames=0;
while(nnames<100 && *ch=='Y'){
fgets(names[nnames++], sizeof names[0], stdin); //since names is a 2d array, look
//only at the length of a row, (in this case, names[0])
fgets(ch, 2, stdin);
*ch = toupper(*ch);
}
for(x=0; x<nnames; x++)
//print names[x].
And the second goes roughly like this:
char names[100*52], *np=names, *ep=names+sizeof names; //an array, the position, and the end
char ch[2]="Y";
while(np<ep && *ch=='Y'){
fgets(np, ep-np, stdin); //read a name, and a newline into the buffer
//note how I use the difference between the end and the position to tell
//fgets the most it can possibly read
np+=strlen(np); //advance the position to the end of what we read.
//same deal with the y/n stuff...
}
printf("%s", names);
Notice the lack of loop at the end, because the whole string is stored in names.

Use a single string to get all names:
char allnames[1000] = "";
do {
//get name in fgets
selection = toupper(selection);
strcat(allnames, selection);
//Check for repetion
} while (/*there is repetion*/);
printf("%s", allnames);
You've to select the size of allnames suitably to store all names.

You can use a linked list to store all the entered names. All data structure books talk about linked list a lot.
#include <stdio.h>
#include <stdlib.h>
struct name_node
{
char name[100];
struct name_node *next;
};
struct name_node* add_name(struct name_node *first, const char *name)
{
struct name_node *p;
/* create our node */
p = (struct name_node*)malloc(sizeof(struct name_node));
strcpy(p->name, name);
p->next = NULL;
/* link our node to the tail */
if (first) {
for (; first->next; first = first->next);
first->next = p;
}
return p;
}
void print_names(struct name_node *first)
{
/* print names stored in the list */
for (; first; first = first->next) {
printf("%s\n", first->name);
}
}
/* free the memory we used */
void destroy_list(struct name_node *first)
{
if (first) {
if (first->next)
destroy_list(first->next);
free(first);
}
}
int main(void)
{
struct name_node *head = NULL;
struct name_node *node;
char name[100];
char selection;
do {
printf("Enter name: ");
fflush(stdin);
fgets(name, 51, stdin);
/* save the user input to a linked list */
/* save head if we don't have head */
node = add_name(head, name);
if (!head)
head = node;
printf("Enter another name?(Y/N)");
scanf("%c", &selection);
selection = toupper(selection);
}
while (selection == 'Y');
/* print the list if we have any data */
if (head)
print_names(head);
/* free the memory we used */
destroy_list(head);
printf("END\n");
system("pause");
return 0;
}

Related

(C programming) bus error on my linked list

I'm learning to use linkedlist, I feel I already understand the concept but when coding why do I always get an error (bus error)....this code can run, but only until "SCANF the NAME" after that an error appears.
typedef struct Student{
char name[20];
char idNum[10];
int saving;
struct Student *next;
}Student;
Student *head = NULL;
void insert_student(){
char *name,*idNum;
int saving;
Student *current;
Student *new_student;
new_student = (Student*)malloc(sizeof(Student));
// apakah ada memoory kosong?
if(new_student==NULL){
printf("==== YOUR MEMMORY IS FULL! ====\n");
exit(0);
}
printf("Enter your name : ");scanf("%[^\n]s",name);
printf("Enter your Id : ");scanf("%[^\n]s",idNum);
printf("How many your money : Rp");scanf("%d",&saving);
strcpy(new_student->name,name);
strcpy(new_student->idNum,idNum);
new_student->saving = saving;
new_student->next = NULL;
if(head==NULL){
head = new_student;
}
else{
current = head;
while (current->next != NULL)
{
current = current->next;
}
current->next = new_student;
}
}
void print_students(){
Student *current;
if(head==NULL){
printf("==== THERE IS NO STUDENT YET!\n");
exit(0);
}
current = head;
while (current!= NULL)
{
printf("Name : %s",current->name);
printf("id : %s",current->idNum);
printf("Saving : Rp%d",current->saving);
current = current->next;
}
}
int main(){
insert_student();
print_students();
return 0;
}
I'm hoping to create nodes for the dynamic linked-list Student and then display them
printf("Enter your name : ");scanf("%[^\n]s",name);
printf("Enter your Id : ");scanf("%[^\n]s",idNum);
You have to give named and idNum meaningful values before you pass their values to scanf. Instead, you are just passing uninitialized garbage value to scanf, which won't work. You must pass to scanf pointers to the place you want the strings you're reading in to be stored.
For starters it is a bad idea to make the functions to depend on the global variable head. In this case you will not be able to use more than one list in the program.
Within the function insert_student you declared uninitialized pointers name and idNum:
char *name,*idNum;
So using them in the calls of scanf
printf("Enter your name : ");scanf("%[^\n]s",name);
printf("Enter your Id : ");scanf("%[^\n]s",idNum);
invokes undefined behavior.
You need to declare character arrays instead of pointers
char name[20], idNum[10];
Also the format specifications are incorrect.
You should write
printf("Enter your name : "); scanf( " %19[^\n]", name );
printf("Enter your Id : "); scanf( " %9[^\n]", idNum );
Pay attention to the leading space in the format strings It allows to skip white space characters.
Otherwise after this call of scanf
printf("How many your money : Rp");scanf("%d",&saving);
the input buffer will contain the new line character '\n'. So when you will call the function insert_student a second time the first call of scanf (if the format specification does not contain the leading space)
printf("Enter your name : "); scanf( "%19[^\n]", name );
will read an empty string.
Also it is not a flexible approach when the whole program exits if a new node was not allocated.
if(new_student==NULL){
printf("==== YOUR MEMMORY IS FULL! ====\n");
exit(0);
}
It will be better to return to the caller an integer that will report whether the function was executed successfully. For example
int insert_student( void )
{
//...
Student *new_student;
new_student = (Student*)malloc(sizeof(Student));
int success = new_student != NULL;
if ( success )
{
printf("Enter your name : ");scanf("%[^\n]s",name);
printf("Enter your Id : ");scanf("%[^\n]s",idNum);
printf("How many your money : Rp");scanf("%d",&saving);
//...
}
return success;
}

Pointer to structure in C

How can I display the stored values via pointer, my code outputs to NULL. I've already tried assigning the struct emp to ptr before the 2nd loop but it won't run.
struct rec {
char *Name;
}emp[100];
int main() {
int x;
int i;
struct rec *ptr = NULL;
ptr = emp;
printf("Enter Number of Clients: ");
scanf("%d", &x);
getchar();
for(i=0; i!=x; i++){
printf("Enter Name: ");
scanf("%[^\n]", &ptr->Name);
getchar();
ptr++;
printf("\n");
}
i = 0;
while(i!=x){
printf("Name is: %s\n", *ptr->Name);
i++;
ptr++;
}
If the code iterates twice it prints
Name: (NULL)
Name: (NULL)
How can I display the stored values via pointer, my code outputs to NULL. I've already tried assigning the struct emp to ptr before the 2nd loop but it won't run.
There are several issues in your code which are listed below:
You need to re-initialize your ptr pointer to the beginning of the array emp after the first loop.
ptr = emp;
Second one being data member name of your struct emp. It is just a pointer and it doesn't point towards a valid memory address where you can save user input cstring. Either you need to allocate the memory dynamically using malloc or use statically allocated memory just like shown below. However, you can have buffer overflow if you input characters more than DEFAULT_NAME_SIZE (including /0 character).
%[^\n] matches a char *, not a char **. You need to use scanf("%[^\n]", ptr->Name); not scanf("%[^\n]", &ptr->Name);.
"%s" format specifier of printf requires an arugment of type char * but you have been passing char type to it. The correct statement is printf("Name is: %s\n", ptr->Name);.
-
#include <stdio.h>
#define DEFAULT_NAME_SIZE 200
struct rec {
char Name[DEFAULT_NAME_SIZE];
} emp[100];
int main()
{
int x;
int i;
struct rec *ptr = NULL;
ptr = emp;
printf("Enter Number of Clients: ");
scanf("%d", &x);
getchar();
for (i=0; i< x; i++){
printf("Enter Name: ");
scanf("%[^\n]", ptr->Name);
getchar();
ptr++;
printf("\n");
}
ptr = emp;
for (i = 0; i < x; i++){
printf("Name is: %s\n", ptr->Name);
ptr++;
}
return 0;
}
You can try to enable all warning while you compile your code. Most of the bugs can be pointed by the compiler's warning message.
char *Name;
You never allocated space for the name. Did you mean
char Name[100]
?
This should work, until somebody enters too long of a name. You will get to buffer overflow later and learn about dynamic memory allocation.
When scanning or printing strings, we don't use & and * for referencing and dereferencing pointers, but we must also alloc and free space for them. Fixed your code:
#include <stdio.h>
#include <stdlib.h>
struct rec {
char *Name;
}emp[100];
int main() {
int x;
int i;
struct rec *ptr = NULL;
ptr = emp;
printf("Enter Number of Clients: ");
scanf("%d", &x);
getchar();
for(i=0; i!=x; i++)
{
printf("Enter Name: ");
/* alloc space for string pointer */
ptr->Name = (char*) malloc(sizeof(char)*10);
scanf("%s[^\n]",ptr->Name);
getchar();
ptr++;
printf("\n");
}
i = 0;
/* reset array pointer position */
ptr=emp;
while(i!=x)
{
printf("Name is: %s\n", (ptr->Name));
/* free space for string pointer */
free(ptr->Name);
i++;
ptr++;
}
}
PS: Remember resetting a pointer to the initial position whenever using pointers to arrays.

How to show the result of written strings

I'm learning C Programming and I can't resolve this issue.
This is my code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int first;
printf("Write Down Your First Name!\n\n");
scanf("%s", &first);
int last;
printf("\nNow Write Your Sir Name!\n\n");
scanf("%s", &last);
printf("\nYour Full Name is %s\n\n");
system("pause");
return 0;
}
And I want to show the full name written.
Should I use void?
Thanks in advance
first and last should be of char array type instead of int type if you want to store characters into that.
int first; ---> char first[100]; /* define how many char you want in first*/
similarly
int last; --> char last[100];
And while scanning it you don't have to pass &
scanf("%s", first);
scanf("%s", last);
Want to print/show ?
printf("\nNow Write Your Sir Name! %s n\n", first);/* you missed to pass argument to printf */
printf("\nYour Full Name is %s\n\n",first);
How to join both ? Iterate last upto '\0' char and copy each char of last to end of first
int len = strlen(first);
first[len] = ' ';/* if needed, put space at the end of first */
for( i = 0, j = len + 1 ; last[i]!='\0;i++,j++) {
first[j] = last[i]; /* first should have enough space */
}
first[j] = '\0';
Now print it as
printf("\nYour Full Name is %s\n\n",first);

Segmentation fault when writing data to a dynamic array

My assignment is to write a file that displays an unknown number of records entered by the user. Each record has the following fields: First Name, Last Name, Address, City, State, Zip Code, and Phone Number.
I assumed the best way to do this would be to define a struct Record with the fields above, then declare an array of Records that would contain as many records as the user entered. To accomplish this I would use a loop to get the inputs for each field per record, then if the user wanted to continue dynamically allocate an extra space in the Record array and continue until the user enters no. I encountered an access violation writing location error at line:
scanf("%s", records[i]->fname);
What's wrong with my code?
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
struct Record;
struct Record
{
char fname[51];
char lname[51];
char address[51];
char city[51];
char state[51];
int zipcode;
int phoneNumber;
};
int main()
{
FILE *fileWriter;
const char filename[] = "data.txt";
char answer = 'y';
int size = 1;
int i = 0;
struct Record **records;
records = malloc(sizeof(*records)*(size));
while(answer == 'y' || answer == 'Y')
{
printf("First Name: \n");
scanf("%s", records[i]->fname);
printf("Last Name: \n");
scanf("%s", records[i]->lname);
printf("Address: \n");
scanf("%s", records[i]->address);
printf("City: \n");
scanf("%s", records[i]->city);
printf("State: \n");
scanf("%s", records[i]->state);
printf("Zipcode: \n");
scanf("%d", records[i]->zipcode);
printf("Phone Number: \n");
scanf("%d", records[i]->phoneNumber);
//stores all record info
printf("Are there anymore records? [y/n] ");
answer = getchar();
if(answer == 'y' || answer == 'Y')
{
size++;
records[i++];
printf("\n");
}
records = realloc(records,sizeof(*records)*(size));
}
//open file
fileWriter = fopen(filename,"wb");
if(fileWriter != NULL)
{
if(fwrite(records,sizeof(*records),size,fileWriter) != 1)
{
fprintf(stderr, "Failed to write to %s\n", filename);
exit(1);
}
fclose(fileWriter);
}
else
{
printf("Error opening file.");
}
}
EDITED VERSION
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
struct Record
{
char fname[51];
char lname[51];
char address[51];
char city[51];
char state[51];
int zipcode;
int phoneNumber;
};
int main()
{
FILE *fileWriter;
const char filename[] = "data.txt";
char answer = 'y';
int size = 1;
int i = 0;
struct Record *records = NULL;
struct Record *records_temp;
while(answer == 'y' || answer == 'Y')
{
struct Record *records_temp = realloc(records,(size)*sizeof(*records));
if(records_temp == NULL)
{
free(records);
}
records = records_temp;
printf("First Name: \n");
scanf("%s", records[i].fname);
printf("Last Name: \n");
scanf("%s", records[i].lname);
printf("Address: \n");
scanf(" %[^\n]", records[i].address);
printf("City: \n");
scanf("%s", records[i].city);
printf("State: \n");
scanf("%s", records[i].state);
printf("Zipcode: \n");
scanf("%d", &records[i].zipcode);
printf("Phone Number: \n");
scanf("%d", &records[i].phoneNumber);
//stores all record info
printf("Are there anymore records? [y/n] ");
answer = getchar();
if(answer == 'y' || answer == 'Y')
{
size++;
records[i++];
printf("\n");
}
//open file
fileWriter = fopen(filename,"wb");
if(fileWriter != NULL)
{
if(fwrite(records,sizeof(*records),size,fileWriter) != 1)
{
fprintf(stderr, "Failed to write to %s\n", filename);
exit(1);
}
fclose(fileWriter);
}
else
{
printf("Error opening file.");
}
}
}
Well, you get a segfault because you haven't allocated memory for the first entity in your records.
So to resolve that you need to
records[size-1] = malloc(sizeof(Records));
To put it in this way:
You have records that is a pointer to a pointer to Records.
When you did
records = malloc(sizeof(*records)*(size));
You actually asked for size pointers to Records.
But that is not enough, you need to allocate another memory to store the actual Records so that is why we have to
records[size - 1] = malloc(sizeof(Records));
Note: if size > 1 then you should do:
int i = 0;
for(;i < size; i++) {
records[i] = malloc(sizeof(Records));
}
In addition to that, why did you go with Records **, as Arjun has already explained, you should use Records * and fix the part of realloc-ing new memory, because if realloc fails, it returns NULL and you end up with memory leak or another segfault in the worst scenario, either way -- it is not good for your program.
Please see Arjun's post
When you want to dynamically allocate space for a list of Records, you should be doing:
struct Record *records;
records = malloc(size * sizeof(*records));
This allocates space for size number of Records.
To increment the allocated size, you should:
struct Record *records_temp = realloc(records, newsize * sizeof(*records));
if (records_temp == NULL) {
free(records);
/* die with error -ENOMEM */
}
records = records_temp;
Do not realloc to the same pointer. It can cause you to leak memory on failure.
Or, you can avoid malloc() and use just realloc() in a loop by providing it with a NULL pointer initially.
C 89 standards says:
4.10.3.4 The realloc function
If ptr is a null pointer, the realloc function behaves like the malloc
function for the specified size.
struct Record *records = NULL;
struct Record *records_temp;
size = INITIAL_SIZE;
while (/* your condition */) {
records_temp = realloc(records, size * sizeof(*records));
if (records_temp == NULL) {
free(records);
/* die with error -ENOMEM */
}
records = records_temp;
/* do stuff */
size += SIZE_INCREMENT;
}
As Jonathan Leffler commented, but declined to make an answer out of his comments:
Note that the line records[i++]; increments i and does nothing else useful.
And also:
Also note that the struct Record; line really isn't necessary. The only time it might make a difference is if you are defining mutually recursive structures in a function scope rather than at file scope (and this use is at file scope). As it is, the line says "there is a type struct Record", and the next block of code says "there is a type struct Record and this is how it is defined".
When asked by Cool Guy to illustrate what was meant by that, Jonathan said:
struct A { … };
struct B { … };
void f(void)
{
struct A;
struct B
{
…;
struct A *a_ref;
…
};
struct A
{
…;
struct B *b_ref;
…
};
…
}
Without the struct A; line, the a_ref element would point at a structure of the externally defined type struct A, not the mutually recursive pair of structure types. The error messages could be quite confusing too! However, reusing type names like this is a bad idea.

Using pointer in structure and writing it file in C

I was working on my college project in C and got some problem.
I used pointer to structure and used it to write in a file using fwrite but it isn't helping.Here is the code I used.
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
#include<conio.h>
struct collection{
char *fname, *lname, *telephone, *address, *seat;
};
collection * alloc( ){
struct collection *r = (struct collection *) malloc (sizeof(collection*));
r->fname = NULL;
r->lname = NULL;
r->telephone = NULL;
r->address = NULL;
r->seat = NULL;
return (r);
}
void string_realloc_and_copy (char **dest, const char *src){
*dest =(char *) realloc (*dest, strlen (src) + 1);
strcpy (*dest, src);
}
int main(){
char ch = 'Y', temp[50];
FILE *ptf;
struct collection *asd;
asd = alloc();
//printf("%d",sizeof(asd));
//opening file
ptf = fopen("lang.txt","w+");
do{
printf("First name: ");
gets(temp);
string_realloc_and_copy(&asd->fname,temp);
printf("Last name: ");
gets(temp);
string_realloc_and_copy(&asd->lname,temp);
printf("Telephone: ");
gets(temp);
string_realloc_and_copy(&asd->telephone,temp);
printf("Address: ");
gets(temp);
string_realloc_and_copy(&asd->address,temp);
printf("Seat you want to book: ");
gets(temp);
string_realloc_and_copy(&asd->seat,temp);
fwrite(asd,12*sizeof(collection),1,ptf);
fflush(ptf);
//fprintf(ptf,"\n");
printf("Do you wish to enter another data...? (Y/N) ");
ch = getch();
}while((ch=toupper(ch))== 'Y');
rewind(ptf);
while(fread(asd,12*sizeof(collection),1,ptf) == 1){
printf("\n\n%s",asd->fname);
printf("\n\n%s",asd->lname);
printf("\n\n%s",asd->telephone);
printf("\n\n%s",asd->address);
printf("\n\n%s",asd->seat);
}
fclose(ptf);
}
It works until asd->telephone is reached it ask for address and goes unresponding. I could not figure out what i did wrong. I thought it was out of memory so i change
struct collection *r = (struct collection *) malloc (sizeof(collection*));
to
struct collection *r = (struct collection *) malloc (12*sizeof(collection*));
And it worked for some time and again same thing happened. I am using devC++ for compilation. Thanks in advance;
First you should not use gets() because its deprecated and there is no limit in how many characters it gets from stdin. I recommand you to use fgets. You should use malloc like this for a pointer
malloc(sizeof(*collection));
This way you allocate memory for a pointer.
And one another thing try this program with putc() and see if it works.
malloc (sizeof(collection*)) should be malloc(sizeof(*collection)). Your code is only allocating enough space for a pointer to the collection type, not the size of the structure that the collection pointer points to.
This also shows why it's a bad idea to use the same name for both a variable and a type. If you'd used different names, you would have gotten an error from the compiler. Use collection_t for the type.
Try sizeof (struct collection) without the *
i found so many changes in your code.First change is struct collection instead of collection .Second change is i used two file descriptors one for reading another one for writing.Third in your code you are initializing "asd" only once due to this it will write same structure every time into file . So i initialized inside do-while loop.Fourth one i used scanf instead of gets because when you are taking multiple inputs it's skipping some inputs.Fifth i removed 12 form fwrite and fread.Sixth i used one more getchar because we will press enter after giving seat number so ch is taking that enter to take the user input i had to use one more getcharFinally the changed code is
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
//#include<conio.h>
struct collection
{
char *fname, *lname, *telephone, *address, *seat;
};
struct collection *alloc( ){
struct collection *r= malloc(sizeof(struct collection));
r->fname = NULL;
r->lname = NULL;
r->telephone = NULL;
r->address = NULL;
r->seat = NULL;
return (r);
}
void string_realloc_and_copy (char **dest, const char *src){
*dest =(char *) realloc (*dest, strlen (src) + 1);
strcpy (*dest, src);
}
int main(){
char ch = 'Y', temp[50];
FILE *ptf;
struct collection *asd;
//printf("%d",sizeof(asd));
//opening file
ptf = fopen("lang.txt","wb");
do{
asd = alloc();
printf("First name: ");
scanf("%s",temp);
string_realloc_and_copy(&asd->fname,temp);
printf("Last name: ");
scanf("%s",temp);
string_realloc_and_copy(&asd->lname,temp);
printf("Telephone: ");
scanf("%s",temp);
string_realloc_and_copy(&asd->telephone,temp);
printf("Address: ");
scanf("%s",temp);
string_realloc_and_copy(&asd->address,temp);
printf("Seat you want to book: ");
scanf("%s",temp);
string_realloc_and_copy(&asd->seat,temp);
fwrite(asd,sizeof(struct collection),1,ptf);
fflush(ptf);
//fprintf(ptf,"\n");
printf("Do you wish to enter another data...? (Y/N) ");
ch = getchar();
ch = getchar();
}while((ch=toupper(ch))== 'Y');
//rewind(ptf);
fclose(ptf);
FILE *ptf1;
ptf1 = fopen("lang.txt","rb");
while(fread(asd,sizeof(struct collection),1,ptf1)){
printf("\n\n%s",asd->fname);
printf("\n\n%s",asd->lname);
printf("\n\n%s",asd->telephone);
printf("\n\n%s",asd->address);
printf("\n\n%s",asd->seat);
}
fclose(ptf1);
}
and sample out put is

Resources