turning file string into char pointer - c

Hello in first I will give some details, I' m working in:
Ubuntu , in c language and my compiler is gcc.
I was make a lisle test of my skills because I'm not so good with pointers so I tried my luck and I get a weird output.
I will show my code now.
#include<stdio.h>
#include<string.h>
#define F1 ".file.txt"
typedef struct{
char par1[30];
int par2;
int par3;
int par4;
char* par5[3];
}S1;
//this was the structure I was working
void initiate_S1(S1*a,char part1[],int* part2,int *part3, int*part4,char part51[],char part52[],char part53[]);
//this function will start the struct parameters
void get_S1(S1*a);
//this function will print struct parameters
void save_S1_on_file(S1*a);
//this will save all parameters of a structure in file
void search_S1_on_file(S1*a);
//This function will search for a first parameter of structure and if
//find it fill the other parameters
int main(){
S1 a;
int part2,part3,part4;
char part1[30],part51[15],part52[15],part53[15];
scanf("%s %d %d %d %s %s %s",part1,&part2,&part3,&part4,part51,part52,part53);
initiate_S1(&a,part1,&part2,&part3,&part4,part51,part52,part53);
get_S1(&a);
save_S1_on_file(&a);
search_S1_on_file(&a);
get_S1(&a);
return 0;
}
//this main is only to test the functions
void initiate_S1(S1*a,char part1[],int* part2,int *part3, int*part4,char part51[],char part52[],char part53[]){
strcpy(a->par1,part1);
a->par2=*part2;
a->par3=*part3;
a->par4=*part4;
a->par5[0]=part51;
a->par5[1]=part52;
a->par5[2]=part53;
}
void get_S1(S1*a){
printf("%s\n%d\n%d\n%d\n%s %s %s\n",a->par1,a->par2,a->par3,a->par4,a->par5[0],a->par5[1],a->par5[2]);
}
void save_S1_on_file(S1*a){
FILE *af;
af=fopen(F1,"a");
fprintf(af,"%s;%d;%d;%d;%s;%s;%s;\n",a->par1,a->par2,a->par3,a->par4,a->par5[0],a->par5[1],a->par5[2]);
fclose(af);
}
void search_S1_on_file(S1*a){
FILE *af;
char s[100];
char*token;
af=fopen(F1,"r");
int n=2;
while(fgets(s,100,af)!=NULL){
token=strtok(s,";");
if(strstr(a->par1,token)!=NULL){
n=0;
token=strtok(NULL,";");
a->par2=atoi(token);
token=strtok(NULL,";");
a->par3=atoi(token);
token=strtok(NULL,";");
a->par4=atoi(token);
a->par5[0]=strtok(NULL,";");
a->par5[1]=strtok(NULL,";");
a->par5[2]=strtok(NULL,";");
break;
}
else
n=1;
}
if(n==1)
printf("The S1 no exist\n");
}
input:
name 15 3 2 tag1 tag2 tag3
output:
name
15
3
2
tag1 tag2 tag3
name
15
3
2
%��j��2 j��2 tag3
For some reason when I try fill the char pointers from file string appears this weir output
why appear this weird chars and whats is wrong in my code?

You are good until you call search_S1_on_file()
Inside this for the array of pointers a->par5 you assign the address of the local variable s.
a->par5[0]=strtok(NULL,";");/* The string being broken into tokens is a local array */
a->par5[1]=strtok(NULL,";");
a->par5[2]=strtok(NULL,";");
Once you exit this function the memory allocated for the array s is freed so accessing this memory location you are bound to get garbage values because this is UB.
In order to fix this keep a char array in main and pass it to the function search_S1_on_file() along with other requierd parameters and that should work.
Alternatively you can try allocating memory on heap for the array s like
char *s = malloc(100); /* Take care to free this memory accordingly */

Related

printing struct member using user input

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.

failed while trying to reach pointer in struct

my project is to build book structure - and fill it with users parameters.
involving dynamic allocation, arrays and pointers.
my book structure has the following:
struct BOOK
{
char* author;
char** genders;
int totalGenders;
char* name;
int* chapterPages;
int totalChapters;
}typedef book;
when I tried reaching author name, line 1 in structure:
struct BOOK
{
char* author;
I failed doing that.. my code in main :
int main()
{
book* b;
char authorChar[10] = { 0 };
int authorLen;
char* authorName;
// get author name
puts("please enter the name of the author");
scanf("%s", &authorChar);
authorLen = strlen(authorChar);
printf("%d", authorLen); //print to see that lentgh is correct.
authorName = (char*)calloc(authorLen, sizeof(char));
strcpy(authorName, authorChar);
puts("\n");
b->author = authorName;
printf("%d", b->author);
when i have debugged i got a problem in this line :
b->author = authorName;
ideas please? :)
The problem is in the following line
b->author = authorName;
at this point, b is not allocated memory, i.e., b is an uninitialized pointer. It points to some random memory location which is not a valid one. Any attempt to access invalid memory invokes undefined behavior.
You can use either of the following approach to resolve the issue:
allocate memory to b dynamically before using it, like b = malloc(sizeof*b); and a check for success.
define b as a variable of type book, instead of a pointer-to-type.
That said, int main() should be int main(void) at least, to conform to the standards.
You are forgetting to do the memory allocation for b variable.
b = malloc(sizeof(book));
b->author = malloc(sizeof(100000)); // replace value for the size you want

Array of struct implementation in C

I need some ideas on my array of struct implementation. This is what I have in my structs. I plan on making SHAPES an array because I will have multiple SHAPES. Each shape will have multiple x and y coordinates. Because of this I'm not sure if should make a linked list or not. The purpose of the start and finish is I will eventually be running a search algorithm after I get my shapes right.
struct START
{
int x;
int y;
};
struct END
{
int x;
int y;
};
struct SHAPES
{
int x [100];
int y [100];
int *link;
};
struct DISTANCE
{
int distance_traveled;
int distance_to_finish;
};
I was reading this and was wondering if I needed to malloc or calloc my structs as I create them. If so why and if not why? Malloc and calloc are always confusing to me.
How do you make an array of structs in C?
int main(int argc, char *argv[])
{
//Is it better to make these pointers?
struct START start;
struct END end;
struct SHAPES shapes[100];
while(fgets(line, 80, fp) != NULL)
{
//I have a very annoying issue here, I don't know the size of the lines.
//If there are more values I want to increment the x[] and y[] array but NOT the
//shapes array. I can only think of one way to deal with this by putting a bunch of
//variables in the sscanf. I discovered putting sscanf on the next line didn't do what
//I was hoping for.
sscanf(line, "%d%*c %d%*c ", &shapes[i].x[i] , &shapes[i].y[i] );
printf(" line is: %s \n", line);
sscanf(line, "%d%*c %d%*c ", &x1_main , &y1_main );
printf(" line is: %s \n", line);
printf(" shapes[i].x[i] is: %d \n", shapes[i].x[i]);
printf(" shapes[i].y[i] is: %d \n", shapes[i].y[i]);
printf(" x1_main is: %d \n", x1_main);
printf(" y1_main is: %d \n", y1_main);
i++;
memset(line, 0, 80);
}
}
This is what my file looks like. Adding the %*c seemed to handle the commas and semicolons appropriately.
10, 4
22, 37
22, 8; 2, 0; 3, 6; 7, 8; 5, 10; 25, 2
1, 2
I got that idea from here.
https://www.daniweb.com/software-development/c/threads/334515/reading-comma-separated-values-with-fscanf
First of all, you might want to consider something like this:
struct point {
int x;
int y;
};
so you can use a struct point data structure (array) instead of two separate data structures for x and y. Using it like this should also speed up access to the points, since their coordinates are next to each other in memory. Otherwise you will have x somewhere in the x array and y somewhere in the y array.
The choice of the data structure to store the points depends on your usage. If you need to address points directly, a linked list may be a bad choice. If you always access all points in a linear order, it is fine. However, consider that a singly linked list will add 8 bytes per point for the next pointer. A doubly linked list will use another 8 bytes for prev (assuming 64-bit arch that is; sizeof(pointer) in general). I assume, that you create x[100] and y[100] to make sure you have enough space. You might be better off using a dynamic array (the ADT) e.g. glib's GArray after all. It will grow as big as you need it without you doing anything.
For malloc vs calloc: it doesn't really matter. A call to calloc is basically a malloc followed by a
memset(ptr, 0, sizeof(mallocd area);
i.e. the memory is zeroed; cf manpage calloc. If you initialize the memory directly you may not need to do this.
A struct with no pointer members
If your struct has no pointer members, such as:
typedef struct {
int a;
int b;
} DEMO;
Then you can simply declare an array instance of a typedef struct like this:
DEMO demo[10];// instance of array of 10 DEMO
Example, struct with Pointer members
If you have a pointer in the list of members:
#define SIZE_STR 20
typedef struct {
int a;
int b;
char *str;//pointer, will require memory allocation
} DEMO;
DEMO demo[10];// instance of array of 10 DEMO
int main(void)
{
int i;
for(i=0;i<10;i++)//create memory for each instance of char * in array of DEMO
{
demo[i].str = malloc(SIZE_STR);
}
return 0;
}
Don't forget to free() all instances of malloc'ed memory.
Dynamically allocate array of struct
If you need to dynamically allocate memory for a struct:
typedef struct {
int a;
int b;
} DEMO;
DEMO demo, *pDemo;// create a pointer to DEMO
In a function, main() for example:
int main(void)
{
pDemo = &demo;
pDemo = malloc(sizeof(DEMO)*10);//provides an array of 10 DEMO
return 0;
}
Again, don't forget to free() all instances of malloc'ed memory.

Function SegFault with Arrays of Structs

I am using this function:
int times_on_table(char *search,struct table index[],int wct){
int ct=0,num=0;
while(ct<wct){
if(strcmp(search,(index[ct].label))==0) {
num++;
}
ct++;
}
return num;
}
to search through an array of structs and find all the times a certain string is stored in the array and returns the number of times the string occurs. Whenever i use this function inside main:
/*EDIT: i had a main from the wrong program my apologies*/
int main(int argc, char **argv){
int numwds=get_num_words(argv[1]);
struct table index[numwds];
int a;
struct cmd_ops symbol[22];
store(argv[1],index,numwds);
ops_gen(symbol);
int b=times_on_table("in",index,numwds);
printf("%d",b);
}
the code works fine. However, when i try to use it inside certain functions like this one
struct table* store(char *filename,struct table index[]) {
FILE *fp;
fp=fopen(filename,"r");
char *a;int d=0,e=0,t=0;
a=malloc(60);
int wordcount=get_num_words(filename);
while(d<wordcount){
fscanf(fp,"%s",a);
if ((index[d].label=strdup(a))==NULL)
break;
index[d].word_num=d;
times_on_table("this",index,wordcount);/*when i comment this out
of my code it runs fine*/
index[d].address=findline(filename,index[d].label,wordcount,index,t);
d++;
}
free(a);
}
the code does not run and gives me a segmentation fault. Any thoughts?
EDIT: I don't know if this helps but when i get the segfault, it happens before even the first line of code in main is executed.
EDIT:here is the other function that causes a segfault when times_on_table() is called:
int findline(char *filename,char *check,int wordcount,struct table index[],int t){
char *a;
a=malloc(60);
int b=line_count(filename);
int ch;
fpos_t pos;
int line=0,wd=0,loc,s=0,c=1,times;
times=times_on_table(check,index,wordcount);
FILE *fp;
fp=fopen(filename,"r");
int list[wordcount];
while(c<=b){
fscanf(fp,"%s",a);
fgetpos(fp,&pos);
ch=fgetc(fp);ch=fgetc(fp);
if(strcmp(a,check)==0){
if(times==0)
return line;
else
times--;
}
if(ch==10){
line++;c++;
}
else
fsetpos(fp,&pos);
}
return line;
}
it was in this function that i first added times_on_table(), and had the segmentation fault keep my program from running.
Here
while(d<wordcount){
fscanf(fp,"%s",a);
if ((index[d].label=strdup(a))==NULL)
break;
index[d].word_num=d;
times_on_table("this",index,wordcount);
you try to count the occurrences of "this" in a wordcount long array, but you have only filled d+1 slots of the array. The other slots may contain garbage, and then accessing index[ct].label is likely to cause a segmentation fault when ct > d.
It is very likely you are going past the array index. These two lines do not really match up (from the code you have shared with us :
int wordcount=get_num_words(filename);
times_on_table("this",index,wordcount);
(wordcount I assume counts something in filename which is passed in as the first parameter, but it seems irrelevant to your struct table index[])
So the parameter being passed in struct table index[], is probably a different size than the value you are storing into wordcount. I would suggest you pass in the array size as a parameter to the store function and use that as you would in your working main example. example
struct table* store(char *filename,struct table index[], int structSize){
....
times_on_table("this",index,structSize); //replace b from the call in main
}
It may be related with setting the "index[d].label" properly. Try to print all the labels outside the times_on_table() function without comparing them with anything.

C malloc() with structs advice

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.

Resources