As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
I don't know why the first fwrite() for customer, works, but not the second fwrite() for the symbol of the message. My program wants to check if the customer and the symbol from the message already contained in the library.dat. Here is my piece of code :
typedef struct {
char Name[50];
int totalmsg;
int totalword;
} Customer;
typedef struct {
char symbol;
char alphabet[20];
} Ssymbol;
void add_customer () {
boolean found;
int i;
fp = fopen("customer.dat", "wb+");
fread(&Customer_history, sizeof(TabInt), 102, fp);
i = GetLastIdx(Customer_history);
do {
printf ("Please input customer's name: ");scanf("%s",&temp);
if (i == 0) {
i++;
SetName(&Customer_history,i,temp);
SetMsg(&Customer_history,i,i);
SetEff(&Customer_history,i);
printf("Do you still wanna add another customer ?(Y/N)"); scanf("%s",&CC);
}
else {
found = Search_name(Customer_history,temp);
if (found == true) {
printf("The name is already exist \n\n");
}
else {
i++;
SetName(&Customer_history,i,temp);
SetMsg(&Customer_history,i,i);
SetEff(&Customer_history,i);
}
printf("Do you still wanna add another customer ?(Y/N)"); scanf("%s",&CC);
}
} while ((CC == 'y') || (CC =='Y'));
fwrite(&Customer_history, sizeof(Customer), 102, fp);
fclose(fp);
}
void add_symbol() {
char tempc;
char tempalphabet[20];
boolean found;
int i;
fp = fopen("library.dat","wb+");
fread(&list_symbol, sizeof(Ssymbol), 52, fp);
i = GetLastIdx2(list_symbol);
do{
printf("Please input new symbol:");
scanf("%s", &tempc);
printf("Please input the alphabet of the symbol:");
scanf("%s", &tempalfabet);
if (i==0){
i++;
SetSymbol(&list_symbol,i,tempc);
SetAlphabet(&list_symbol,i,tempalphabet);
printf("Do you want to add another symbol? (Y/N)");
scanf("%s",&CC);
}
else{
found = Search_symbol(list_symbol, tempc);
if (found==true){
printf("Symbol is already exist \n\n");
}
else{
i++;
SetSymbol(&list_symbol,i,tempc);
SetAlphabet(&list_symbol,i,tempalphabet);
printf("Do you want to add another symbol? (Y/N)");
scanf("%s",&CC);
}
}
}
while((CC=='y') || (CC=='Y'));
fwrite(&list_symbol, sizeof(Ssymbol),52, fp);
fclose(fp);
}
If you are only expecting a single character here:
scanf("%s", &tempc);
then change it to:
scanf("%c", &tempc);
otherwise, you need to define tempc as an array (and don't use &).
Here also, since tou are passing an array, you should not use address-of (&):
printf("Please input the alphabet of the symbol:");
// scanf("%s", &tempalfabet); is wrong
scanf("%s", tempalfabet); // correct
Inspect all scanf calls in your code and fix them
It's hard to say without a more "compile-able" version of your code... Here're some points for you:
A) boolean is not a type in C. You'll need something like:
#include <stdbool.h> // or some other header that defines bool
typedef bool boolean;
Failing that:
typedef int boolean;
#define false 0
#define true 1
B) add_customer() and add_symbol() using fp which is not defined. You need to define a FILE * fp for those operations.
C) The following (I assume to be) methods are not defined: GetLastIdx(), SetName(), SetMsg(), SetEff(), Search_Name(), GetLastIdx2(), SetSymbol(), SetAlphabet(), Search_symbol()
D) The following (I assume to be) global variables and data structers are not defined: Customer_history, TabInt, temp, CC, list_symbol, tempalfabet
Based on your problem description I assume you have this working, so these should all be defined. If you can provide a more complete, compile-able version of your code showing the problem, I could be of more help.
So based on what I have, here's some input:
1) You are reading into your list_symbol, this should be a pointer to a block of memory big enough for 52*sizeof(Ssymbol), this should be around 1092 bytes.
fread(&list_symbol, sizeof(Ssymbol), 52, fp);
Also note that if list_symbol is an array of Ssymbols then your read code be screwed up by the fact that you have an array in your structure, fread() will read and fill your data exactly byte for byte. For example:
Ssymbol list_symbol[52];
FILE * fp = fopen("test.txt", "r");
memset(list_symbol, 0, 52*sizeof(Ssymbol));
fread(list_symbol, sizeof(Ssymbol), 52, fp);
And let's says "test.txt" has in it:
C abcdefghijklmn
3 12345678
Then your list_symbol will look like:
list_symbol[0].symbol = 'C'
list_symbol[0].alphabet = ' abcdefghijklmn3 12' //note the newline and spaces fill it
list_symbol[1].symbol = '3'
list_symbol[1].alphabet = '45678'
And that might not be what you wanted to do. Make sure your data matches your structures!
2) Your one scanf() that you completely show is wrong:
char tempc;
...
scanf("%s", &tempc);
You want "%c" if you want a character, not "%s". I don't see the other declarations (see point D) above, however based on your prints and your usage I can tell you tempalfabet and CC are almost certainty wrong as well.
3) Your scanf()s are going to leave newline characters unless you consume them:
printf("Please input new symbol:");
scanf("%c\\n", &tempc); // <-- escaped newline will do that for you
4) You open your files with "wb+". See fopen() options that's for writing and appending to a binary file. If you want a binary file to read and write you need: "ab+", if you want a text file "a+" will do.
5) You do not reset the file pointer:
fopen(file for reading, writing, and appending);
fread(stuff);
do c code;
fwrite(stuff);
This will result in what you have written being appended to the bottom of your file. I don't know if that's what you wanted. So this might not be a problem if you wanted to read a full list_symbol worth of data, then append a new set to the bottom of your file. I suspect that you wanted to overwrite what was in your file however... in which case you need to fseek() back to the beginning, or you can simply close and open the file.
I am trying to guess the issue, since the entire code is not vailable..
Is it possible that the number of symbols is exceeding 52, and you are writing only first 52 symbols? So fwrite is indeed working, but it is not changing the data file. Try printf'ing i(=GetLastIdx2), to see if it is exceeding 52.
Also, instead of having array for list_symbols, I would recommend using a linked list & fread/fwrite, using a while loop, to read/write all the symbols in the data file.
From the code logic, it want to read some data from file and then update it.
Then you should use "rb+" mode to open the file, instead of "wb+" which truncate the whole data. With "wb+" mode, the file data is truncated and the fread() should return 0, the whole do/while becomes invalid.
I don't know why the first fwrite() works, both of them should not.
In all, try ab+ mode in fopen(), and don't forget to call fseek() with SEEK_SET to reset the file position indicator before calling fwrite(), it may resolve your problem.
Related
I really need your help with my program. I'm a newbie in C and need to create a linked list in my project.
I use xcode on macOS.
My code is here:
typedef struct person
{
char name[500];
char telnum[16];
char wohnort[500];
struct person *next;
}person;
person *head=NULL;
void einlesen()
{
person *p;
char name[30];
char telnum[16];
char wohnort[30];
//char buff1[15], buff2[15];
int cnt=0;
FILE *fp=fopen("Data2.txt", "r");
if(fp==NULL)
{
printf("File konnte nicht geoeffnet werden!\n");
exit(1);
}
while(fscanf(fp," %29[A-z ]\t%s\t%s", &name, &telnum, &wohnort)!=EOF)
{
cnt++;
printf("Datei gefunden!\nDaten:%s, %s, %s\n", name, telnum, wohnort);
if(head == NULL){
head = (person*)malloc(sizeof(person));
strcpy(head->name, name);
strcpy(head->telnum, telnum);
strcpy(head->wohnort, wohnort);
head->next = NULL;
}
else{
p = head;
while(p->next != NULL)
{
p = p->next;
}
p->next = (person*)malloc(sizeof(person));
strcpy(p->next->name,name);
strcpy(p->next->telnum,telnum);
strcpy(p->next->wohnort,wohnort);
p->next->next = NULL;
}
}
printf("Die Daten von %d Personen wurden eingelesen!\n\n", cnt);
fclose(fp);
}
void addieren()
{ char name[30];
char telnum[16];
char wohnort[30];
person *p = head;
printf("Bitte den Namen der hinzufuegenden Person eingeben:\n");
scanf(" %29s", name);
while(getchar() != '\n');
printf("\nBitte die Telefunnumer der hinzufuegenden Person eingeben:\n");
scanf(" %15s", telnum);
while(getchar() != '\n');
printf("\nBitte den Wohnort der hinzufuegenden Person eingeben:\n");
scanf(" %29s", wohnort);
while(getchar() != '\n');
if(p==NULL) return;
while(p->next)
{
p=p->next;
}
p->next = (person*)malloc(sizeof(person));
strcpy(p->next->name, name);
strcpy(p->next->telnum, telnum);
strcpy(p->next->wohnort, wohnort);
p->next->next=NULL;
}
and i have this in my main function:
int main()
{
person *p1=head;
einlesen();
addieren();
while(p1 !=NULL)
{
printf("Namen: %s\n", p1->name);
p1=p1->next;
}
return 0;
}
It's already read the data from the file and I wanted to add some new records to it and the print to the screen. This returns 0 and doesn't really print the list on the screen.
Later I need to add more functions to my program, like:
-deletefromlist
-modify element
-search in the linked list
-save to file
-and a menue
I see no particular question, so I'll start by pointing out some errors, and perhaps when you've added a question (which ends in a question mark) you can ping me for an update.
while(fscanf(fp," %29[A-z ]\t%s\t%s", &name, &telnum, &wohnort)!=EOF)
Let me just start off by saying I'm a huge advocate of reading the manual before using a function for the first time. In fact, I'm pretty sure it's expected of us, as programmers. Granted, we must learn which manuals to seek, because the internet is a dangerous place and people do occasionally lie. The OpenGroup manuals are good. For example, if you type into Google "Opengroup fscanf", you'll find the manual for fscanf, which will answer many questions I', sure...
The manual states that all whitespace is treated the same, as a directive which attempts to read and discard as much whitespace as possible. Hence, a plain space has the same meaning to \t in a format specifier (at least, in your context)... so if your question is something along the lines of "Why are all whitespaces treated the same?" then the answer is "because that's what the manual says it should do."
The fixed width field you're reading into can fail to translate, in a scenario the manual also describes where-by the first character tested failed to match the criteria ([A-z ], which looks highly suspect, and you'll probably realise by reading the manual that this isn't what you want). That would result in a return value (from scanf) of 0, which, to your code, looks like a successful read.
Here's an idiomatic guideline: Let's first count the number of objects that you want to read into... Here they are, copied verbatim from your code: &name, &telnum, &wohnort... There are three of them.
Now, take that number, three, and compare it to what fscanf returns... If these two numbers match, then you can use all three arguments safely (though as I note below, they may not necessarily contain the values that you expect them to contain).
You also shouldn't use the & (address-of) operator here for name, telnum or wohnort. The address-of operator on a char [10] array would result in a char (*)[10] expression, where-as you most certainly want a plain vanilla char * expression. Hence, the correct thing to do is to let Cs implicit "array expression to pointer expression" conversion do that for you.
Below is probably closer to what you want. My advice regarding the [A-z ] thing is that you list out each of the characters you want to include in those brackets, or use [^...] if you want to list out each of the characters you want to exclude. To be clear, there are no ranges in C format strings, in case that's what your question was about. e.g.:
while(fscanf(fp," %29[qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM ] %s %s", name, telnum, wohnort)==3)
Note that it isn't quite there, yet. There's the potential for 29 bytes of a 32 byte input to be read into that fixed width field, leaving three characters on the stream. Perhaps they're not space, in which case your whitespace directive will silently fail, and those remaining three characters will be treated as telnum.
You should try to read just one item per call to scanf, if only until you understand the corresponding manual.
No collection should ever require n calls to malloc to store n objects. If you manage to complete this (no doubt self-assigned) task, I suggest making it your next priority to allocate your list as multiple nodes per call to malloc... or better yet, the convenience you get not having to free() every string fscanf returns, you could benefit from the same technique; expect caller to allocate the list, passing you all the storage you need, as well as items to add, remove, etc from the list. All the function does is modify the objects passed in.
while(getchar() != '\n');
Above you recognise that EOF can occur... what do you think getchar() will return when that happens? Not '\n', that's for sure, and it'll keep returning that (not `'\n') value indefinitely, hence an infinite loop. Trying to solve this problem complicates the loop a bit; you need storage for the character, e.g.:
int c;
while ((c = getchar()) != EOF && c != '\n');
The clearer alternative to that is actually to use fread, e.g.
char c;
while (fread(&c, 1, 1, stdin) && c != '\n');
Nonetheless, better yet, is using fscanf, according to how the manual explains (there are many other useful functionalities for you to read about A.S.A.P.). Do you think you can remember these two lines, after typing them ten or fifteen times in a row?
scanf("%*[^\n]");
getchar();
Man... your code should always check malloc return values before they're used. How do we know your malloc calls aren't returning NULL, leading to a question which you haven't asked?
You are creating a new person inside the function addieren instead of receiving the one you created on the main function. You need to receive it as an argument, something like that
int addieren(person **head) { ... }
And on the main you should make
addieren(&p1);
Notice the double pointer so you can pass the pointer and modify it inside of the function. Also you probably should return an int to confirm either the operation was succesfull or not
Im still considered a beginner in c and i started learning about files. i already built a blank file. Every time i compile this program, the file is still blank. Need help!!
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE * x;
char name[25];
printf("enter your name: ");
scanf("%s", &name);
x = fopen("x1.txt", "w");
if(x = NULL)
{
printf("Unable to open the file");
}
else
{
fprintf(x, "%s\n", name);
printf("date has been entered successfully to the file");
fclose(x);
}
return 0;
}
Thank you
A file existed, and contained my name, after making the following changes and rebuilding/running the program:
(see comments in line for reasons)
Change:
if(x = NULL)//assignment - as is, this statement will always evaluate
//to false, as x is assigned to NULL.
To:
if(x == NULL)// comparison - this will test whether x is equal to NULL without changing x.
Change: (this was key to your file not being populated)
scanf("%s", &name);//the 'address of' operator: '&' is not needed here.
//The symbol 'name' is an array of char, and is
//located at the address of the first element of the array.
To:
scanf("%s", name);//with '&' removed.
Or better:
scanf("%24s", name);//'24' will prevent buffer overflows
//and guarantee room for NULL termination.
Yet one more method to address the comment about not using scanf at all...:
char buffer[25];//create an additional buffer
...
memset(name, 0, 25);//useful in loops (when used) to ensure clean buffers
memset(buffer, 0, 25);
fgets(buffer, 24, stdin);//replace scanf with fgets...
sscanf(buffer, "%24s", name);//..., then analyze input using sscanf
//and its expansive list of format specifiers
//to handle a wide variety of user input.
//In this example, '24' is used to guard
//against buffer overflow.
Regarding the last method, here is a page detailing the versatility of handling user input strings using sscanf.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have to get node ids from DIMES ASNodes.csv (http://netdimes.org/new/?q=node/65) files.
File looks like this:
6067,UNKNOWN,2007-02-03 10:03:53.0,2007-01-02 02:54:13.0,12,6,0
29287,UNKNOWN,2007-02-03 21:11:07.0,2007-01-02 07:33:35.0,1,0,0
...
So far I came up with this code, but it doesn't work quite right. Althought it prints out all the numbers I needed, it also prints out the node id twice and sometimes prints zeroes in between. Thanks for any ideas
void loadNodes(const char* filename)
{
FILE* nodes = fopen(filename, "r");
unsigned int id = 0;
char line[64];
while (fgets(line, sizeof(line), nodes) != NULL) {
sscanf(line, "%u%*[^\n]", &id);
printf("id = %u\n", id);
}
fclose(nodes);
}
output
I think the trouble is that your lines have 63 characters plus a newline, which means that the fgets() reads up to, but not including, the newline (and you process that and get the correct number), then the next fgets() reads the newline that was left behind on the previous input (and you process that — it is surprising that you get zeros rather than a repeat of the previous number).
Here's your code converted into an MCVE (How to create a Minimal, Complete, and Verifiable Example?) main() program that reads from standard input (which saves me from having to validate, open and close files):
#include <stdio.h>
int main(void)
{
unsigned id = 0;
char line[64];
while (fgets(line, sizeof(line), stdin) != NULL)
{
printf("Line: [%s]\n", line);
sscanf(line,"%u", &id);
printf("id = %u\n", id);
}
return 0;
}
Note the diagnostic printing of the line just read. The code should really check the return value from sscanf(). (There was no virtue in skipping the trailing debris, so I removed that from the format string.)
Given the data file (data):
6067,UNKNOWN,2007-02-03 10:03:53.0,2007-01-02 02:54:13.0,12,6,0
29287,UNKNOWN,2007-02-03 21:11:07.0,2007-01-02 07:33:35.0,1,0,0
The output I get from so.37103830 < data is:
Line: [6067,UNKNOWN,2007-02-03 10:03:53.0,2007-01-02 02:54:13.0,12,6,0]
id = 6067
Line: [
]
id = 6067
Line: [29287,UNKNOWN,2007-02-03 21:11:07.0,2007-01-02 07:33:35.0,1,0,0]
id = 29287
Line: [
]
id = 29287
Avoiding the problem
The simplest fix is to use a longer buffer length; I normally use 4096 when I don't care about what happens if a really long line is read, but you might decide that 128 or 256 is sufficient.
Otherwise, I use POSIX getline() which will read arbitrarily long lines (subject to not running out of memory).
With a longer line length, I get the output:
Line: [6067,UNKNOWN,2007-02-03 10:03:53.0,2007-01-02 02:54:13.0,12,6,0
]
id = 6067
Line: [29287,UNKNOWN,2007-02-03 21:11:07.0,2007-01-02 07:33:35.0,1,0,0
]
id = 29287
Assuming you only need the first column from the file (since you mention node ids), you could use:
unsigned int node_id;
char str[100];
while(scanf("%u,%[^\n]",&node_id, str) == 2) {
printf("%u\n",node_id);
}
Demo
I have this code that is meant to read from a text file, store the information in a bin file and then read the information from the bin file and project it onto the screen.
I have the writing to the bin file all correct except when I go to print the tempStudents to the screen it always says the LAST option that is in the text file. So it's as if the only student it's saving is the last student.
#include<stdlib.h>
#include<stdio.h>
struct student {
char name[200];
float marks;
};
int main() {
FILE * txtFile;
struct student tempStudent;
// File pointer to binary file
FILE * binFile;
int searchNum;
if ((txtFile = fopen("/Users/Ash/Desktop/Lab 8B/input.txt", "r")) == NULL) {
printf("Can not open file input.txt\n");
}
else {
FILE * binFile;
binFile = fopen("/Users/Ash/Desktop/Lab 8B/binFile.bin","w+b");
while (fscanf(txtFile,"%s %f", tempStudent.name, &(tempStudent.marks)) == 2) {
fwrite(tempStudent.name,sizeof(char),sizeof(tempStudent.name),binFile);
fwrite(&tempStudent.marks,sizeof(int),1,binFile);
}
printf("Please enter the student you want to search for\n");
printf("For example if you want the first student type 1\n");
scanf("%d", &searchNum);
int i = 0;
for (i = 0; i <= searchNum; i++)
{
fread(tempStudent.name, 60, sizeof(char),binFile);
fread(&tempStudent.marks,60, sizeof(int),binFile);
}
// write code that reads in the student structure that the user asked for
// from the binary file and store it in the variable tempStudent
printf("The student name retreived is: %s\n", tempStudent.name);
printf("The student mark retreived is: %.2f\n", tempStudent.marks);
fclose(binFile);
fclose(txtFile);
}
return 0;
}
A file has something like a current position. After writing the binary data to the file this position is at the end. When you (try to) read the bin data in this state fread will read nothing.
Check the return values!
You are always searching one too far:
for (i = 0; i <= searchNum; i++)
if you want the first student (searchNum = 1), then you will in fact do two reads. Usually this gets you "one more than the value I intended to read".
More critically, if you are reading and writing from a file, you need to make sure you start at the right place. For this you have the fseek() function. Instead of doing lots of reads / writes, just make sure you are in the right place before reading or writing.
More importantly still, you seem to have variable length records for your name and marks - this makes the whole thing a giant mess. Some recommendations:
Make the record length constant - in this way you will be able to fseek to a particular record without having to read all the previous records first.
Be VERY CAREFUL about reading and writing to a file at the same time; consider first writing all the inputs to file, closing the file, then opening for reading
Make sure you read the right number of bytes... don't just hard wire "60".
Learn about fseek(). Google it.
You are writing 60*sizeof(int) bytes of data into a single float element:
struct student {
char name[200];
float marks;
};
struct student tempStudent;
fread(&tempStudent.marks,60,sizeof(int),binFile);
Surely you can't expect this code to work!!!
Im currently learning C through random maths questions and have hit a wall. Im trying to read in 1000 digits to an array. But without specifiying the size of an array first i cant do that.
My Answer was to count how many integers there are in the file then set that as the size of the array.
However my program returns 4200396 instead of 1000 like i hoped.
Not sure whats going on.
my code: EDIT
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
FILE* fp;
const char filename[] = "test.txt";
char ch;
int count = 0;
fp = fopen(filename, "r");
if( fp == NULL )
{
printf( "Cannot open file: %s\n", filename);
exit(8);
}
do
{
ch = fgetc (fp);
count++;
}while (ch != EOF);
fclose(fp);
printf("Text file contains: %d\n", count);
return EXIT_SUCCESS;
}
test.txt file:
731671765313306249192251196744265747423553491949349698352031277450632623957831801698480186947885184385861560789112949495459501737958331952853208805511
125406987471585238630507156932909632952274430435576689664895044524452316173185640309871112172238311362229893423380308135336276614282806444486645238749
303589072962904915604407723907138105158593079608667017242712188399879790879227492190169972088809377665727333001053367881220235421809751254540594752243
525849077116705560136048395864467063244157221553975369781797784617406495514929086256932197846862248283972241375657056057490261407972968652414535100474
821663704844031998900088952434506585412275886668811642717147992444292823086346567481391912316282458617866458359124566529476545682848912883142607690042
242190226710556263211111093705442175069416589604080719840385096245544436298123098787992724428490918884580156166097919133875499200524063689912560717606
0588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450
Any help would be great.
You forgot to initialize count, so it contains random garbage.
int count = 0;
(But note that with this change it's still not going to work, since %d in a scanf format means read as many digits as you find rather than read a single digit.)
Turn on your compiler's warnings (-Wall), it will tell you that you didn't initialize count, which is a problem: it could contain absolutely anything when your program starts.
So initialize it:
int count = 0;
The other problem is that the scanfs won't do what you want, at all. %d will match a series of digits (a number), not an individual digit. If you do want to do your counting like that, use %c to read individual characters.
Another approach typically used (as long as you know the file isn't being updated) is to use fseek/ftell to seek to the end of the file, get the position (wich will tell you its size), then seek back to the start.
The fastest approach though would be to use stat or fstat to get the file size information from the filesystem.
If you want number of digits thin you tave to do it char-by-char e.g:
while (isdigit(fgetc(file_decriptor))
count++;
Look up fgetc, getc and scanf in manpages, you don't seem to understand whats going on in your code.
The way C initializes values is not specified. Most of the time it's garbage. Your count variable it's not initialized, so it mostly have a huge value like 1243435, try int count = 0.