so sorry if I am a little confused.
I am trying to fill out an array of structs with values I read in from an input file. I am having no trouble reading in the values from the file. But when the file is very small and does not fill the array completely, the remaining structs have random values in them, and I would like to completely set these structs to NULL. I am attempting to do this because I would like to run through this filled out array of structs and print its values, and I need to see which array values are legitimately from the file.
Here is my code so far
struct function {
char name[20];
int parameterNumer;
};
int main(int argc, const char * argv[])
{
struct function functionList[10];
int i =0, j;
int portNumber;
char *configFile = argv[1];
FILE *fp;
fp = fopen(configFile, "r");
if(fp == NULL) {
perror("File not found");
exit(1);
}
fscanf(fp, "%d", &portNumber);
while(fscanf(fp, "%s %d", functionList[i].name, &functionList[i].parameterNumer) == 2) {
i++;
}
functionList[i] = NULL; //getting an error here
for(j = 0; functionList[j] != NULL; j++) { //and here
printf("%s %d", functionList[j].name, &functionList[j].parameterNumer);
}
return 0;
}
Initialize the array:
/* Remaining elements zero-d. */
struct function functionList[10] = { { "", 0 } };
if an empty string or a zero indicates an unpopulated entry in the array and then use either an empty string or zero int to terminate the for:
for(j = 0; strlen(functionList[j].name); j++) {
for(j = 0; functionList[j].parameterNumber; j++) {
Additionally, prevent out of bounds access on functionList in the while:
while(i < 10 && fscanf(fp,
"%s %d",
functionList[i].name,
&functionList[i].parameterNumer) == 2)
{
i++;
}
Note that the value of i after this while would also provide a terminating condition for the subsequent for loop:
for (j = 0; j < i; j++) {
You could create the array with a calloc()
struct function* functionList = calloc(sizeof(struct function), 10);
and change to this pointer where the array is referenced, in this way the struct is created with all zero in it.
You can also use memset:
memset(functionList, 0, sizeof(functionList));
Related
I have written a struct array to a binary file using this function:
int write_binary(const char* filename, const Product* shop)
{
FILE* OUT;
int jees = 0;
int i = 0;
OUT = fopen(filename, "wb");
if (!OUT) {
return 1;
}
while (jees == 0)
{
//the last element of the struct array has '\0' as the first char of its name
if (shop[i].name[0] == '\0')
{
jees = 1;
}
fwrite(&shop[i], sizeof (Product), 1, OUT) ;
i++;
}
fclose(OUT);
return 0;
}
Now I want to read it back into a struct array pointer. I have tried:
Product* read_binary(const char* filename)
{
FILE* IN = fopen(filename,"rb");
Product *shop;
for (int i = 0; i < 10; i++) {
fread(&shop[i], sizeof(Product), 1, IN);
}
fclose(IN);
return shop;
}
But this way doesn't seem to work. Is there a way to find out the how many structs are in the binary data?
Product *shop;
Here you are declaring a pointer, but you are not allocating memory for it. You should allocate with malloc() or do some static allocation.
To know the number of structs in the file, I'd seek to the end of it, count the bytes and divide by the size of the struct.
A side note: you don't need the jees variable. Just test the breaking condition after writing and break the loop explicitly:
for (i = 0; ; i++)
{
fwrite(&shop[i], sizeof (Product), 1, OUT);
if (shop[i].name[0] == '\0')
break;
}
struct reviewStruct {
char reviewer[50];
int feedback[3];
};
int readReviews(FILE *file, struct reviewStruct reviews[10]) {
int i;
file = fopen("reviews.txt", "r");
if (file == NULL) {
printf("Error");
exit(-1);
}
for(i = 0; i < 10; i++) {
fgets(reviews[i], 50, file);
}
return 0;
fclose(file);
for(i = 0; i < 10; i++) {
printf("%s", reviews[i]);
}
}
I'm trying to populate "struct reviewStruct reviews[10]" with information from a text file called "reviews.txt" I keep getting an error that says, "error: incompatible type for argument 1 of ‘fgets’" I'm not sure how to fix this, the output should be in the form \n \n and so on... How do I do this?
fgets(reviews[i], 50, file); -> fgets(reviews[i].reviewer, 50, file);
printf("%s", reviews[i]); -> printf("%s", reviews[i].reviewer);
The declaration struct reviewStruct reviews[10] in the readReviews function declaration is creating an array of structs. in this call: fgets(reviews[i], 50, file);, you are passing a specific struct to fgets() which expects to be passed a string. Actually, you want to pass a certain element of the struct. Use the dot (.) operator to access a struct's element. I assume you want your code to look like this:
struct reviewStruct {
char reviewer[50];
int feedback[3];
};
int readReviews(FILE *file, struct reviewStruct reviews[10]) {
int i;
file = fopen("reviews.txt", "r");
if (file == NULL) {
printf("Error");
exit(-1);
}
for(i = 0; i < 10; i++) {
fgets(reviews[i].reviewer, 50, file);
}
return 0;
fclose(file);
for(i = 0; i < 10; i++) {
printf("%s", reviews[i].reviewer);
}
}
I just replaced reviews[i] with reviews[i].reviewer to pass the reviewer string to the functions as opposed to the whole struct.
I'm currently writing a program that is doing what is a simple task; read a file line by line, parse it, and store the results into an array where the structure would be array[lineNumber][lineElement]. And for the most part, it's working, except for one odd issue that I've ran into.
In the code below, any access to the array that is housing the data outside of the while loop that's populating it, only returns the last entry. This occurs regardless of the key for lineNumber. Basically it acts like it's overwriting, even though within the while loop its accessible just fine. The only two items that I think could be at fault I've outlined in bold, although for char *processData[100];, it shouldn't be an issue as it's stored within an array that's declared outside the while loop (and if I remember right while loops shouldn't have scope?), and the other line **char **processArray[100];
**, it might be the double star for an array of pointers, but returning that to just one star introduces a whole wave of bugs, namely the aforementioned array structure breaks completely.
So in a nutshell, not being a C expert by any means and exhausting my resources for this issue, I wonder if the C coders here might have some advice as to what the heck is going on, and how I can get this to work as intended....if I even can.
As mentioned previously, the code.
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
FILE *ifp;
char line[80];
int returnValue = 0;
//Open file
ifp = fopen("dataFile", "rt");
if (ifp == NULL) {
fprintf(stderr, "Can't open input file!\n");
returnValue = 1;
}
int lineCounter = 0;
char **processArray[100];
while(fgets(line, 80, ifp) != NULL) {
char *processData[100];
char *p = strtok(line, " ,\n");
int keyCounter = 0;
while (p != NULL) {
processData[keyCounter] = p;
p = strtok(NULL, " ,\n");
keyCounter++;
}
processArray[lineCounter] = processData;
printf("%d\n", lineCounter);
printf("Inside -> %s\n", processArray[0][0]);
lineCounter++;
}
printf("Outside %s\n", processArray[0][0]);
fclose(ifp);
int i;
int j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
printf("%d-%d => %s\n ", i, j, processArray[i][j]);
}
}
return returnValue;
}
[Just about] everything gets overwritten on the outer while loop, so only the last processed line remains. The intermediate results must be preserved
I've fixed the program with annotations as to the bugs. The style is #if 0 /* original code */ #else /* fixed code */ #endif
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(void)
{
FILE *ifp;
char line[80];
int returnValue = 0;
//Open file
ifp = fopen("dataFile", "rt");
if (ifp == NULL) {
fprintf(stderr, "Can't open input file!\n");
returnValue = 1;
}
int lineCounter = 0;
char **processArray[100];
// NOTE/BUG: things get lost on each iteration of this loop
while(fgets(line, 80, ifp) != NULL) {
char *processData[100];
char *p = strtok(line, " ,\n");
int keyCounter = 0;
while (p != NULL) {
// NOTE/BUG: p will get overwritten -- so we must save the string
#if 0
processData[keyCounter] = p;
#else
processData[keyCounter] = strdup(p);
#endif
p = strtok(NULL, " ,\n");
keyCounter++;
}
// NOTE/BUG: processData must be duplicated -- it is overwritten
// on the outer loop
#if 0
processArray[lineCounter] = processData;
#else
char **pA = malloc(sizeof(char *) * keyCounter);
processArray[lineCounter] = pA;
for (int copyidx = 0; copyidx < keyCounter; ++copyidx)
pA[copyidx] = processData[copyidx];
#endif
printf("%d\n", lineCounter);
printf("Inside -> %s\n", processArray[0][0]);
lineCounter++;
}
printf("Outside %s\n", processArray[0][0]);
fclose(ifp);
int i;
int j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
printf("%d-%d => %s\n ", i, j, processArray[i][j]);
}
}
return returnValue;
}
processData is being allocated on the stack and the memory address is not valid after you leave the while loop, regardless of you storing it in processArray. You need to allocate from the heap instead (using malloc or some other memory allocation function)
this is an assignment for my CS course,
im trying to write a code that reads a file line by line and put the input into a struct element.the struct looks like this:
typedef char* Name;
struct Room
{
int fStatus;
Name fGuest;
};
the status is 0 for available and 1 for booked. the name will be empty if the room is available.
there are 2 function, one to read and put the values to a struct element, and the other one to print it out.
int openRoomFile()
{
FILE *roomFile;
char *buffer = NULL;
size_t length = 0;
size_t count = 0;
roomFile = fopen("roomstatus.txt", "r+");
if (roomFile == NULL)
return 1;
while (getline(&buffer, &length, roomFile) != -1) {
if (count % 2 == 0) {
sscanf(buffer, "%d", &AllRooms[count].fStatus);
} else {
AllRooms[count].fGuest = buffer;
}
count++;
}
fclose(roomFile);
free(buffer);
return 0;
}
print function
void printLayout(const struct Room rooms[])
{
for (int i=0; i<3; i++) {
printf("%3d \t", rooms[i].fStatus);
puts(rooms[i].fGuest);
}
}
the output is not what i expected, given the input file is :
1
Johnson
0
1
Emilda
i will get the output :
1 (null)
0
0 (null)
i dont know what went wrong, am i using the right way to read the file? every code is adapted from different sources on the internet.
Here is a fixed version of the openRoomFile()
int openRoomFile(void)
{
FILE *roomFile;
char *buffer = NULL;
size_t length = 0;
size_t count = 0;
roomFile = fopen("roomstatus.txt", "r+");
if (roomFile == NULL)
return 1;
while (1) {
buffer = NULL;
if (getline(&buffer, &length, roomFile) == -1) {
break;
}
sscanf(buffer, "%d", &AllRooms[count].fStatus);
free(buffer);
buffer = NULL;
if (getline(&buffer, &length, roomFile) == -1) {
fprintf(stderr, "syntax error\n");
return 1;
}
AllRooms[count].fGuest = buffer;
count++;
}
fclose(roomFile);
return 0;
}
When you no longer need those fGuest anymore, you should call free on them.
If your input is guaranteed to be valid (as were many of my inputs in my CS classes), I'd use something like this for reading in the file.
while(!feof(ifp)){
fscanf(ifp,"%d%s",&AllRooms[i].fStatus, AllRooms[i].fGuest); //syntax might not be right here
//might need to play with the '&'s
//and maybe make the dots into
//arrows
//do work here
i++;
}
You are not allocating memory for Name. Check this. In the below example i'm not included free() calls to allocated memory. you need to call free from each pointer in AllRooms array, once you feel you are done with those and no more required.
#include<stdio.h>
#include<stdlib.h>
typedef char* Name;
struct Room
{
int fStatus;
Name fGuest;
}Room_t;
struct Room AllRooms[10];
int openRoomFile()
{
FILE *roomFile;
char *buffer = NULL;
size_t length = 0;
size_t count = 0;
size_t itemCount = 0;
roomFile = fopen("roomstatus.txt", "r+");
if (roomFile == NULL)
return 1;
buffer = (char *) malloc(16); // considering name size as 16 bytes
while (getline(&buffer, &length, roomFile) != -1) {
if (count % 2 == 0) {
sscanf(buffer, "%d", &AllRooms[itemCount].fStatus);
} else {
AllRooms[itemCount].fGuest = buffer;
itemCount++;
}
count++;
buffer = (char *) malloc(16); // considering name size as 16 bytes
}
fclose(roomFile);
free(buffer);
return 0;
}
void printLayout(const struct Room rooms[])
{
int i;
for (i=0; i<3; i++) {
printf("%3d \t", rooms[i].fStatus);
puts(rooms[i].fGuest);
}
}
int main(void)
{
openRoomFile();
printLayout(AllRooms);
// free all memory allocated using malloc()
return 0;
}
I need to put a string (from a file) in a matrix and print out the result. I have some issue in understanding the right way to do this so:
#include <stdio.h>
#include <string.h>
int main (int argc, char *argv[])
{
const int MAX = 50;
char mat[MAX][MAX];
char str[MAX];
char word[MAX];
int row = 0;
int i = 0;
FILE * fp;
fp = fopen ("file.txt", "r");
if (fp == NULL)
printf ("Error!\n");
while (fgets(str, MAX, fp) != NULL)
{
sscanf (str, "%s\n", word);
strcpy(mat[i][0], word);
row++;
}
for (i = 0; i <= row; i++)
{
puts(mat[i][0]);
}
return 0;
}
I'm obliviously doing something wrong but... what?
I have a file like this:
One
Two
Three
Four
Five
Six
Hello
If you compile this with gcc, it will give you two warnings: each warning points to one of the three major errors in the code:
main.c: In function 'main':
main.c:24: warning: passing argument 1 of 'strcpy' makes pointer from integer without a cast
main.c:31: warning: passing argument 1 of 'puts' makes pointer from integer without a cast
Each of those line numbers -- 24 and 31 -- is a line where you're using mat[i][0], which is a character, when you should instead use mat[i], which is a character array. Fix those, and then there's just one problem: you use i, which is always 0, in the while loop. Use row, which is incremented as the row progresses, and the program should work exactly as designed.
There are a couple of other things I would change to improve the program: your while loop reads a string into one buffer, copies it into a second buffer, then copies it into the matrix; you could just scan it directly into the matrix and be done with it!
A matrix usually contains numbers. Yours contains chars. There are problems with your code but to get a good answer you should tell us the format of the file you are reading (maybe paste a small one in your question).
EDIT:
This file contains an array of strings separated by newline. You can read it like this (if the strings don't have any whitespace in them):
while (fscanf(fp, "%s\n", mat[row]) > 0)
{
row++;
}
for (i = 0; i <= row; i++)
{
printf( "%s\n", mat[i]);
}
You should copy the string to the element of matrix with the given index. You should pass the pointer to the first element of matrix to strcpy(i.e. remove the [0]).
Do something like:
while (fgets(str, MAX, fp) != NULL)
{
sscanf (str, "%s\n", word);
strcpy(mat[i], word);
row++;
}
EDIT: also when printing the strings use only mat[i] not mat[i][0].
I have done some changes to your code. First lets pin point your mistakes.
char mat[MAX][MAX]; will not serves your intention of creating string matrix.
It is unnecessary to do read sscanf (str, "%s\n", word);. Already you read it from file. you can directly use it.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
const int MAX = 50;
char *mat[MAX][MAX];
char str[MAX];
int i = 0, j = 0;
int now = 0;
FILE * fp;
fp = fopen ("file.txt", "r");
if (fp == NULL)
printf ("Error!\n");
while (fgets(str, MAX, fp) != NULL)
{
//sscanf (str, "%s\n", word);
mat[i][j] = malloc(sizeof(str));
strcpy(mat[i][j], str);
j++;
now++; //Tracks no.of elements
if(j == MAX)
{
j = 0;
i++; //store in next row
}
}
for (i = 0; i < MAX; i++)
for (j = 0; j < MAX; j++)
{
if(now == 0)
break;
now--;
puts(mat[i][j]);
free(mat[i][j]);//Avoids memory leak
}
return 0;
}