问题
this function will rewind file, create the dynamic array (of size), and read in the data, populating the _data struct dynamic array. Note that stream is passed by value this time. The function then returns the populated array of struct
struct _data
{
char* name;
long number;
};
struct _data *load(FILE *stream, int size)
{
struct _data BlackBox = calloc(size, sizeof(_data));
char tempName[3];
stream = fopen("names.txt", "r");
for (int i=0; i<size; i++)
{
fscanf(stream, "%s %ld", tempName, &data.number);
BlackBox[i].name = calloc(strlen(tempName), sizeof(char));
strcpy(BlackBox[i].name, tempName);
}
fclose(stream);
return &BlackBox;
}
File Content
ron 7774013
jon 7774014
I am a beginner and having difficulty designing the code. Can someone please explain. Thanks
回答1:
I think you have some warning from gcc to help you.
Fix memory management with your calloc, and don't return a stack pointer
typedef struct _data
{
char* name;
long number;
} _data;
_data *load(FILE *stream, int size)
{
_data *BlackBox = calloc(size, sizeof(_data));
char tempName[3];
for (int i=0; i<size; i++)
{
fscanf(stream, "%s %ld", tempName, &BlackBox[i].number);
BlackBox[i].name = strdup(tempName);
}
fclose(stream);
return BlackBox;
}
int main (void)
{
FILE *f = fopen("test.data", "r");
_data *data = load(f, 2);
printf("%s %ld\n", data[0].name, data[0].number);
printf("%s %ld\n", data[1].name, data[1].number);
return 0;
}
output
aurel@vm-pontarlier:~$ ./a.out
ron 7774013
jon 7774014
Think about change _data
typedef struct _data{
char name[256];
long number;
} _data;
scan will be:
for (int i=0; i<size; i++)
{
fscanf(stream, "%s %ld", BlackBox[i].name, &BlackBox[i].number);
}
回答2:
You are making the same arrors as with your previous post. You also don't allocate memory for the name member in _data. As for the compilation errors:
- Arrays of type
Tthat you allocate dynamically withmallocorcallocare controlled by a handle, a pointer toTof typeT*. - The structure you defined is of type
struct _data, the type includes the keywordstruct. If you want a one-word identifier for your type, use `typedef´ as Ôrel has shown you. - You have no variable called ´data
. The handle to the newly allocated memory is ´BlackBox.
If you fix these errors, you will run into logical errors that the compiler cannot know about:
- Your
BlackBox[i].nameis initialised toNULLviacalloc, so it doesn't point to valid memory. You cannotstrcpyanything into it. What you can do is to use the non-standard, but widely availablestrdup, which first allocates memory as required and then copies. - Your temporary string is of length 3; it can hold at most two characters plus the null terminator. The names in your file are short, granted, but your program must prepare for any input, even illegal input.
- The
FILE *isn't used outside your function; it should be local toload. - The user must specify how many items to read. This defies the purpose of dynamic allocation. Also the user can't know how many items were read; there might be fewer items in the file as requested. Your function design should reflect that. (Okay, thst's not really true: You zero-initialise the memory, which means a char pointer of
NULLsignals the end of the array, but:) - You don't test the output of
fscanf, which you should. If your file has fewer thansizeitems, the last items will contain garbage, because you copy garbage values into the zero initialised memory. - Not an error per se, but if your file is organised along lines, consider reading a line with
fgetsfirst and then parsing that withsscanf.
The example code below tries to incorporate these guidelines. Things to note:
- The memory isn't allocated in one huge chunk, but it grows as needed with subsequent calls to
realloc. The callrealloc(NULL, s)is equivalent tomalloc(s). - The functions "fills in" the number of elementsread via a pointer to an integer.
- The strings are copied into newly allocated memory. That means that in theory, the strings can e as long as they want. (In practice, the max buffer length of 20 cuts such strings short.) The function
duplicateemulates the functionstrdup. - These strings should be
freed when cleaning up. - The
loadfunction takes a filename istead of a file handle. - File reading takes place in two stages: Read a line first, then scan this line. If the format is not "string without spaces" + "number", an error message is written.
Anyway, here goes:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct _data
{
char *name;
long number;
};
/*
* Duplicate a string on the heap (aka strdup)
*/
char *duplicate(const char *str)
{
char *p = malloc(strlen(str) + 1);
strcpy(p, str);
return p;
}
/*
* Read a list of names from file fn
*/
struct _data *load(const char *fn, int *psize)
{
struct _data *data = NULL;
FILE *stream;
char line[80]; // buffer for line
int lnr = 0; // line number for error message
int n = 0; // number of read items
stream = fopen("names.txt", "r");
if (stream == NULL) return NULL; // Can't open file
while (fgets(line, sizeof(line), stream)) {
long int number;
char buf[20];
lnr++;
if (sscanf(line, "%19s %ld", buf, &number) == 2) {
data = realloc(data, (n + 1) * sizeof(*data));
data[n].number = number;
data[n].name = duplicate(buf);
n++;
} else {
fprintf(stderr, "[%s, line %d] Illegal format\n", fn, lnr);
}
}
fclose(stream);
*psize = n; // Assign number of read items
return data;
}
/*
* Free memory allocated by load
*/
void cleanup(struct _data *data, int n)
{
while (n--) free(data[n].name);
free(data);
}
int main()
{
struct _data *data;
int i, n;
data = load("names.txt", &n);
if (data == NULL) return -1;
for (i = 0; i < n; i++) {
printf("%-20s%12ld\n", data[i].name, data[i].number);
}
cleanup(data, n);
return 0;
}
回答3:
...and lastly tempName[3] is too small: it must be at least 4, given your 3 letter inputs. Further, you forget to allocate room for the terminating null character in your malloc call:
char tempName[4];
...
BlackBox[i].name = malloc(strlen(tempName)+1);
(That tempName[3] did not lead to errors is because the compiler probably rounded it up to an even number of bytes - but it is a typical beginner's fault.)
来源:https://stackoverflow.com/questions/28823218/rewind-file-create-dynamic-struct