So, the task is to read file and push data to structure. the data file is:
babe 12 red 12
deas 12 blue 12
dsa 12 red 512
bxvx 15 blue 52
reed 18 black 15
while code is something like that
struct shoes {
char name[8];
int size;
char color[8];
int price;
};
//open file
shoes *item=(struct shoes*)malloc(sizeof(struct shoes));
for (i=0; !feof(file); i++) {
item=(struct shoes*)realloc(item,sizeof(struct shoes)+i*sizeof(struct shoes));
fscanf(file,"%s %i %s %i\n",(item+i)->name,(item+i)->size,(item+i)->color,(item+i)->price);
}
but the program crashes every time.
dbg says: No symbol "item" in current context.
where is error?
You code has some bugs:
1) You need a typedef for shoes unless you're compiling with a C++ compiler ... but then you should have tagged this C++.
2) feof doesn't return false until an attempt has actually been made to read beyond the end of file, so your code makes the array of shoes 1 too large.
3) You're passing ints to fscanf instead their addresses.
If compiling as C code, not C++ code, the casts on malloc and realloc aren't necessary and are advised against. And there are other stylistic issues that make you code harder to comprehend than it could be. Try this:
typedef struct {
char name[8];
int size;
char color[8];
int price;
} Shoe;
// [open file]
Shoe* shoes = NULL; // list of Shoes
Shoe shoe; // temp for reading
for (i = 0; fscanf(file,"%s %i %s %i\n", shoe.name, &shoe.size, shoe.color, &shoe.price) == 4; i++)
{
shoes = realloc(shoes, (i+1) * sizeof *shoes);
if (!shoes) ReportOutOfMemoryAndDie();
shoes[i] = shoe;
}
The problem is that you are not passing pointers to the integers you want to read using fscanf, you are passing the integers themselves.
fscanf treats them as pointers. And where do they point? Who knows - the integers were uninitialized, so they could point ANYWHERE. Therefore, CRASH.
Fix thusly:
fscanf(file,"%s %i %s %i\n",
(item+i)->name,
&((item+i)->size),
(item+i)->color,
&((item+i)->price));
Note that you don't need the same for name and color because arrays degenerate to pointers, so you're passing the right thing already.
And please, consider ditching the item+i notation; item[i] is so much clearer and easier to understand when casually reading the code:
fscanf("%s %i %s %i\n",
item[i].name,
&item[i].size,
item[i].color,
&item[i].price);
Are you sure the debugger says that? I'm surprised it even compiled...
You wanted:
struct shoes *item
If you don't proved a typedef of your structure, you have to explicitly say "struct" every time you reference it.
Second note:
item=(struct shoes*)realloc(item...
Don't assign the same pointer from realloc() that you pass into it. If the reallocation fails it will return NULL and that could be killing you. You should make sure you're checking the results of both the initial malloc() and the realloc()
Third point:
You need to be passing the address of the int's to the fscanf().
fscanf(file,"%s %i %s %i\n",(item+i)->name,&((item+i)->size),(item+i)->color,&((item+i)->price));
There are two issues with your code:
1st. The struct:
you could define your struct in two ways,
the way you did:
struct shoe{
char name[8];
int size;
char color[8];
int price;
};
and in this case you should refer to a pointer to it as:
struct shoe *item;
the other (perhaps more convenient?) way using a typedef along with the defenition:
typedef struct {
char name[8];
int size;
char color[8];
int price;
} shoe;
and in this case you should refer to a pointer to it as:
shoe *item;
Therefore the code you posted isn't supposed to compile.
2nd one:
fscanf should be given pointers to integers/chars in the case you showed.
You've correctly passed the char pointer(since you passed the name of a char array which is actually a char pointer to the first element), but you have passed some integers and fscanf needs pointer to integers it is supposed to fill, so your code should be:
fscanf(file,"%s %i %s %i\n",(item+i)->name,&((item+i)->size),(item+i)->color,&((item+i)->price));
Related
I need to get name from the file (string).
But certainly it gets (null) value.
void dealer__init(){
FILE * dealer = fopen(DEALER_L, "r");
fscanf(dealer, "%d %d %255s", &my_og.money, &my_og.check_ok, my_og.name);
printf("%255s\n", my_og.name);
printf("%d\n", my_og.money);
printf("%d\n", my_og.check_ok);
if(money_at_beg == true && my_og.check_ok == 0){
my_og.money = MONEY_AT_BEG_INT;
my_og.check_ok = 1;
dealer__save();
}
printf("My name is set to: %s", &my_og.name);
fclose(dealer);
}
My file:
3000 1 dimitar
My struct:
struct dealer{
int money;
int check_ok;
char *name;
}my_og;
You can't use the fscanf function (or most other functions)1 to read data into an uninitialized – or invalid – pointer. That causes undefined behaviour which, in your case, appears to go unnoticed until you try to print out the value after the attempted read. (This is one of the nastier aspects of UB: that the code appears to work.)
You need to either explicitly allocate some memory to which your pointer refers to, like this:
my_og.name = malloc(256); // Allocate some memory
Or, perhaps simpler, declare the name member as a fixed-size array, rather than a pointer:
struct dealer{
int money;
int check_ok;
char name[256]; // 'allocated' when the structure is declared
}my_og;
1 There is, I believe a non-standard (POSIX) version of the scanf formatting option (%ms) that automatically allocates memory, but I would personally avoid such things like the plague. See: scanf dynamic allocation.
So I've been looking at structures, functions and pointers for days now. I just cant wrap my head around structures good enough to do what I want...
I was trying to write a function, which was originally going to receive user input (taken with fgets) as an argument. I have put that aside now, and just decided to give the function a single argument. That argument will be the name of a struct, and I'll use that name to access it's variables and print them the way I want.
typedef struct
{
int hp;
char *name;
} bare;
bare example;
void print_info(char *name);
int main()
{
example.hp = 5;
strcpy(example.name,"John");
print_info("example");
}
void print_info(char *name)
{
printf("The hp of %s is %d", (*name), (*name)->hp);
}
Whatever bloody thing I put there instead of char *name, it always ended up giving me the error "error: struct or union expected"! I tried struct bare **name and (*name)->hp/(*name).hp, char *name/**name and *&name.hp, *&name->hp, every possible solution I could think of..! i think they all turned out to be nonsense... I just cant wrap my head around pointers and structs enough to do this! A little help please? I searched high and low on function arguments, pointers and structs, yet couldn't find a solution/question like mine..
First, it's better to declare your struct this way:
typedef struct bare {
int hp;
char *name;
} bare;
Second, avoid global variable as much as you can. I don't see the point of declaring example in the global namespace since you are using it only inside main().
Third, this line has a problem:
strcpy(example.name, "John");
You are attempting to copy "John" to an uninitialized pointer (example.name) that points to some random memory address. You have to either allocate enough space using malloc() (and free it when you're done with it), or use a fixed-length array. Moreover, it's better to use strncpy() because it allows to specify the maximum number of characters to copy. This way you avoid the risk of buffer overflow.
Fourth, to avoid copying your entire struct to print_info() (in fact, any other struct to any other function), you should pass its address.
With all that said, here is how your code should be written:
#include <stdio.h>
#include <string.h>
typedef struct bare {
int hp;
char name[100]; // Make sure it has enough space, or use malloc() if you don't know how much it will hold initially
} bare;
void print_info(bare *name);
int main(void)
{
bare example; // Declare it inside main()
example.hp = 5;
strncpy(example.name, "John", sizeof example.name); // This works and is safe
print_info(&example);
}
void print_info(bare *name)
{
printf("The hp of %s is %d", name->name, name->hp);
}
Output:
The hp of John is 5
I think what you wish to do is this:
#include <stdio.h>
#include <string.h>
typedef struct {
int hp;
char *name;
} bare;
bare example;
void print_info(bare *name);
int main() {
example.hp = 5;
strcpy(example.name, "John");
print_info(&example);
}
void print_info(bare *name) {
printf("The hp of %s is %d", name->name, name->hp);
}
Or if you want to pass example by value:
#include <stdio.h>
#include <string.h>
typedef struct {
int hp;
char *name;
} bare;
bare example;
void print_info(bare name);
int main() {
example.hp = 5;
strcpy(example.name, "John");
print_info(example);
}
void print_info(bare name) {
printf("The hp of %s is %d", name.name, name.hp);
}
Why did your code not work?
print_info had an incorrect argument data type. What you wanted was to pass an object of bare or perhaps a pointer to an object of bare, but you were instead passing a variable of type char *.
The arrow operator is used on pointers. Maybe take a look at Arrow operator (->) usage in C.
You wanted to pass in a string typed in by the user.
I was trying to write a function, which was originally going to receive user input (taken with fgets) as an argument. I have put that aside now, and just decided to give the function a single argument.
This explains why you pass in a char * to your function. The input value was originally going to be read from fgets. In your program, you passed in the name of your variable.
bare example;
/* ... */
print_info("example");
To do a dynamic lookup on a symbol name, use dlsym.
As I suggested in comments, if you want to be able to look up the name of a variable to find the associated object, you can use dlsym so long as you are on a POSIX system (like Linux). For example:
// Need to inlcude <dlfcn.h> and link with -ldl
// Make local variables findable with -rdynamic
void print_info(char *name)
{
bare *p = dlsym(0, name);
if (p != NULL)
printf("The hp of %s is %d", p->name, p->hp);
else
printf("%s not found!\n", name);
}
So long as you include <dlfcn.h> and use -ldl when linking the program, and you make your symbol table visible (with -rdynamic on GCC), the program will find the pointer to your example variable. (Try it online!)
But you probably meant to do a lookup by name.
However, you seemed to have mixed some things up. Usually, the user will not care what names you have used for the variables in your program. You would never expect fgets to give you "example" because that is not what the user would type in.
You probably meant to search for the bare record that matches the name parameter of bare. In your case, "John".
print_info("John");
Normally, you would have a table of bares that you would look over and check for a match. However, in your simplified example, there is only one to check.
bare * find_bare(char *name)
{
if (strcmp(name, example.name) == 0) return &example;
return NULL;
}
void print_info(char *name)
{
bare *p = find_bare(name);
if (p != NULL)
printf("The hp of %s is %d", p->name, p->hp);
else
printf("%s not found!\n", name);
}
It isn't hard to create and search a table of bare.
In this case, you could probably simple create an array of bare to represent your collection that you would search over.
#define BARE_TABLE_SIZE 50
bare table_example[BARE_TABLE_SIZE];
Assuming you add the code to populate your table, you could use a simple loop to search for a matching name.
bare * find_bare(char *name)
{
for (int i = 0; i < BARE_TABLE_SIZE; ++i)
{
if (strcmp(name, table_example[i].name) == 0)
return &table_example[i];
}
return NULL;
}
Your example.name was an uninitialized pointer.
Finally, the most egregious error in your program is the attempt to call strcpy on an uninitialized pointer. One solution is to allocate new memory to hold the new name and assign the location of the new name to the pointer. POSIX systems (like Linux) supply a function called strdup that creates a copy of the input for you, in newly allocated memory.
example.name = strdup("John");
Since the memory is allocated by malloc, you would need to call free on the pointer if example is ever recycled for a new name.
i try to store name and age in a dynamic array
when we have a different type of data , int , and Char that we dont know the size in the start how to use a dynamic array to store the 2 types
typedef struct personne{
char nom ;
int age ;
}personne;
struct personne saisie_personne_suivante(struct personne* x){
scanf("%s",&x->nom);
scanf("%d",&x->age);
return *x;
}
int main(void){
personne *ali;
ali = malloc(sizeof(char*));
saisie_personne_suivante(ali);
printf("\n %d ",ali->age);
printf("\n %s",&ali->nom);
return 0;
}
Why i dont sucess ?
i think we cant store two types of data at a time in array.If we do so we need to allocate half of memory to char and half to integers provided you should give some size of array.
=>in your program at this line [ali = malloc(sizeof(char*))] you are passsing address of only char not of variable.If you want to store both values just pass address of both int and char.
ali is a pointer to a struct of size sizeof(char) + sizeof(int) which may vary between architectures.
For the time being, let's assume it's 5 bytes (which it probably is on your PC).
What you're doing, is allocate space equal to size of a pointer to char, (which is either 32 or 64bits wide, depending on your OS).
What you probably want to do is allocate space equal to size of your struct (5 bytes), that is:
ali = malloc(sizeof(personne));
Note the lack of *, since you want actual memory for a struct and not a pointer pointing to such a location.
By the way, you wouldn't want to write: malloc(sizeof(char)) either, since that would be just one byte needed for your struct.
I strongly advise you to get your hands on a book on C or a decent tutorial at least.
int main() {
personne *ali;
ali = (struct personne *)malloc(sizeof(personne));
saisie_personne_suivante(ali);
printf("\n %d ", ali->age);
printf("\n %c", ali->nom);
return 0;
}
There is not enough memory for struct personne, so you need to malloc sizeof(personne) memory. nom is not a pointer,it's a char variable,when you print it, use printf("%c",ali->nom);
I can concur with the commenters who recommended a good book/tutorial to get started but nevertheless: here is your repaired code, with a bit of comment.
// printf(), fprintf(), and puts()
#include <stdio.h>
// exit(), malloc(), and scanf()
#include <stdlib.h>
#define PERSONNE_ERROR 0
#define PERSONNE_OK 1
typedef struct personne {
// fixed width for 49 characters and the trailing NUL
char nom[50];
int age;
} personne;
int saisie_personne_suivante(struct personne *x)
{
// For the returns of the scanf()s.
// Because you always check the returns if available
// (well, actually: the returns of printf() et al. rarely get checked)
// preset it to a value meant to say "OK"
int res = PERSONNE_OK;
// UX: let the users know what they are supposed to do.
puts("Your name, please");
// we have a fixed maximum size of name and we can set it here within scanf()
// scanf() returns the number of elements it parsed, *not* the number of characters
// sacnf() needs a pointer to the memory it is expected to put the value into.
// x->nom is already a pointer to a char array, no need to use "&"
if ((res = scanf("%49s", x->nom)) != 1) {
// we can return immediatly here.
// If we would need to cleanup (free memory, for example) we would
// set res to PERSONNE_ERROR and use a goto to jump at the place
// where all the cleanup happens. But that should be done if the clean-up
// is always the same (or could be sorted) and you need such cleanups
// more than just two or three times.
return PERSONNE_ERROR;
}
puts("Your age, too, if you don't mind.");
// x->age is not a pointer to an int, hence we need to prefix "&"
if ((res = scanf("%d", &x->age)) != 1) {
return PERSONNE_ERROR;
}
return res;
}
int main(void)
{
personne *ali;
int res;
// reserve momory for the struct
ali = malloc(sizeof(personne));
// call function that fills the struct and check the return
if ((res = saisie_personne_suivante(ali)) != PERSONNE_OK) {
fprintf(stderr, "Something went wrong with saisie_personne_suivante()\n");
exit(EXIT_FAILURE);
}
// print the content of struct personne
// you can feed printf() directly, no need to find the pointer to the memory
// holding the int
printf("Age: %d\n", ali->age);
// To print strings it needs to know the start of the string whcih needs to be
// a pointer and ali->nom is a pointer to the start of the string
printf("Name: %s\n", ali->nom);
// free allocated memory (not really necessary at the end of the
// program but it's deemed good style and because it costs us nothing
// we cannot find a good reason to skip it)
free(ali);
// exit with a value that tells the OS that this programm ended without an error
// It shoudl be 0 (zero) which it almost always is.
// *Almost* always
exit(EXIT_SUCCESS);
}
But really: go and get some beginners book/tutorial. I cannot give you a recommendation because I don't know about any good ones in your native language (sometimes the english version is good but the translation lacks a lot).
I want to create a database sort of, that stores a list of 5000 names and 5000 coresponding salaries into an array, I simply can't find the problem since the console either crashes or the compiler gives me the following error: "cannot convert 'char* ()[30]' to 'char' for argument '1' to 'char*' fgets(char*,int,*FILE)".
EDIT: I changed whatever I could figure out in the code, and I seem to have an issue with
this line in particular:
person* TAB = calloc(N, sizeof(struct));
I can't spot other errors(lack of experience), and I don't know exactly what to use instead of fgets to put in a line.
#include <stdio.h>
#include <stdlib.h>
#define N 5000
typedef struct {
char name[30]
int salary;
} person;
int main()
{
person* TAB = calloc(N, sizeof(struct));
FILE * input;
input = fopen("in.txt","r+");
int nr=0;
int r;
while(nr<5000)
{
fscanf(input,"%s",TAB[nr].name);
fscanf(input,"%d",TAB[nr].salary);
nr++;
}
printf("%s %d",TAB[1].name,TAB[1].salary);
fclose(input);
return 0;
}
You really should avoid putting that much data on the stack, which is what a normal variable like that will generally do. It will occupy around 5000 * (30 + 4 * 5000) = 95 MB of stack space, which might be more than your operating system feels is reasonable.
Anyway, the fix is not to allocate this on the heap; the fix is to change the declaration. I believe there's a logic error, since you allocate space for 5000 salaries per person, which is probably not what you meant.
Also, the name field should be an array of characters, but you've declared it as an array of character pointers, which is what the warnings are all about.
I believe you should have:
struct person
{
char name[30];
int salary;
};
This will drop the memory usage for struct person TAB[N]; down to around 5000 * (30 + 4) or around 166 KB which is way more reasonable. This assumes a 4-byte int which is a pretty common situation.
Finally, your file reading code is not very nicely designed, it will probably not work.
Look into using fgets() to read lines, stopping when it fails (i.e. never calling feof()), and then parsing/tokenizing each line as read. Remember that names can contain whitespace, which will make %s in sscanf() stop.
The name struct member should not be declared as 30 char pointers and the salary is one per name so it should look something like this
typedef struct {
char name[30]
int salary;
} person;
Now in order to have it as an array you are best off allocating on the heap
person* persons = calloc(N, sizeof(struct));
Now you can access the name and salary of one person
persons[3].name
persons[3].salary
...
fgets(persons[nr].name,30,input); // although you may want to remove \n
struct person
{
char* name[30];
I think you mean char name[30]. That is if you want one name of at most 29 bytes.
Later on you do:
fgets(&TAB[nr].name,30,input);
Why are you taking the address? If you make the change above, the TAB[nr].name should be of type char[30], which should degenerate into a char* as desired.
I have two structs and I have an array of 30 pointer StudentType.
I have a problem with malloc(). When I compile it it's ok. But when I try to debug it, it shows "Segmentation Fault" in Dev c++.
In Eclipse, it shows up anything on console. I think that my mistakes are on these lines of code:
students[0]=(StudentType *)malloc(sizeof(StudentType)*NumOfStudents);
(*students[NumOfStudents]).firstName=(char*)malloc(sizeof(char[30]));
(*students[NumOfStudents]).lastName=(char*)malloc(sizeof(char[30]));
That's a part of my code.
#include <stdio.h>
#include <stdlib.h>
typedef struct{
float firstAssignment;
float secondAssignment;
float midterm;
float final;
float finalMark;
}StudentRecordType;
typedef struct{
char *firstName;
char *lastName;
int idNumber;
StudentRecordType marks;
}StudentType;
StudentType *students[30];
char firstName[30];
char lastName[30];
int ReadFromFile();
int PrintAll();
int NumOfStudents;
int i;
int main(void)
{
ReadFromFile();
}
int ReadFromFile()
{
FILE *fp;
fp=fopen("project2-askhsh2.dat","r");
if(fp==NULL)
{
printf("Error opening file.\n");
}
else
{
printf("Successful open of project2-askhsh2.dat\n");
}
fscanf(fp,"%d",&NumOfStudents);
printf("%d\n",NumOfStudents);
students[0]=(StudentType *)malloc(sizeof(StudentType)*NumOfStudents);
(*students[NumOfStudents]).firstName=(char*)malloc(sizeof(char[30]));
(*students[NumOfStudents]).lastName=(char*)malloc(sizeof(char[30]));
for(i=0;i<NumOfStudents;i++)
{
(*students[i]).idNumber=i;
fscanf(fp,"%s %s", (*students[i]).firstName,(*students[i]).lastName);
fscanf(fp,"%f %f %f %f",(*students[i]).marks.firstAssignment,(*students[i]).marks.secondAssignment,(*students[i]).marks.midterm,(*students[i]).marks.final);
printf("%s",(*students[i]).firstName);//, students[i].lastName);
}
}
(*students[NumOfStudents]).firstName=(char)malloc(sizeof(char[30]));
First, the cast is just plain wrong. Casting to char loses information.
Second, in C don't cast the return value from malloc(). It is, at best, redundant, and may hide an error the compiler would have caught without the cast.
If you're going to cast anyway, cast to char*.
You seem to have an extra level of pointers that you don't need causing some confusion, when using the students pointer. You also access past the end of the array that you've allocated.
So instead of
StudentType *students[30];
Which gives you an array of 30 pointers to StudentType I guess you probably just wanted:
StudentType *students;
Which is just a plain pointer to StudentType and can be used as the base of your dynamically allocated array. Then when you do the allocations you'd do this:
students = malloc(sizeof(*students) * NumOfStudents);
And you'd have to initialise each of those StudentTypes before you use them.
for(i=0;i<NumOfStudents;i++)
{
students[i].firstname = malloc(30);
students[i].lastname = malloc(30);
}
Notice that each StudentType is now accessed directly as an element from the students array as student[i], rather than the *students[i] which you had that was wrong. You can expand this to the rest of your code. Remember that you can only access from index 0 to NumOfStudents-1, so do not use students[NumOfStudents].
The other problem you will have is that when you use fscanf() you need to pass the address of the variable to store the result in using the ampersand operator. Currently you are only passing the value, e.g. you should use &students[i].marks.firstAssignment instead of (*students[i]).marks.firstAssignment, assuming you also fix the pointer errors.
These two statements are wrong:
(*students[NumOfStudents]).firstName=(char*)malloc(sizeof(char[30]));
(*students[NumOfStudents]).lastName=(char*)malloc(sizeof(char[30]));
C-arrays are zero-indexed, and so you are trying to dereference one past the size of the array. Assuming that you want to set the first and last name of the last element of students[], then you need to dereference index NumOfStudents - 1.
You don't need to cast the result of malloc() to char * (assuming you are writing a C application).
The sizeof(char) is 1, and so you just need to write malloc(30).
(*students[NumOfStudents]).firstName=(char*)malloc(sizeof(char[30]));
I think you meant:
students[some_index]->firstName = malloc(30);
With some_index something below NumOfStudents.
So your loop becomes:
for(i=0; i < NumOfStudents ; i++)
{
/* students[] is an array of pointers
** students[i] is a pointer
*/
students[ i ] = malloc(sizeof *students[ i ]);
students[ i ]->idNumber=i;
students[ i ]->firstName = malloc(30);
students[ i ]->lastName= malloc(30);
fscanf(fp,"%s %s"
, students[i]->firstName
, students[i]->lastName
);
fscanf(fp,"%f %f %f %f"
, &students[i]->marks.firstAssignment
, &students[i]->marks.secondAssignment
, &students[i]->marks.midterm
, &students[i]->marks.final
);
printf("%s",students[i]->firstName);//, students[i].lastName);
}
And using a global index named "i" can be considered bad style.