I am reading in a file of locations with coordinates, city names and country names. Currently I am just testing to see if i can store the first element of each line in my array. The fallowing is a sample of the file i am reading in:
Durban, South Africa
29 53 S
30 53 E
The trouble i am having is that when I try to store the first element of each line in my array the same value gets stored for every element in the array. Code i have so far is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "kml.h"
#define LEN 128
struct quard_t {
char *city;
char *state;
char *country;
int longitude;
int latitude;
};
struct data_t {
int nval;
int max;
struct quard_t *data;
};
enum {INIT = 1, GROW = 2};
int main(int argc, char **argv)
{
char buf[LEN];
char *str;
int cnt = 0;
FILE *in = fopen(argv[1], "r") ;
struct data_t *data = malloc(sizeof(struct data_t));
data->nval = INIT;
data->max = INIT;
data->data = NULL;
while (fgets(buf, LEN, in)) {
if (data->nval > data->max){
data->data = realloc(data->data, GROW * data->max *sizeof(struct quard_t));
data->max = GROW * data->max;
}
else if (data->data == NULL)
data->data = malloc(INIT * sizeof(struct quard_t));
str = strtok(buf, " ");
data->data[cnt].city = str;
cnt++;
}
int i = 0;
for ( ; i < cnt; i++ ){
printf("%d: %s\n", i, data->data[i].city);
}
fclose(in);
return 0;
}
The fallowing is the output i am getting, the numbers being the index of the array and everything after being what is stored in the array:
190: 30
191: 30
192: 30
193: 30
194: 30
When you are assigning a value to city:
data->data[cnt].city = str;
All you are doing is assigning a pointer, not the actual data currently stored in str. So when you overwrite str later, city is pointing to the latest value of str. To fix this you need to allocate space for city when you allocate space for the quard_t structure. Then copy the string into this new buffer using strcpy. You'll have to do the same for the state and country fields.
Also, your data structure isn't really a linked list. You've really just created your own quasi-vector structure. A true linked list has the data members plus a pointer to the structure itself. I suggest you do a little research on linked list implementations.
Related
My program will read the datas from a txt into my structure.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct competitor
{
int id;
char* name;
char* nationality;
char* sex;
double weight;
char* event;
}competitor;
int sportolok_beolvas(char* filename, competitor* array)
{
FILE* file = fopen(filename, "r");
int n = 0;
while(fscanf(file, "%d %s %s %s %lf %s", &array[n].id, array[n].name, array[n].nationality, array[n].sex, &array[n].weight, array[n].event) == 6)
{
++n;
}
fclose(file);
return n;
}
int main()
{
competitor* array;
int i = sportolok_beolvas("sportolok.txt", array);
printf("%d", i);
return 0;
}
I did this function based on my previous project, which uses almost the same function. Read in the file to my struct. I don't understand what's wrong with it.
A string is really an array of characters with a null-terminator at the end.
You can create a string using plain arrays, like
char str[] = "foo";
Or you can use pointers and allocate memory dynamically, like
char *str = malloc(4);
strcpy(str, "foo");
Both those examples are almost equivalent (there are some important differences between arrays and pointers, but lets put those aside for now). Both those examples creates a string with three characters (plus the null-terminator).
However, if you have
char *str;
strcpy(str, "foo");
then you have undefined behavior because the pointer str doesn't point anywhere.
Going back to your code, the simplest solution for the strings are simply to change them from pointers to arrays:
#define NAME_SIZE 20
#define NATIONALITY_SIZE 20
#define SEX_SIZE 10
#define EVENT_SIZE 20
typedef struct competitor
{
int id;
char name[NAME_SIZE];
char nationality[NATIONALITY_SIZE];
char sex[SEX_SIZE];
double weight;
char event[EVENT_SIZE];
}competitor;
As for the array of competitor structures, I recommend you create it dynamically as needed inside the loop, reallocating as needed.
Read into a single defined competitor structure object, and copy it to the current array element.
Once done return the pointer to the first element of the array.
Perhaps something like this:
// Out dynamic "array", pointer to its first element
competitor *competitors = NULL;
// Current size of the competitor array
size_t current_size = 0;
// A structure object to store the data we read from the input
competitor current_competitor;
// Now the loop to read the data
while(fscanf(file, "%d %s %s %s %lf %s",
¤t_competitor.id,
current_competitor.name,
current_competitor.nationality,
current_competitor.sex,
¤t_competitor.weight,
current_competitor.event) == 6)
{
// Reallocate the array, adding one new element (+1)
// If the array doesn't exist, when competitors is NULL, create
// an array with a single element
competitor *new_array = realloc(competitors, sizeof *new_array * current_size + 1);
// Check if the allocation succeeded or failed
if (new_array == NULL)
{
// TODO: Report it
exit(EXIT_FAILURE);
}
// Make the new array our actual array
competitors = new_array;
// Copy the the structure object we just have read, into the array
competitors[current_size] = current_competitor;
// And finally increase the size
++current_size;
}
After this, the `competitors` pointer will point to the first element of an array of `current_size` elements.
Exactly how to return these values (*both* needs to be returned) is left as an exercise for the reader.
I have to dynamically allocate memory using these two functions but I keep getting a segfault. The code takes in strings from a file. I need to dynamically allocate memory for a specific number of monsters using structs, pointers and malloc.
typedef struct monster {
char *name;
char *element;
int population;
} monster;
monster* createMonster(char *name, char *element, int population){
//Copying the data into the monster
monster *temp =(monster*) malloc(sizeof(monster));
strcpy(temp->name, name);
strcpy(temp->element, element);
strcpy(temp->population, population);
return temp;
free(temp);
}
monster** readMonsters(FILE* infile, int *monsterCount){
//getting monster count and creating temp pointers
monster **temp = NULL;
char m_word [8];
fscanf(infile, "%d", monsterCount);
fscanf(infile, "%s", m_word); //reading the word monster to skip it
char* temp_name;
char* temp_element;
int temp_pop;
//allocating memory and creating an array of monster pointers * mcount
temp = (monster**)malloc(*monsterCount * sizeof(monster*));
for(int i = 0; i < monsterCount; i++){
fscanf(infile, "%s",temp_name);
fscanf(infile, "%s",temp_element);
fscanf(infile, "%d",temp_pop);
monster *monster_temp = createMonster(temp_name, temp_element, temp_pop);
temp[i]->name = monster_temp->name;
temp[i]->element = monster_temp->element;
temp[i]->population = monster_temp->population;
}
return temp;
}
You haven't posted the definition of struct monster.
If struct monster contains a lot of char* and you are assigning a char* to it, that char* needs to be allocated somewhere. It doesn't look like temp_name and temp_element have been allocated, which would cause a crash on the scanf.
your code segfault because you write at uninitialized and unallocated pointers
you directly write with strcpy name and element field of your struct but these two field point at unknow location
also, you try strcpy an integer, directly assign it : temp->population = population ;
finally you cannot return temp and free temp, if you return it it will be reused, you must not free it, hopefully the free is never reach as you exit the function one line before :)
for storing your strings into the struct, you have some possibilities
declare them as array of char in your structure : char name[64]
use a buffer in your structure and set the name and element field point on part of it
malloc them with strlen of original strings before the copy
directly point name and element vars of your createMonster function to the pointer, it will use original memory, but it's not suitable here as they come from temporary memory
an example of create monster function using a static common buffer for your strings (untested) :
#define MONSTER_MAX_BF 64
typedef struct monster {
char *name;
char *element;
int population;
char bf[MONSTER_MAX_BF];
} monster;
monster* createMonster(char *name, char *element, int population){
monster *temp =(monster*) malloc(sizeof(monster));
char * lastBf = temp->bf + (MONSTER_MAX_BF - 1); // buffer last char
char *bfp = bf, *p ;
// copy name
temp->name = bfp ;
p = name ;
while( *p && *bfp != lastBf ) *bfp++ = *p++ ;
*bfp++ = 0;
// copy element
temp->element = bfp ;
p = element ;
while( *p && *bfp != lastBf ) *bfp++ = *p++ ;
*bfp = 0;
temp->population = population ;
return temp;
}
So the purpose of this code is to scanf a sentence like this one:
In my house#House#28#-134.943|47.293#21-24
The code must scan 6 different parts separated by '#'. The first one, "In my house" is the location of the party, the second one "House" is the type of place where there will be the party, the third one "28" is walk time to arrive there, the fourth one "-134.943|47.293" are the latitude and longitude (to find the place) separated by a '|', and finally, "21-24" is the time when the party starts and when it finishes. All of the previous parameters have to be saved in different variables that are into a structure like the following one:
typedef struct {
char name[MAX]; //name of the location
char location_type[MAX]; //type of location
int travel; //time to arrive
int latitude;
int longitude;
int hours[5]; //when the party starts and ends
} Locations;
And then, everything is stored neatly for every party location.
So, I'm asking for a function that asks and stores all that information (separated by "#" and "|") in the structure we have seen before. This function is something like this:
int AddLocation(Locations location[]) {
int i = 0;
i = num_locations;
printf ("Location information: ");
// here should be the scanf and this stuff
i++;
return i;
}
Making a few changes to the format (namely, lat/long need to be floats, and I'm not sure what you meant to do with the int array for hours), you could do something like:
#include <stdio.h>
#define MAX 32
struct loc {
char name[MAX];
char location_type[MAX];
int travel;
float latitude;
float longitude;
char hours[MAX];
};
int
main(void)
{
struct loc Locations[16];
struct loc *t = Locations;
struct loc *e = Locations + sizeof Locations / sizeof *Locations;
char nl;
char fmt[128];
/* Construct fmt string like: %31[^#]#%31[^#]#%d#%f|%f#%31[^\n]%c */
snprintf(fmt, sizeof fmt,
"%%%1$d[^#]#%%%1$d[^#]#%%d#%%f|%%f#%%%1$d[^\n]%%c", MAX - 1);
while( t < e
&& 7 == scanf(fmt,
t->name, t->location_type, &t->travel,
&t->latitude, &t->longitude, t->hours, &nl
) && nl == '\n'
) {
t += 1;
}
for( e = Locations; e < t; e++ ){
; /* Do something with a location */
}
}
Try compile and run this. This code should split your string . All you have to do is enter the results properly into your structure.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
/*Declare variable */
char *line = malloc(250 * sizeof(char *));
size_t line_size = 250;
char *argument = malloc(250 *sizeof(char *));
/*Get string and save it in line */
getline(&line,&line_size,stdin);
/*Split string */
char corrector[] = "#|\n";
argument = strtok(line,corrector);
while(argument != NULL){
printf("%s\n", argument);
argument = strtok(NULL,corrector);
}
return 0;
}
Input : In my house#House#28#-134.943|47.293#21-24
Output:
In my house
House
28
-134.943
47.293
21-24
Hey so im trying to attempt to read in a file, store it in a hash and then copy it. However i get the incompatible pointer type
struct hash_struct {
int id;
char name[BUFFER_SIZE]; /* key (string WITHIN the structure */
UT_hash_handle hh; /* makes this structure hashable */
};
int main(int argc, char *argv[] )
{
char *lines[80];
FILE* fp = fopen("file.txt","r");
if(fgets(*lines, BUFFER_SIZE, fp) != NULL)
{
puts(*lines);
// do something
}
fclose(fp);
const char **n;
char *names[1024];
strcpy(*names, *lines);
struct hash_struct *s, *tmp, *users = NULL;
int i=0;
for (n = names; *n != NULL; n++)
{
s = (struct hash_struct*)malloc(sizeof(struct hash_struct));
strncpy(s->name, *n,10);
s->id = i++;
HASH_ADD_STR( users, name, s );
}
HASH_FIND_STR( users, "joe", s);
if (s) printf("joe's id is %d\n", s->id);
printf("Hash has %d entries\n",HASH_COUNT(users));
/* free the hash table contents */
HASH_ITER(hh, users, s, tmp) {
HASH_DEL(users, s);
free(s);
}
return 0;
}
The code works when i initialize const char **n, *names = {array elements here};
But it doesnt work with the code i have. Please help.
lines is declared to be an array of char pointers, but doesn't allocate any space for the strings they point to. In your working version, the compiler took care of allocating space for each string.
Plus, you can't use strcpy to copy an array of 80 pointers to an array of 1024 pointers.
Instead, each line you read in needs space to be allocated for it to be read into; then the addresses of each of those can be assigned to an element of names. In fact, as #BLUEPIXY suggests, line should be an array of 80 chars, not an array of 80 pointers-to-chars. Or you could just malloc the space for each new line, and put the address of that line into names.
I'm trying to split a string every X amount of characters, and then store each line in an array of structs. However, I'm wondering what would be a short and efficient way of doing it. I thought that maybe I could use sscanf, but not very sure how to. Any help will be appreciated. So far I have:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct st {char *str;};
int main ()
{
struct st **mystruct;
char tmp[] = "For configuration options (arch/xxx/config.in, and all the Config.in files),somewhat different indentation is used.";
size_t max = 20, j = 0; // max length of string
size_t alloc = strlen(tmp)/max + 1;
mystruct = malloc(alloc * sizeof *mystruct);
for (j = 0; j < alloc; j++)
mystruct[j] = malloc(sizeof *mystruct[j]);
const char *ptr = tmp;
char field [ max ];
int n;
while (*ptr != '\0') {
int line = sscanf(ptr, "%s", field, &n); // not sure how to use max in here
mystruct[j]->str = field;
field[0]='\0';
if (line == 1)
ptr += n;
if ( n != max )
break;
++ptr;
++j;
}
return 0;
}
So when I iterate over my struct, I can get something like:
For configuration op
tions (arch/xxx/conf
ig.in, and all the C
onfig.in files),some
what different inden
tation is used.
You could use strncpy.
FYI:
char field [ max ];
while (...) {
mystruct[j]->str = field;
Two problems with this: (1) every struct in your array is going to end up pointing at the same string, which will have the value of the last thing you scanned, (2) they are pointing to a variable on the stack, so when this function returns they will be trashed. That doesn't manifest itself visibly here (e.g. your program doesn't explode) because the function happens to be 'main', but if you moved this to a separate routine and called it to parse a string, you'd get back garbage.
mystruct doesn't need to be pointer to pointer. For a 1D array, just allocate a block N * sizeof *myarray for N elements.
A common C idiom when dealing with structs is to use typedef so you don't have to type struct foo all the time. For instance:
typedef struct {
int x, y;
} point;
Now instead of typing struct point pt you can just say point pt.
If your string is not going to change after you split it up, I'd recommend using a struct like this:
struct st {
char *begin;
char *end;
};
or the alternative:
struct st {
char *s;
size_t len;
};
Then instead of creating all those new strings, just mark where each one begins and ends in your struct. Keep the original string in memory.
One option is to do it character-by-character.
Calculate the number of lines as you are currently doing.
Allocate memory = (strlen(tmp) + number_of_lines) * sizeof(char)
Walk through your input string, copying characters from the input to the newly allocated memory. Every 20th character, insert a null byte to delimit that string. Save a pointer to the beginning of each line in your array of structs.
Its easy enough?
#define SMAX 20
typedef struct {char str[SMAX+1];} ST;
int main()
{
ST st[SMAX]={0};
char *tmp = "For configuration options (arch/xxx/config.in, and all the Config.in files),somewhat different indentation is used.";
int i=0,j;
for( ; (st[i++]=*(ST*)tmp).str[SMAX]=0 , strlen(tmp)>=SMAX; tmp+=SMAX );
for( j=0;j<i;++j )
puts(st[j].str);
return 0;
}
You may use (non C standard but GNU) function strndup().
#define _GNU_SOURCE
#include <string.h>
struct st {char *str;};
int main ()
{
struct st *mystruct; /* i wonder if there's need for double indirection... */
char tmp[] = "For configuration options (arch/xxx/config.in, and all the Config.in files),somewhat different indentation is used.";
size_t max = 20, j = 0; // max length of string
size_t alloc = (strlen(tmp) + max - 1)/max; /* correct round up */
mystruct = malloc(alloc * sizeof mystruct);
if(!mystruct) return 1; /* never forget testing if allocation failed! */
for(j = 0; j<alloc; j++)
{
mystruct[j].str = strndup(tmp+alloc*max, max);
}
}