I’m trying to program a HMI console to read a file from an USB pen drive and display its data on the screen. This is a csv file and the objective is to store the interpreted data to HMI console memory, which the HMI console later interprets. The macros on these consoles run in C (not C++).
I have no issue with both reading and interpreting the file, the issue that the existing function (not accessible to me, shown below) to write in the console memory only interprets char.
int WriteLocal( const char *type, int addr, int nRegs, void *buf , int flag );
Parameter: type is the string of "LW","LB" etc;
address is the Operation address ;
nRegs is the length of read or write ;
buf is the buffer which store the reading or writing data
flag is 0,then codetype is BIN,is 1 then codetype is BCD;
return value : 1 , Operation success
0 , Operation fail.
As my luck would have it I need to write integer values. What are available to me are the variables for each memory position. These are preexisting and are named individually such as:
int WR_LW200;
int WR_LW202;
int WR_LW204;
...
int WR_LW20n;
Ideally we could have a vector with all the names of the variables but unfortunately this is not possible. I could manually write every single variable but I need to do 300 of these…
must be a better way, right?
Just to give you a look on how it ended up looking:
int* arr[50][5] = { {&WR_LW200, &WR_LW400, &WR_LW600, &WR_LW800, &WR_LW1000},
{&WR_LW202, &WR_LW402, &WR_LW602, &WR_LW802, &WR_LW1002},
{&WR_LW204, &WR_LW404, &WR_LW604, &WR_LW804, &WR_LW1004},
{&WR_LW206, &WR_LW406, &WR_LW606, &WR_LW806, &WR_LW1006},
{&WR_LW208, &WR_LW408, &WR_LW608, &WR_LW808, &WR_LW1008},
{&WR_LW210, &WR_LW410, &WR_LW610, &WR_LW810, &WR_LW1010},
{&WR_LW212, &WR_LW412, &WR_LW612, &WR_LW812, &WR_LW1012},
{&WR_LW214, &WR_LW414, &WR_LW614, &WR_LW814, &WR_LW1014},
{&WR_LW216, &WR_LW416, &WR_LW616, &WR_LW816, &WR_LW1016},
{&WR_LW218, &WR_LW418, &WR_LW618, &WR_LW818, &WR_LW1018},
{&WR_LW220, &WR_LW420, &WR_LW620, &WR_LW820, &WR_LW1020},
{&WR_LW222, &WR_LW422, &WR_LW622, &WR_LW822, &WR_LW1022},
{&WR_LW224, &WR_LW424, &WR_LW624, &WR_LW824, &WR_LW1024},
{&WR_LW226, &WR_LW426, &WR_LW626, &WR_LW826, &WR_LW1026},
{&WR_LW228, &WR_LW428, &WR_LW628, &WR_LW828, &WR_LW1028},
{&WR_LW230, &WR_LW430, &WR_LW630, &WR_LW830, &WR_LW1030},
{&WR_LW232, &WR_LW432, &WR_LW632, &WR_LW832, &WR_LW1032},
{&WR_LW234, &WR_LW434, &WR_LW634, &WR_LW834, &WR_LW1034},
{&WR_LW236, &WR_LW436, &WR_LW636, &WR_LW836, &WR_LW1036},
{&WR_LW238, &WR_LW438, &WR_LW638, &WR_LW838, &WR_LW1038},
{&WR_LW240, &WR_LW440, &WR_LW640, &WR_LW840, &WR_LW1040},
{&WR_LW242, &WR_LW442, &WR_LW642, &WR_LW842, &WR_LW1042},
{&WR_LW244, &WR_LW444, &WR_LW644, &WR_LW844, &WR_LW1044},
{&WR_LW246, &WR_LW446, &WR_LW646, &WR_LW846, &WR_LW1046},
{&WR_LW248, &WR_LW448, &WR_LW648, &WR_LW848, &WR_LW1048},
{&WR_LW250, &WR_LW450, &WR_LW650, &WR_LW850, &WR_LW1050},
{&WR_LW252, &WR_LW452, &WR_LW652, &WR_LW852, &WR_LW1052},
{&WR_LW254, &WR_LW454, &WR_LW654, &WR_LW854, &WR_LW1054},
{&WR_LW256, &WR_LW456, &WR_LW656, &WR_LW856, &WR_LW1056},
{&WR_LW258, &WR_LW458, &WR_LW658, &WR_LW858, &WR_LW1058},
{&WR_LW260, &WR_LW460, &WR_LW660, &WR_LW860, &WR_LW1060},
{&WR_LW262, &WR_LW462, &WR_LW662, &WR_LW862, &WR_LW1062},
{&WR_LW264, &WR_LW464, &WR_LW664, &WR_LW864, &WR_LW1064},
{&WR_LW266, &WR_LW466, &WR_LW666, &WR_LW866, &WR_LW1066},
{&WR_LW268, &WR_LW468, &WR_LW668, &WR_LW868, &WR_LW1068},
{&WR_LW270, &WR_LW470, &WR_LW670, &WR_LW870, &WR_LW1070},
{&WR_LW272, &WR_LW472, &WR_LW672, &WR_LW872, &WR_LW1072},
{&WR_LW274, &WR_LW474, &WR_LW674, &WR_LW874, &WR_LW1074},
{&WR_LW276, &WR_LW476, &WR_LW676, &WR_LW876, &WR_LW1076},
{&WR_LW278, &WR_LW478, &WR_LW678, &WR_LW878, &WR_LW1078},
{&WR_LW280, &WR_LW480, &WR_LW680, &WR_LW880, &WR_LW1080},
{&WR_LW282, &WR_LW482, &WR_LW682, &WR_LW882, &WR_LW1082},
{&WR_LW284, &WR_LW484, &WR_LW684, &WR_LW884, &WR_LW1084},
{&WR_LW286, &WR_LW486, &WR_LW686, &WR_LW886, &WR_LW1086},
{&WR_LW288, &WR_LW488, &WR_LW688, &WR_LW888, &WR_LW1088},
{&WR_LW290, &WR_LW490, &WR_LW690, &WR_LW890, &WR_LW1090},
{&WR_LW292, &WR_LW492, &WR_LW692, &WR_LW892, &WR_LW1092},
{&WR_LW294, &WR_LW494, &WR_LW694, &WR_LW894, &WR_LW1094},
{&WR_LW296, &WR_LW496, &WR_LW696, &WR_LW896, &WR_LW1096},
{&WR_LW298, &WR_LW498, &WR_LW698, &WR_LW898, &WR_LW1098} };
Big right? I had consurns that this HMI would have issues with such an approach but it did the job. The code below runs trough a string that comes from the csv file. This code runs inside another while cycle to cycle trough the multi dimensional array.
it's a little crude but works.
while (i<=5)
{
memset(lineTemp, 0, sizeof lineTemp); // clear lineTemp array
while (lineFromFile[index] != delimiter)
{
if (lineFromFile[index] != delimiter && lineFromFile[index] != '\0') { lineTemp[j] = lineFromFile[index]; index++; j++; }
if (lineFromFile[index] == '\0') { i = 5; break; }
}
index++;
lineTemp[j] = '\0'; // NULL TERMINATION
j = 0;
if (i == -1) { WriteLocal("LW",temp,3,lineTemp,0); }
if (i >= 0 && i<=5) { *(arr[x][i]) = atoi(lineTemp); }
i++;
}
Thanks again for the tip.
Cheers
I am making a quiz program in c for a school project.I was storing question and answers in a text file.The text file contains 1 question and followed by 4 choices and a correct answer(each in a new line) and so on.The code for file handling is
#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<process.h>
void main()
{
int tnum=2,mnum;
printf("Enter a file name to load the quiz from or enter dhruv.txt to load the default file\n");
printf("(For type of file and arrangement of data in it, refer to the documentation\n");
printf("WARNING: An improper quiz file may result in malfunctioning of the program.\n");
char quizfile[100];
scanf("%s",quizfile);
FILE *dj;
dj = fopen(quizfile,"r");
int test = 1;
while(dj == NULL)
{
printf("Requested file does not exist.Please enter a valid name\n");
scanf("%s",quizfile);
dj = fopen(quizfile,"r");
test++;
if(test == 5)
{
exit(0);
}
}
char line[500];
char ques[20][500],ansa[20][500],ansb[20][500],ansc[20][500],ansd[20][500],anse[20][500];
int start = 1,quesval=1,ans1=1,ans2=1,ans3=1,ans4=1,ans5=1;
while(fgets(line,sizeof line,dj) != NULL)
{
if((start%6) == 1)
{
strcpy(ques[quesval],line);
quesval++;
}
if((start%6) == 2)
{
strcpy(ansa[ans1],line);
ans1++;
}
if((start%6) == 3)
{
strcpy(ansb[ans2],line);
ans2++;
}
if((start%6) == 4)
{
strcpy(ansc[ans3],line);
ans3++;
}
if((start%6) == 0)
{
strcpy(anse[ans5],line);
ans5++;
}
if((start%6) == 5)
{
strcpy(ansd[ans4],line);
ans4++;
}
start++;
}
fclose(dj);
printf("Quiz file successfully loaded\n");
printf("/t/t WELCOME TO THE QUIZ\n\n");
printf("Every team must select one of the four correct answers to the asked questions to gain points\n");
printf("Wrong answer will not be penalized\n");
for(int k =1;k<quesval;k++)
{
int myvar;
myvar = k%tnum;
if(myvar == 0)
{
myvar = tnum;
}
printf("Question for TEAM %d\n\n",myvar);
printf("%s \n A.%s B.%s C.%s D.%s\n",ques[k],ansa[k],ansb[k],ansc[k],ansd[k]);
}
getch();
}
The problem is
if((start%6) == 0)
{
strcpy(anse[ans5],line);
ans5++;
}
The program shows File does not exist if i use this but as soon as i comment it out the program works fine.I don't know what the error is.Please do help
EDIT:My text file looks like:
Who is the owner
dhruv
jain
kalio
polika
dhruv
who is his friend
sarika
katrina
jen
aarushi
aarushi
where is he
home
office
college
toilet
office
where will he go
home
office
college
toilet
home
EDIT
I am using Turbo c++ in windows 7 using DOSBOX..The script is updated above
It's difficult to say without seeing your input file, but I suspect that your array declarations are backwards. For example, you have:
char ques[500][20];
This declares an array of 500 elements, where each element can be up to 20 characters. You probably want:
char ques[20][500];
This declares an array of 20 elements, where each element can be up to 500 characters.
If your input file contains lines longer than 20 characters, then your current code is likely overwriting your arrays.
There are several problems here but your immediate problem is this:
strcpy(anse[ans5],line);
(And all the other strcpy calls like it.)
You are copying line to the array beginning at anse[1][0]. If line contains more than 20 characters, it will overwrite memory past the end of anse. For example, if line contains 25 characters, you'll be putting it in anse[1][0] through anse[1][24]. Unfortunately anse[1][24] does not exist because anse is only 20 characters long. If any question exceeds 20 characters, you'll be corrupting memory and possibly causing a crash. Let me guess: Question 5 is longer than 19 characters, right?
In short, you have your rows and columns mixed up in your declarations. I think you wanted to allow 20 questions of 500 characters each, but you're actually allowing 500 questions of 20 characters each.
Next problem: In C, arrays are zero-based, not one-based. The first string in ques, for example, is ques[0], not ques[1].
To simplify this, think of two-dimensional arrays as a table composed of rows and columns. For example, declare a 3x4 array named foo:
char foo[3][4];
Picture it like this:
0 1 2 3
0 . . . .
1 . . . .
2 . . . .
What I have is an array of three character strings, each 4 characters long. The first string in my array is at foo[0]. The first character of the first string is at foo[0][0]. The second character is at foo[0][1], the second character of the third string is foo[2][1], and so on.
To solve this, your declarations should look like this:
char ques[20][500],ansa[20][500],ansb[20][500],ansc[20][500],ansd[20][500],anse[20][500];
int start = 1,quesval=0,ans1=0,ans2=0,ans3=0,ans4=0,ans5=0;
When you get it working, you should then ask yourself why you're testing the value of start six times each pass through the loop when it only changes once. There's a much better solution available here. Consider a three-dimensional array like this:
char answers[20][500][5];
That gives you 20 questions with 5 answers each.
I'm doing a read from a file, but the input seems to "overflow" into other variables.
I have these 2 variables:
char str[250]; //used to store input from stream
char *getmsg; //already points to some other string
The problem is, when I use fgets() to read the input
printf("1TOKEN:%s\n",getmsg);
fp=fopen("m.txt","r");
fp1=fopen("m1.txt","w");
if(fp!=NULL && fp1!=NULL)
printf("2TOKEN:%s\n",getmsg);
while(fgets(str,250,fp)!=NULL){
printf("3TOKEN:%s\n",getmsg);
printf("read:%s",str);
printf("4TOKEN:%s\n",getmsg);
I get something like this:
1TOKEN:c
2TOKEN:c
3TOKEN:b atob atobbody
read:a b atob atobbody
4TOKEN:b atob atobbody
You see how str kind of flows into getmsg. What happened there? How can I avoid this from happening?
Thanks in advance :)
in the code, "getmsg" is called "token", I thought it might have something to do with identical names or something so I changed it to getmsg, same error, so I changed it back...
if(buf[0]=='C'){
int login_error=1;
fp=fopen("r.txt","r");
if(fp!=NULL){
memcpy(&count,&buf[1],2);
pack.boxid=ntohs(count);
memcpy(pack.pword,&buf[3],10);
printf("boxid:%u pword:%s\n",pack.boxid,pack.pword);
while(fgets(str,250,fp)!=NULL){
/*"getmsg"===>*/ token=strtok(str," ");
token=strtok(NULL," ");//receiver uname
token1=strtok(NULL," ");//pword
token2=strtok(NULL," ");//boxid
sscanf(token2,"%hu",&count);//convert char[] to unsigned short
if(pack.boxid==count && strcmp(token1,pack.pword)==0){//uname & pword found
login_error=0;
printf("found:token:%s\n",token);
break;
}
}
if(login_error==1){
count=65535;
pack.boxid=htons(count);
}
if(login_error==0){
count=0;
pack.boxid=htons(count);
}
fclose(fp);
}
printf("1TOKEN:%s\n",token);
if(login_error==0){
int msg_error=1;
fp=fopen("m.txt","r");
fp1=fopen("m1.txt","w");
if(fp!=NULL && fp1!=NULL){
printf("2TOKEN:%s\n",token);
while(fgets(str,250,fp)!=NULL){
printf("3TOKEN:%s\n",token);
printf("read:%s",str);
token1=strtok(str," ");//sender
token2=strtok(NULL," ");//receiver
token3=strtok(NULL," ");//subject
token4=strtok(NULL," ");//body
printf("m.txt:token1:%s token2:%s token3:%s token4:%s\n",token1,token2,token3,token4);
if(msg_error==1 && strcmp(token,token2)==0){//message found
msg_error=0;
count=0;
pack.boxid=htons(count);
strcpy(pack.uname,token1);
strcpy(pack.subject,token3);
strcpy(pack.body,token4);
printf("pack:uname:%s subject:%s body:%s token:%s token2:%s strcmp:%d\n",pack.uname,pack.subject,pack.body,token,token2,strcmp(token,token2));
continue;
}
fprintf(fp1,"%s %s %s %s\n",token1,token2,token3,token4);
}
if(msg_error==1){
count=65534;
pack.boxid=htons(count);
}
printf("count:%u -> boxid:%u\n",count,pack.boxid);
fclose(fp);
fclose(fp1);
}
str[0]='c';
memcpy(&str[1],&pack.boxid,2);
memcpy(&str[3],pack.uname,8);
memcpy(&str[11],pack.subject,20);
memcpy(&str[31],pack.body,200);
str[231]='\0';
bytes=232;
}
}
below is m.txt, it is used to store senders, receivers, subjects and msgbodies:
the naming patter is quite obvious >.^
a b atob atobbody
a c atoc atoccc
b c btoc btoccccc
b a btoa btoaaaaa
So I'm trying to get a msg stored in m.txt for the recipient "c", but it flows over, and by much coincidence, it returns the msg for "b"...
It looks like getmsg is pointing to the third character of your str buffer:
`str` is "a b atob atobbody"
^
|
\__ `getmsg` is pointing there.
Therefore, every time you change str by calling fgets(), the string pointed to by getmsg also changes, since it uses the same memory.
I'm making a small console-based rpg, to brush up on my programming skills.
I am using structures to store character data. Things like their HP, Strength, perhaps Inventory down the road. One of the key things I need to be able to do is load and save characters. Which means reading and saving structures.
Right now I'm just saving and loading a structure with first name and last name, and attempting to read it properly.
Here is my code for creating a character:
void createCharacter()
{
char namebuf[20];
printf("First Name:");
if (NULL != fgets(namebuf, 20, stdin))
{
char *nlptr = strchr(namebuf, '\n');
if (nlptr) *nlptr = '\0';
}
strcpy(party[nMember].fname,namebuf);
printf("Last Name:");
if (NULL != fgets(namebuf, 20, stdin))
{
char *nlptr = strchr(namebuf, '\n');
if (nlptr) *nlptr = '\0';
}
strcpy(party[nMember].lname,namebuf);
/*Character created, now save */
saveCharacter(party[nMember]);
printf("\n\n");
loadCharacter();
}
And here is the saveCharacter function:
void saveCharacter(character party)
{
FILE *fp;
fp = fopen("data","a");
fwrite(&party,sizeof(party),1,fp);
fclose(fp);
}
and the loadCharacter function
void loadCharacter()
{
FILE *fp;
character tempParty[50];
int loop = 0;
int count = 1;
int read = 2;
fp= fopen("data","r");
while(read != 0)
{
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
loop++;
count++;
}
fclose(fp);
}
So the expected result of the program is that I input a name and last name such as 'John Doe', and it gets appended to the data file. Then it is read in, maybe something like
1. Jane Doe
2. John Doe
and the program ends.
However, my output seems to add one more blank structure to the end.
1. Jane Doe
2. John Doe
3.
I'd like to know why this is. Keep in mind I'm reading the file until fread returns a 0 to signify it's hit the EOF.
Thanks :)
Change your loop:
while( fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp) )
{
// other stuff
}
Whenever you write file reading code ask yourself this question - "what happens if I read an empty file?"
You have an algorithmic problem in your loop, change it to:
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
while(read != 0)
{
//read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
loop++;
count++;
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
}
There are ways to ged rid of the double fread but first get it working and make sure you understand the flow.
Here:
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
You are not checking whether the read was successful (the return value of fread()).
while( 1==fread(&tempParty[loop],sizeof*tempParty,1,fp) )
{
/* do anything */
}
is the correct way.
use fopen("data","rb")
instead of fopen("data","r") which is equivalent to fopen("data","rt")
You've got the answer to your immediate question but it's worth pointing out that blindly writing and reading whole structures is not a good plan.
Structure layouts can and do change depending on the compiler you use, the version of that compiler and even with the exact compiler flags used. Any change here will break your ability to read files saved with a different version.
If you have ambitions of supporting multiple platforms issues like endianness also come into play.
And then there's what happens if you add elements to your structure in later versions ...
For robustness you need to think about defining your file format independently of your code and having your save and load functions handle serialising and de-serialising to and from this format.