How to Store dynamic string in a struct ** containing char * pointer
Im currently working on a problem to store data from an input file into a struct of the following format:
typedef struct school_{
char *name;
char *state;
}School;
Im reading from an input file of the format :
name1, state1
name2, state2
And I would like to store the data dynamically for each school in a struct via pointers as the length of the name is unknown. k is the number of lines in the file.
So far this is what I have:
void input_schools(FILE *IN, School **Sch, int k) {
int i, j;
char ch;
for (i=0; i<k; i++)
{ fscanf(IN, "%c", &ch);
Sch[i].name = (char *)malloc(sizeof (char));
j = 0;
Sch[i].name[j] = ch;
while(ch != '-') {
fscanf(IN, "%c", &ch);
j++;
Sch[i].name = (char *) realloc(Sch[i].name, sizeof(char)*(j+1));
Sch[i].name[j] = ch;
}
}
Sch[i].name[j-1] = '';
However I am receiving a seg fault which I'm assuming is from the way I'm trying to store "ch" when writing "Sch[i].name[j]" I have also tried Sch[i]->name[j] and been unsuccessful. I would appreciate any help in knowing the correct way to write the address to store the data?
I call the function using :
input_schools(school_info,TOP100,school_size);
where school info is the input file
School *TOP100[school_size];
is top100
and school_size is the number of lines in the file
c pointers struct
add a comment |
Im currently working on a problem to store data from an input file into a struct of the following format:
typedef struct school_{
char *name;
char *state;
}School;
Im reading from an input file of the format :
name1, state1
name2, state2
And I would like to store the data dynamically for each school in a struct via pointers as the length of the name is unknown. k is the number of lines in the file.
So far this is what I have:
void input_schools(FILE *IN, School **Sch, int k) {
int i, j;
char ch;
for (i=0; i<k; i++)
{ fscanf(IN, "%c", &ch);
Sch[i].name = (char *)malloc(sizeof (char));
j = 0;
Sch[i].name[j] = ch;
while(ch != '-') {
fscanf(IN, "%c", &ch);
j++;
Sch[i].name = (char *) realloc(Sch[i].name, sizeof(char)*(j+1));
Sch[i].name[j] = ch;
}
}
Sch[i].name[j-1] = '';
However I am receiving a seg fault which I'm assuming is from the way I'm trying to store "ch" when writing "Sch[i].name[j]" I have also tried Sch[i]->name[j] and been unsuccessful. I would appreciate any help in knowing the correct way to write the address to store the data?
I call the function using :
input_schools(school_info,TOP100,school_size);
where school info is the input file
School *TOP100[school_size];
is top100
and school_size is the number of lines in the file
c pointers struct
1
School **Sch
soSch[i]
is a pointer -Sch[i].name
should produce a compiler error. Show how you call the function.
– Johnny Mopp
Nov 13 '18 at 19:40
4
Also, c-strings need to be terminated withwhich you neglect to do.
– Johnny Mopp
Nov 13 '18 at 19:43
1
Try and give your variables meaningful names, especially as arguments. What isk
?
– tadman
Nov 13 '18 at 19:43
2
Hint:strdup
instead of manually copying strings.
– tadman
Nov 13 '18 at 19:44
yap. try better names, and use a better indentation and formatting. Probably install a linter, it checks for formatting & compilation errors as you type. Also, there are some nice naming conventions out there. for example, instead ofk
, I would writea_number_of_lines
. Thea_
tells me that the variable is a function argument, and the remaining part tells me what the variable has. Also, unless you need, declare the variables in the loop.for(int i = 0; i < a_numer_of_lines; i++)
– Aravind Voggu
Nov 14 '18 at 4:37
add a comment |
Im currently working on a problem to store data from an input file into a struct of the following format:
typedef struct school_{
char *name;
char *state;
}School;
Im reading from an input file of the format :
name1, state1
name2, state2
And I would like to store the data dynamically for each school in a struct via pointers as the length of the name is unknown. k is the number of lines in the file.
So far this is what I have:
void input_schools(FILE *IN, School **Sch, int k) {
int i, j;
char ch;
for (i=0; i<k; i++)
{ fscanf(IN, "%c", &ch);
Sch[i].name = (char *)malloc(sizeof (char));
j = 0;
Sch[i].name[j] = ch;
while(ch != '-') {
fscanf(IN, "%c", &ch);
j++;
Sch[i].name = (char *) realloc(Sch[i].name, sizeof(char)*(j+1));
Sch[i].name[j] = ch;
}
}
Sch[i].name[j-1] = '';
However I am receiving a seg fault which I'm assuming is from the way I'm trying to store "ch" when writing "Sch[i].name[j]" I have also tried Sch[i]->name[j] and been unsuccessful. I would appreciate any help in knowing the correct way to write the address to store the data?
I call the function using :
input_schools(school_info,TOP100,school_size);
where school info is the input file
School *TOP100[school_size];
is top100
and school_size is the number of lines in the file
c pointers struct
Im currently working on a problem to store data from an input file into a struct of the following format:
typedef struct school_{
char *name;
char *state;
}School;
Im reading from an input file of the format :
name1, state1
name2, state2
And I would like to store the data dynamically for each school in a struct via pointers as the length of the name is unknown. k is the number of lines in the file.
So far this is what I have:
void input_schools(FILE *IN, School **Sch, int k) {
int i, j;
char ch;
for (i=0; i<k; i++)
{ fscanf(IN, "%c", &ch);
Sch[i].name = (char *)malloc(sizeof (char));
j = 0;
Sch[i].name[j] = ch;
while(ch != '-') {
fscanf(IN, "%c", &ch);
j++;
Sch[i].name = (char *) realloc(Sch[i].name, sizeof(char)*(j+1));
Sch[i].name[j] = ch;
}
}
Sch[i].name[j-1] = '';
However I am receiving a seg fault which I'm assuming is from the way I'm trying to store "ch" when writing "Sch[i].name[j]" I have also tried Sch[i]->name[j] and been unsuccessful. I would appreciate any help in knowing the correct way to write the address to store the data?
I call the function using :
input_schools(school_info,TOP100,school_size);
where school info is the input file
School *TOP100[school_size];
is top100
and school_size is the number of lines in the file
c pointers struct
c pointers struct
edited Nov 13 '18 at 19:49
codingstruggles
asked Nov 13 '18 at 19:33
codingstrugglescodingstruggles
192
192
1
School **Sch
soSch[i]
is a pointer -Sch[i].name
should produce a compiler error. Show how you call the function.
– Johnny Mopp
Nov 13 '18 at 19:40
4
Also, c-strings need to be terminated withwhich you neglect to do.
– Johnny Mopp
Nov 13 '18 at 19:43
1
Try and give your variables meaningful names, especially as arguments. What isk
?
– tadman
Nov 13 '18 at 19:43
2
Hint:strdup
instead of manually copying strings.
– tadman
Nov 13 '18 at 19:44
yap. try better names, and use a better indentation and formatting. Probably install a linter, it checks for formatting & compilation errors as you type. Also, there are some nice naming conventions out there. for example, instead ofk
, I would writea_number_of_lines
. Thea_
tells me that the variable is a function argument, and the remaining part tells me what the variable has. Also, unless you need, declare the variables in the loop.for(int i = 0; i < a_numer_of_lines; i++)
– Aravind Voggu
Nov 14 '18 at 4:37
add a comment |
1
School **Sch
soSch[i]
is a pointer -Sch[i].name
should produce a compiler error. Show how you call the function.
– Johnny Mopp
Nov 13 '18 at 19:40
4
Also, c-strings need to be terminated withwhich you neglect to do.
– Johnny Mopp
Nov 13 '18 at 19:43
1
Try and give your variables meaningful names, especially as arguments. What isk
?
– tadman
Nov 13 '18 at 19:43
2
Hint:strdup
instead of manually copying strings.
– tadman
Nov 13 '18 at 19:44
yap. try better names, and use a better indentation and formatting. Probably install a linter, it checks for formatting & compilation errors as you type. Also, there are some nice naming conventions out there. for example, instead ofk
, I would writea_number_of_lines
. Thea_
tells me that the variable is a function argument, and the remaining part tells me what the variable has. Also, unless you need, declare the variables in the loop.for(int i = 0; i < a_numer_of_lines; i++)
– Aravind Voggu
Nov 14 '18 at 4:37
1
1
School **Sch
so Sch[i]
is a pointer - Sch[i].name
should produce a compiler error. Show how you call the function.– Johnny Mopp
Nov 13 '18 at 19:40
School **Sch
so Sch[i]
is a pointer - Sch[i].name
should produce a compiler error. Show how you call the function.– Johnny Mopp
Nov 13 '18 at 19:40
4
4
Also, c-strings need to be terminated with
which you neglect to do.– Johnny Mopp
Nov 13 '18 at 19:43
Also, c-strings need to be terminated with
which you neglect to do.– Johnny Mopp
Nov 13 '18 at 19:43
1
1
Try and give your variables meaningful names, especially as arguments. What is
k
?– tadman
Nov 13 '18 at 19:43
Try and give your variables meaningful names, especially as arguments. What is
k
?– tadman
Nov 13 '18 at 19:43
2
2
Hint:
strdup
instead of manually copying strings.– tadman
Nov 13 '18 at 19:44
Hint:
strdup
instead of manually copying strings.– tadman
Nov 13 '18 at 19:44
yap. try better names, and use a better indentation and formatting. Probably install a linter, it checks for formatting & compilation errors as you type. Also, there are some nice naming conventions out there. for example, instead of
k
, I would write a_number_of_lines
. Thea_
tells me that the variable is a function argument, and the remaining part tells me what the variable has. Also, unless you need, declare the variables in the loop. for(int i = 0; i < a_numer_of_lines; i++)
– Aravind Voggu
Nov 14 '18 at 4:37
yap. try better names, and use a better indentation and formatting. Probably install a linter, it checks for formatting & compilation errors as you type. Also, there are some nice naming conventions out there. for example, instead of
k
, I would write a_number_of_lines
. Thea_
tells me that the variable is a function argument, and the remaining part tells me what the variable has. Also, unless you need, declare the variables in the loop. for(int i = 0; i < a_numer_of_lines; i++)
– Aravind Voggu
Nov 14 '18 at 4:37
add a comment |
2 Answers
2
active
oldest
votes
Your file is very similar in shape to a csv. See if you can use any csv parsing libraries or code.
Instead of checking every char, read a whole line into a buffer and use strtok. strtok is a function used to split a string by a delimiter. a ',' in your case.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char* getfield(char* line, int num)
{
const char* tok;
for (tok = strtok(line, ",");
tok && *tok;
tok = strtok(NULL, ",n"))
{
if (!--num)
return tok;
}
return NULL;
}
int main()
{
FILE* stream = fopen("in.md", "r");
char line[1024];
while (fgets(line, 1024, stream))
{
char* tmp1 = strdup(line);
char* tmp2 = strdup(line);
printf("Name is %sn", getfield(tmp1, 1));
printf("State is %sn", getfield(tmp2, 2));
// NOTE strtok changes the string. Hence two vars. You can try duplicating in the function instead.
// Note that I'm freeing the data. copying with strdup instead of directly assigning may be wise.
free(tmp1);
free(tmp2);
}
}
Sadly I have to use the format of the struct above. if I used strtok to get each string is there a way to store them in the struct formatted as shown above?
– codingstruggles
Nov 13 '18 at 21:13
1
There are, but I advise you go with the answer by Ted Lyngmo. It's much easier to understand and implement. You can use just the fscanf part, you don't need to use the other part, but it's generally good.
– Aravind Voggu
Nov 14 '18 at 4:31
add a comment |
You could use something like this to read one School entry from the FILE*
you supply:
bool School_read(School* s, FILE* in) {
int scan = fscanf(in, " %m[^,n], %m[^n]", &s->name, &s->state);
// the fscanf format string:
// <space> = skip leading whitespaces (like a newline from the line before)
// %m[^,n] = read a string until, but not including, "," or "n" m = allocate space for it
// , = expect a comma and discard it
// %m[^n] = read a string until, but not including, "n" and allocate space for it
// just a debug print
fprintf(stderr, " -- got %d hits, >%s< >%s<n", scan, s->name, s->state);
if(scan<2) {
// not a complete scan, failure
if(scan==1) {
// apparently, we got one match, free it
free(s->name);
s->name = NULL;
}
return false;
}
return true;
}
I don't know how widespread the support for the 'm' modifier that dynamically allocates memory for the strings is though. Recent gcc and clang compilers supports it anyway.
You could also make functions for creating and destroying a School:
School* School_create() {
School* s = malloc(sizeof(School));
if(s!=NULL) {
s->name = NULL;
s->state = NULL;
}
return s;
}
void School_destroy(School** sp) {
if(sp) {
School* s = *sp;
if(s) {
if(s->state) free(s->state);
if(s->name) free(s->name);
free(s);
}
*sp = NULL;
}
}
..and combine them all:
School* School_create_and_read(FILE* in) {
School* s = School_create();
if(s) {
if(School_read(s, in)==false) {
School_destroy(&s);
}
}
return s;
}
So in your function populating the array of schools:
void input_schools(FILE* IN, School** Sch, int k) {
School* s;
while( (s=School_create_and_read(IN)) ) {
// s is a valid School pointer
// store it in your array
}
}
1
Ah, this is much nice. Thanks showing us! I'm gonna use this better way the next time.
– Aravind Voggu
Nov 14 '18 at 4:34
Thank you! I very rarely use scanf myself but has its uses :-)
– Ted Lyngmo
Nov 14 '18 at 6:17
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53288290%2fhow-to-store-dynamic-string-in-a-struct-containing-char-pointer%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Your file is very similar in shape to a csv. See if you can use any csv parsing libraries or code.
Instead of checking every char, read a whole line into a buffer and use strtok. strtok is a function used to split a string by a delimiter. a ',' in your case.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char* getfield(char* line, int num)
{
const char* tok;
for (tok = strtok(line, ",");
tok && *tok;
tok = strtok(NULL, ",n"))
{
if (!--num)
return tok;
}
return NULL;
}
int main()
{
FILE* stream = fopen("in.md", "r");
char line[1024];
while (fgets(line, 1024, stream))
{
char* tmp1 = strdup(line);
char* tmp2 = strdup(line);
printf("Name is %sn", getfield(tmp1, 1));
printf("State is %sn", getfield(tmp2, 2));
// NOTE strtok changes the string. Hence two vars. You can try duplicating in the function instead.
// Note that I'm freeing the data. copying with strdup instead of directly assigning may be wise.
free(tmp1);
free(tmp2);
}
}
Sadly I have to use the format of the struct above. if I used strtok to get each string is there a way to store them in the struct formatted as shown above?
– codingstruggles
Nov 13 '18 at 21:13
1
There are, but I advise you go with the answer by Ted Lyngmo. It's much easier to understand and implement. You can use just the fscanf part, you don't need to use the other part, but it's generally good.
– Aravind Voggu
Nov 14 '18 at 4:31
add a comment |
Your file is very similar in shape to a csv. See if you can use any csv parsing libraries or code.
Instead of checking every char, read a whole line into a buffer and use strtok. strtok is a function used to split a string by a delimiter. a ',' in your case.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char* getfield(char* line, int num)
{
const char* tok;
for (tok = strtok(line, ",");
tok && *tok;
tok = strtok(NULL, ",n"))
{
if (!--num)
return tok;
}
return NULL;
}
int main()
{
FILE* stream = fopen("in.md", "r");
char line[1024];
while (fgets(line, 1024, stream))
{
char* tmp1 = strdup(line);
char* tmp2 = strdup(line);
printf("Name is %sn", getfield(tmp1, 1));
printf("State is %sn", getfield(tmp2, 2));
// NOTE strtok changes the string. Hence two vars. You can try duplicating in the function instead.
// Note that I'm freeing the data. copying with strdup instead of directly assigning may be wise.
free(tmp1);
free(tmp2);
}
}
Sadly I have to use the format of the struct above. if I used strtok to get each string is there a way to store them in the struct formatted as shown above?
– codingstruggles
Nov 13 '18 at 21:13
1
There are, but I advise you go with the answer by Ted Lyngmo. It's much easier to understand and implement. You can use just the fscanf part, you don't need to use the other part, but it's generally good.
– Aravind Voggu
Nov 14 '18 at 4:31
add a comment |
Your file is very similar in shape to a csv. See if you can use any csv parsing libraries or code.
Instead of checking every char, read a whole line into a buffer and use strtok. strtok is a function used to split a string by a delimiter. a ',' in your case.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char* getfield(char* line, int num)
{
const char* tok;
for (tok = strtok(line, ",");
tok && *tok;
tok = strtok(NULL, ",n"))
{
if (!--num)
return tok;
}
return NULL;
}
int main()
{
FILE* stream = fopen("in.md", "r");
char line[1024];
while (fgets(line, 1024, stream))
{
char* tmp1 = strdup(line);
char* tmp2 = strdup(line);
printf("Name is %sn", getfield(tmp1, 1));
printf("State is %sn", getfield(tmp2, 2));
// NOTE strtok changes the string. Hence two vars. You can try duplicating in the function instead.
// Note that I'm freeing the data. copying with strdup instead of directly assigning may be wise.
free(tmp1);
free(tmp2);
}
}
Your file is very similar in shape to a csv. See if you can use any csv parsing libraries or code.
Instead of checking every char, read a whole line into a buffer and use strtok. strtok is a function used to split a string by a delimiter. a ',' in your case.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char* getfield(char* line, int num)
{
const char* tok;
for (tok = strtok(line, ",");
tok && *tok;
tok = strtok(NULL, ",n"))
{
if (!--num)
return tok;
}
return NULL;
}
int main()
{
FILE* stream = fopen("in.md", "r");
char line[1024];
while (fgets(line, 1024, stream))
{
char* tmp1 = strdup(line);
char* tmp2 = strdup(line);
printf("Name is %sn", getfield(tmp1, 1));
printf("State is %sn", getfield(tmp2, 2));
// NOTE strtok changes the string. Hence two vars. You can try duplicating in the function instead.
// Note that I'm freeing the data. copying with strdup instead of directly assigning may be wise.
free(tmp1);
free(tmp2);
}
}
answered Nov 13 '18 at 19:58
Aravind VogguAravind Voggu
791413
791413
Sadly I have to use the format of the struct above. if I used strtok to get each string is there a way to store them in the struct formatted as shown above?
– codingstruggles
Nov 13 '18 at 21:13
1
There are, but I advise you go with the answer by Ted Lyngmo. It's much easier to understand and implement. You can use just the fscanf part, you don't need to use the other part, but it's generally good.
– Aravind Voggu
Nov 14 '18 at 4:31
add a comment |
Sadly I have to use the format of the struct above. if I used strtok to get each string is there a way to store them in the struct formatted as shown above?
– codingstruggles
Nov 13 '18 at 21:13
1
There are, but I advise you go with the answer by Ted Lyngmo. It's much easier to understand and implement. You can use just the fscanf part, you don't need to use the other part, but it's generally good.
– Aravind Voggu
Nov 14 '18 at 4:31
Sadly I have to use the format of the struct above. if I used strtok to get each string is there a way to store them in the struct formatted as shown above?
– codingstruggles
Nov 13 '18 at 21:13
Sadly I have to use the format of the struct above. if I used strtok to get each string is there a way to store them in the struct formatted as shown above?
– codingstruggles
Nov 13 '18 at 21:13
1
1
There are, but I advise you go with the answer by Ted Lyngmo. It's much easier to understand and implement. You can use just the fscanf part, you don't need to use the other part, but it's generally good.
– Aravind Voggu
Nov 14 '18 at 4:31
There are, but I advise you go with the answer by Ted Lyngmo. It's much easier to understand and implement. You can use just the fscanf part, you don't need to use the other part, but it's generally good.
– Aravind Voggu
Nov 14 '18 at 4:31
add a comment |
You could use something like this to read one School entry from the FILE*
you supply:
bool School_read(School* s, FILE* in) {
int scan = fscanf(in, " %m[^,n], %m[^n]", &s->name, &s->state);
// the fscanf format string:
// <space> = skip leading whitespaces (like a newline from the line before)
// %m[^,n] = read a string until, but not including, "," or "n" m = allocate space for it
// , = expect a comma and discard it
// %m[^n] = read a string until, but not including, "n" and allocate space for it
// just a debug print
fprintf(stderr, " -- got %d hits, >%s< >%s<n", scan, s->name, s->state);
if(scan<2) {
// not a complete scan, failure
if(scan==1) {
// apparently, we got one match, free it
free(s->name);
s->name = NULL;
}
return false;
}
return true;
}
I don't know how widespread the support for the 'm' modifier that dynamically allocates memory for the strings is though. Recent gcc and clang compilers supports it anyway.
You could also make functions for creating and destroying a School:
School* School_create() {
School* s = malloc(sizeof(School));
if(s!=NULL) {
s->name = NULL;
s->state = NULL;
}
return s;
}
void School_destroy(School** sp) {
if(sp) {
School* s = *sp;
if(s) {
if(s->state) free(s->state);
if(s->name) free(s->name);
free(s);
}
*sp = NULL;
}
}
..and combine them all:
School* School_create_and_read(FILE* in) {
School* s = School_create();
if(s) {
if(School_read(s, in)==false) {
School_destroy(&s);
}
}
return s;
}
So in your function populating the array of schools:
void input_schools(FILE* IN, School** Sch, int k) {
School* s;
while( (s=School_create_and_read(IN)) ) {
// s is a valid School pointer
// store it in your array
}
}
1
Ah, this is much nice. Thanks showing us! I'm gonna use this better way the next time.
– Aravind Voggu
Nov 14 '18 at 4:34
Thank you! I very rarely use scanf myself but has its uses :-)
– Ted Lyngmo
Nov 14 '18 at 6:17
add a comment |
You could use something like this to read one School entry from the FILE*
you supply:
bool School_read(School* s, FILE* in) {
int scan = fscanf(in, " %m[^,n], %m[^n]", &s->name, &s->state);
// the fscanf format string:
// <space> = skip leading whitespaces (like a newline from the line before)
// %m[^,n] = read a string until, but not including, "," or "n" m = allocate space for it
// , = expect a comma and discard it
// %m[^n] = read a string until, but not including, "n" and allocate space for it
// just a debug print
fprintf(stderr, " -- got %d hits, >%s< >%s<n", scan, s->name, s->state);
if(scan<2) {
// not a complete scan, failure
if(scan==1) {
// apparently, we got one match, free it
free(s->name);
s->name = NULL;
}
return false;
}
return true;
}
I don't know how widespread the support for the 'm' modifier that dynamically allocates memory for the strings is though. Recent gcc and clang compilers supports it anyway.
You could also make functions for creating and destroying a School:
School* School_create() {
School* s = malloc(sizeof(School));
if(s!=NULL) {
s->name = NULL;
s->state = NULL;
}
return s;
}
void School_destroy(School** sp) {
if(sp) {
School* s = *sp;
if(s) {
if(s->state) free(s->state);
if(s->name) free(s->name);
free(s);
}
*sp = NULL;
}
}
..and combine them all:
School* School_create_and_read(FILE* in) {
School* s = School_create();
if(s) {
if(School_read(s, in)==false) {
School_destroy(&s);
}
}
return s;
}
So in your function populating the array of schools:
void input_schools(FILE* IN, School** Sch, int k) {
School* s;
while( (s=School_create_and_read(IN)) ) {
// s is a valid School pointer
// store it in your array
}
}
1
Ah, this is much nice. Thanks showing us! I'm gonna use this better way the next time.
– Aravind Voggu
Nov 14 '18 at 4:34
Thank you! I very rarely use scanf myself but has its uses :-)
– Ted Lyngmo
Nov 14 '18 at 6:17
add a comment |
You could use something like this to read one School entry from the FILE*
you supply:
bool School_read(School* s, FILE* in) {
int scan = fscanf(in, " %m[^,n], %m[^n]", &s->name, &s->state);
// the fscanf format string:
// <space> = skip leading whitespaces (like a newline from the line before)
// %m[^,n] = read a string until, but not including, "," or "n" m = allocate space for it
// , = expect a comma and discard it
// %m[^n] = read a string until, but not including, "n" and allocate space for it
// just a debug print
fprintf(stderr, " -- got %d hits, >%s< >%s<n", scan, s->name, s->state);
if(scan<2) {
// not a complete scan, failure
if(scan==1) {
// apparently, we got one match, free it
free(s->name);
s->name = NULL;
}
return false;
}
return true;
}
I don't know how widespread the support for the 'm' modifier that dynamically allocates memory for the strings is though. Recent gcc and clang compilers supports it anyway.
You could also make functions for creating and destroying a School:
School* School_create() {
School* s = malloc(sizeof(School));
if(s!=NULL) {
s->name = NULL;
s->state = NULL;
}
return s;
}
void School_destroy(School** sp) {
if(sp) {
School* s = *sp;
if(s) {
if(s->state) free(s->state);
if(s->name) free(s->name);
free(s);
}
*sp = NULL;
}
}
..and combine them all:
School* School_create_and_read(FILE* in) {
School* s = School_create();
if(s) {
if(School_read(s, in)==false) {
School_destroy(&s);
}
}
return s;
}
So in your function populating the array of schools:
void input_schools(FILE* IN, School** Sch, int k) {
School* s;
while( (s=School_create_and_read(IN)) ) {
// s is a valid School pointer
// store it in your array
}
}
You could use something like this to read one School entry from the FILE*
you supply:
bool School_read(School* s, FILE* in) {
int scan = fscanf(in, " %m[^,n], %m[^n]", &s->name, &s->state);
// the fscanf format string:
// <space> = skip leading whitespaces (like a newline from the line before)
// %m[^,n] = read a string until, but not including, "," or "n" m = allocate space for it
// , = expect a comma and discard it
// %m[^n] = read a string until, but not including, "n" and allocate space for it
// just a debug print
fprintf(stderr, " -- got %d hits, >%s< >%s<n", scan, s->name, s->state);
if(scan<2) {
// not a complete scan, failure
if(scan==1) {
// apparently, we got one match, free it
free(s->name);
s->name = NULL;
}
return false;
}
return true;
}
I don't know how widespread the support for the 'm' modifier that dynamically allocates memory for the strings is though. Recent gcc and clang compilers supports it anyway.
You could also make functions for creating and destroying a School:
School* School_create() {
School* s = malloc(sizeof(School));
if(s!=NULL) {
s->name = NULL;
s->state = NULL;
}
return s;
}
void School_destroy(School** sp) {
if(sp) {
School* s = *sp;
if(s) {
if(s->state) free(s->state);
if(s->name) free(s->name);
free(s);
}
*sp = NULL;
}
}
..and combine them all:
School* School_create_and_read(FILE* in) {
School* s = School_create();
if(s) {
if(School_read(s, in)==false) {
School_destroy(&s);
}
}
return s;
}
So in your function populating the array of schools:
void input_schools(FILE* IN, School** Sch, int k) {
School* s;
while( (s=School_create_and_read(IN)) ) {
// s is a valid School pointer
// store it in your array
}
}
edited Nov 13 '18 at 23:30
answered Nov 13 '18 at 23:10
Ted LyngmoTed Lyngmo
2,5211317
2,5211317
1
Ah, this is much nice. Thanks showing us! I'm gonna use this better way the next time.
– Aravind Voggu
Nov 14 '18 at 4:34
Thank you! I very rarely use scanf myself but has its uses :-)
– Ted Lyngmo
Nov 14 '18 at 6:17
add a comment |
1
Ah, this is much nice. Thanks showing us! I'm gonna use this better way the next time.
– Aravind Voggu
Nov 14 '18 at 4:34
Thank you! I very rarely use scanf myself but has its uses :-)
– Ted Lyngmo
Nov 14 '18 at 6:17
1
1
Ah, this is much nice. Thanks showing us! I'm gonna use this better way the next time.
– Aravind Voggu
Nov 14 '18 at 4:34
Ah, this is much nice. Thanks showing us! I'm gonna use this better way the next time.
– Aravind Voggu
Nov 14 '18 at 4:34
Thank you! I very rarely use scanf myself but has its uses :-)
– Ted Lyngmo
Nov 14 '18 at 6:17
Thank you! I very rarely use scanf myself but has its uses :-)
– Ted Lyngmo
Nov 14 '18 at 6:17
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53288290%2fhow-to-store-dynamic-string-in-a-struct-containing-char-pointer%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
School **Sch
soSch[i]
is a pointer -Sch[i].name
should produce a compiler error. Show how you call the function.– Johnny Mopp
Nov 13 '18 at 19:40
4
Also, c-strings need to be terminated with
which you neglect to do.
– Johnny Mopp
Nov 13 '18 at 19:43
1
Try and give your variables meaningful names, especially as arguments. What is
k
?– tadman
Nov 13 '18 at 19:43
2
Hint:
strdup
instead of manually copying strings.– tadman
Nov 13 '18 at 19:44
yap. try better names, and use a better indentation and formatting. Probably install a linter, it checks for formatting & compilation errors as you type. Also, there are some nice naming conventions out there. for example, instead of
k
, I would writea_number_of_lines
. Thea_
tells me that the variable is a function argument, and the remaining part tells me what the variable has. Also, unless you need, declare the variables in the loop.for(int i = 0; i < a_numer_of_lines; i++)
– Aravind Voggu
Nov 14 '18 at 4:37