I have a txt file, which contains groups of 3 elements in each line (2 strings for vertices and 1 integer for edge), which i want to use as input to create an adjacency list for a graph.
The txt file is as so: "string1 string2 34" and the elements are separated by tabs.
I've tried for starters trying to read from the file, using fgets , and managed to print the elements, but i'm stuck as to how i can parse them and store them. Any ideas?
A complete solution can be found at https://www.thecrazyprogrammer.com/2017/06/bellman-ford-algorithm-in-c-and-c.html
The Bellman-Ford algorithm in C is also discussed in https://stackoverflow.com/a/36831569/18980756.
Nevertheless, some code based on your input to put the elements into a dynamically allocated linked list:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct FORM {
char *vertice_one;
char *vertice_two;
int weight;
struct FORM *next;
} FORM;
int main() {
int err = 0; // error indicator
// helper to store temporarily store read values
char s1[256], s2[256];
int w;
FORM *firstEntry = NULL; // root element for the list
FILE *file = fopen("forms.txt", "r");
if (file == NULL) goto cleanup;
// read three line elements into variables
while (fscanf(file, "%s%s%d\n", &s1[0], &s2[0], &w) == 3) {
// print read elements for debugging purposes
printf("read: %s-%s-%d\n", s1, s2, w);
// dynamically allocate memory to store the read values
FORM *newEntry = malloc(sizeof *newEntry);
if (newEntry == NULL) {
fprintf(stderr, "Error - Not enough memory!");
err = 1;
goto cleanup;
}
char *vert1 = malloc(strlen(&s1[0]) + 1);
char *vert2 = malloc(strlen(&s2[0]) + 1);
if (vert1 == NULL || vert2 == NULL) {
fprintf(stderr, "Error - Not enough memory!");
err = 1;
goto cleanup;
}
memcpy(vert1, &s1[0], strlen(&s1[0]) + 1);
memcpy(vert2, &s2[0], strlen(&s2[0]) + 1);
newEntry->vertice_one = vert1;
newEntry->vertice_two = vert2;
newEntry->weight = w;
// put new entry to front a linked list
newEntry->next = firstEntry;
firstEntry = newEntry;
}
FORM *p = firstEntry;
while(p != NULL) {
printf("%s\t%s\t%d\n", p->vertice_one, p->vertice_two, p->weight);
p = p->next;
}
FORM *q;
cleanup:
q = firstEntry;
while(q != NULL) {
FORM *entry = q;
q = q->next;
if (entry->vertice_one != NULL) free(entry->vertice_one);
if (entry->vertice_two != NULL) free(entry->vertice_two);
free(entry);
}
if (file != NULL) {
fclose(file);
}
return err;
}
$ gcc -Wall -Wextra graph.c
$ ./a.out
read: vert1-vert2-1
read: vert3-vert4-2
vert3 vert4 2
vert1 vert2 1
$
Now you are in C land and can start thinking about how you want to work with the data read.
I guess
FORM should be named EDGE
vertex_one should be named source
vertex_two should be named destination
weight remains weight
You could avoid the dynamic allocation if you define arrays which are large enough to hold the data from the file.
Related
This is the one of main part of the code that the pls format file should convert to m3u format song under numbers of seconds which specified :
[playlist]
NumberOfEntries=3
File1=C:\muzika\Chris Rea - Looking For The Summer.mp3
Title1=Chris Rea - Looking For The Summer
Length1=302
File2=C:\muzika\Simply Red - Holding Back The Years.mp3
Title2=Simply Red - Holding Back The Years
Length2=265
File3=C:\muzika\Mambo Kings - Luz de luna.mp3
Title3=Mambo Kings - Luz de luna
Length3=207
Version=2
convert to:
#EXTINF:207,Mambo Kings - Luz de luna
C:\muzika\Mambo Kings - Luz de luna.mp3
#EXTINF:265,Simply Red - Holding Back The Years
C:\muzika\Simply Red - Holding Back The Years.mp3
.
if ( file != NULL )
{
char line[256];
while (fgets(line, sizeof line, file) != NULL)
{
if (count == lineNumber)
{
int j=0;
if (line[0] == 'F') {
int brojac=6;
while(line[brojac]!='\n'){
ffolder[j]=line[brojac];
j++;
brojac++;
}
folder=ffolder;
}
if (line[0] == 'T') {
int brojac=7;
while(line[brojac]!='\n'){
naslov1[j]=line[brojac];
j++;
brojac++;
}
naslov=naslov1;
}
if (line[0] == 'L') {
int brojac=8;
while(line[brojac]!='\n'){
vremee[j]=line[brojac];
j++;
brojac++;
}
vreme=vremee;
//intvreme = folder11(line);
if(atoi(vremee)<atoi(argv[3])) {
//fprintf(out, "\n#EXTINF:%s,%s\n%s", vremee,naslov1,ffolder);**key part**
struct pesma *link = (struct pesma *) malloc(sizeof(struct pesma));
link->folder = folder;
printf("%s\n",folder);
link->naslov = naslov;
printf("%s\n",naslov);
link->vreme = atoi(vreme);
link->next = NULL;
if (!glava) {
glava = link;
} else {
struct pesma *tail = glava;
while (tail->next) {
tail = tail->next;
}
tail->next = link;
}
}
}
}
else
{
count++;
}
}
}
When I call the function that should print the elements of the linked list, for each song that meets the criteria, print this:
#EXTINF:207,Mambo Kings - Luz de luna
C:\muzika\Mambo Kings - Luz de luna.mp3
#EXTINF:265,Mambo Kings - Luz de luna
C:\muzika\Mambo Kings - Luz de luna.mp3
vreme is normal,but folder and naslov are from last last line in file.
However, if I use the fprintf function (in the key part in the main code) instead of a concatenated list, the printout is correct, but then I can't sort alphabetically.
fprintf(out, "\n#EXTINF:%s,%s\n%s", vremee,naslov1,ffolder);
I'm wondering why the linked list is printed like this?
my guess - cant do better since we have an incomplete program
link->folder = folder;
link is a char * member. If so you should do
link->folder = strdup(folder);
otherwise they all end up pointing to the buffer 'folder' and whatever it last contained
Your application modified so that it reads the input data into a linked list. Using char arrays in the song struct makes them easier to handle. For sorting the list insertion sort is used.
There remains some work to do with this code:
Extract duplicate code into functions
Complete error handling, a.o. check all function return values
Maybe use a command line argument for the input file name
In general, try to use English words for names (data structures, functions, variables, etc.).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE_LENGTH 256
typedef struct song { // pesma
char file[MAX_LINE_LENGTH];
char title[MAX_LINE_LENGTH]; // naslov
int time; // vreme
struct song * next;
} SONG;
// Insertion Sort
SONG * sort_songs(SONG * root) {
if (root == NULL || root->next == NULL) {
// All lists with less than two elements are already sorted.
return root;
}
// put first element into sorted list
SONG * sorted_root = root;
// start iteration with second element
SONG * iterator = root->next;
// set end of sorted list
sorted_root->next = NULL;
while (iterator != NULL) {
// trace position directly before insertion point
SONG * previous = NULL;
// iterate over already sorted list
SONG * sorted_iterator = sorted_root;
// determine insertion point in already sorted list
while (
// list end not reached
sorted_iterator != NULL
&&
// need to advance in sorted list for proper position
strcmp(sorted_iterator->title, iterator->title) <= 0) {
previous = sorted_iterator;
sorted_iterator = sorted_iterator->next;
}
if (previous == NULL) {
// prepend sorted list with element
SONG * tmp = sorted_root;
sorted_root = iterator;
iterator = iterator->next;
sorted_root->next = tmp;
} else if (sorted_iterator == NULL) {
// append new last element in sorted list
previous->next = iterator;
SONG * tmp = iterator->next;
iterator->next = NULL;
iterator = tmp;
} else {
// insert element at correct position
SONG * tmp = iterator->next;
previous->next = iterator;
iterator->next = sorted_iterator;
iterator = tmp;
}
}
return sorted_root;
}
int main()
{
char line[MAX_LINE_LENGTH];
char *filename = "playlist.txt";
// pointer to first element of the linked song list
SONG *root = NULL; // glava
FILE *file = fopen(filename, "r");
if (file == NULL) {
fprintf(stderr, "Could not open file '%s'!\n", filename);
return EXIT_FAILURE;
}
// read line containing "[playlist]"
fgets(line, sizeof line, file);
// read line containing "NumberOfEntries=3"
fgets(line, sizeof line, file);
char *start_position = strchr(line, '=') + 1;
int number_of_entries = atoi(start_position);
printf("Number of entries: %d\n", number_of_entries);
for (int i = 0; i < number_of_entries; i++) {
// allocate new node for linked list and put it to the front of the list
SONG *node = malloc(sizeof(SONG));
node->next = root;
root = node;
// read file name
if (fgets(line, sizeof line, file) == NULL) {
fprintf(stderr, "Unexpected end of file!\n");
fclose(file);
// TODO: release allocated memory
return EXIT_FAILURE;
}
start_position = strchr(line, '=') + 1;
strcpy(node->file, start_position);
node->file[strlen(start_position) - 1] = '\0';
// read title
if (fgets(line, sizeof line, file) == NULL) {
fprintf(stderr, "Unexpected end of file!\n");
fclose(file);
// TODO: release allocated memory
return EXIT_FAILURE;
}
start_position = strchr(line, '=') + 1;
strcpy(node->title, start_position);
node->title[strlen(start_position) - 1] = '\0';
// read time
if (fgets(line, sizeof line, file) == NULL) {
fprintf(stderr, "Unexpected end of file!\n");
fclose(file);
// TODO: release allocated memory
return EXIT_FAILURE;
}
start_position = strchr(line, '=') + 1;
int time = atoi(start_position);
node->time = time;
}
// read version
if (fgets(line, sizeof line, file) == NULL) {
fprintf(stderr, "Unexpected end of file!\n");
fclose(file);
// TODO: release allocated memory
return EXIT_FAILURE;
}
start_position = strchr(line, '=') + 1;
int version = atoi(start_position);
printf("Version: %d\n", version);
root = sort_songs(root);
SONG * iterator = root;
while (iterator != NULL) {
fprintf(stdout, "\n#EXTINF:%d,%s\n%s", iterator->time, iterator->title, iterator->file);
iterator = iterator->next;
}
fprintf(stdout, "\n");
// free the allocated memory
while (root != NULL) {
SONG * next = root->next;
free(root);
root = next;
}
fclose(file);
return EXIT_SUCCESS;
}
$ gcc -Wall convert_playlist.c
$ ./a.out
Number of entries: 3
Version: 2
#EXTINF:302,Chris Rea - Looking For The Summer
C:\muzika\Chris Rea - Looking For The Summer.mp3
#EXTINF:207,Mambo Kings - Luz de luna
C:\muzika\Mambo Kings - Luz de luna.mp3
#EXTINF:265,Simply Red - Holding Back The Years
C:\muzika\Simply Red - Holding Back The Years.mp3
$
so, i saw an older post that showed how to do this, but for some reason it seems it no longer works, my input file consists of a header row, and then 15 rows of input, each with 5 columns, first 2 are strings, the last 3 are ints, i have a struct to store them, and im trying to write the contents into an array of these structs
FName LName Credits Transactions Modifer
John Doe 83000 2 1
Jane Doe 64000 5 3
I tried
struct customer cust = { NULL,NULL,0,0,0};
char line[SIZE] = { 0 }, * ptr = NULL;
cust.fName = malloc(15);
cust.lName = malloc(15);
printf("%d\n", &fp);
if (NULL == (fp = fopen("../customers.txt", "r")))
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
while (EOF != fscanf(fp, "%s", line))
{
ptr = strtok(line, "\\");
cust.fName = ptr;
printf("%s", ptr);
while (EOF != (ptr = strtok(NULL, "\\")))
{
i++;
printf("%s",ptr);
if (i == 1)
cust.lName = ptr;
else if (i == 2)
cust.miles = atoi(ptr);
else if (i == 3)
cust.years = atoi(ptr);
else if (i == 4)
cust.sequence = atoi(ptr);
}
i = 0;
printf("After Reading: fName:[%s] lName:[%s] miles:[%d] years:[%d]\n", cust.fName, cust.lName, cust.miles, cust.years);
}
For some reason, the printf within the inner while loop only prints "(null)", and errors out when i==2
with the error
File: minkernel\crts\ucrt\inc\corecrt_internal_strtox.h
Line: 1772
Expression: _p != nullptr
I dont have any idea what that error message means, so i dont know what im doing wrong
Also, Craig, do you mind giving an example, im pretty new to using C and am unfamiliar with fgets
Okay. Because your code was a bit far off, I had to refactor it heavily.
Your code was only handling a single customer record. What you need to do is a separate struct instance for each line (i.e. customer). So, we want to use realloc to enlarge a dynamic array of our struct customer.
And, you have allocate memory [on the heap] for each string in a record (i.e. first and last names). So, we have to use strdup
Anyway, here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct customer {
char *fName;
char *lName;
int miles;
int years;
int sequence;
};
int
main(void)
{
FILE *fp;
char buf[1000];
char *cp;
char *bp;
struct customer *list = NULL;
int custcnt = 0;
struct customer *cust;
const char *delim = "\t\n";
int field;
fp = fopen("customers.txt","r");
if (fp == NULL) {
perror("error opening file");
exit(1);
}
while (1) {
cp = fgets(buf,sizeof(buf),fp);
if (cp == NULL)
break;
// increase size of customer list/array by one
list = realloc(list,sizeof(*list) * (custcnt + 1));
if (list == NULL) {
perror("malloc");
exit(1);
}
// point to place for next customer
cust = &list[custcnt];
// advance customer count
++custcnt;
// preclear the new record in case of a line that is malformed (i.e.
// missing some data)
memset(cust,0,sizeof(*cust));
// loop through and store all customer record fields
bp = buf;
for (field = 0; field < 5; ++field) {
cp = strtok(bp,delim);
if (cp == NULL)
break;
bp = NULL;
switch (field) {
case 0:
cust->fName = strdup(cp);
break;
case 1:
cust->lName = strdup(cp);
break;
case 2:
cust->miles = atoi(cp);
break;
case 3:
cust->years = atoi(cp);
break;
case 4:
cust->sequence = atoi(cp);
break;
}
}
printf("After Reading: fName:[%s] lName:[%s] miles:[%d] years:[%d]\n",
cust->fName, cust->lName, cust->miles, cust->years);
}
fclose(fp);
return 0;
}
I'm trying to store file names in an array. The array is in a struct, and I want to store the names of files found in a directory in the array. However, the process that I'm using to store the names seems to be corrupting 2 or 3 of the names during the process. I think the problem is with the strdup keyword. Whenever I run my program either it reads in the program executable (which is in the directory above the directory I'm reading the files from), or weird symbols stored in the first few array locations. The following is part of my program where I'm trying to capture and store the file names, and a picture of the output results:
typedef struct{
char *filename;
}filename;
typedef struct Configs{
char file_data_path[50];
char event_log_path[50];
filename *fn_data;
}Configs;
typedef struct TestConfigs{
bool done;
int selection;
int attempts_counter;
Configs tConfig;
}TestConfigs;
void read_files(struct TestConfigs *setup);
int main(void) {
printf("Hello Test\n");
TestConfigs setup;
read_files(&setup);
system("pause");
return EXIT_SUCCESS;
}
void read_files(struct TestConfigs *setup)
{
setup->done = false;
setup->attempts_counter = 3;
char cwd[1024];
DIR *dir = NULL;
struct dirent *pent = NULL;
struct stat info;
int total_num_of_files = 0;
strcpy(setup->tConfig.file_data_path, "data/");
chdir(setup->tConfig.frame_data_path);
if((getcwd(cwd, sizeof(cwd))) != NULL)
{
printf("Current Directory: %s\n", cwd);
}
dir = opendir(cwd);
if(dir != NULL)
{
while((pent = readdir(dir)) != NULL)
{
if(stat(pent->d_name, &info))
{
printf("ERROR: stat%s: %s\n", pent->d_name, strerror(errno));
}
else
{
if(S_ISREG(info.st_mode))
{
if((strcmp(pent->d_name, ".cproject") == 0) || (strcmp(pent->d_name, ".project") == 0))
{
continue;
}
else
{
total_num_of_files++;
}
}
}
}
printf("# of files found: %d\n", total_num_of_files);
rewinddir(dir);
// SETUP ARRAY HERE!
setup->tConfig.fn_data = malloc(total_num_of_files);
total_num_of_files= 0;
printf("During Storage Process:\n");
while((pent = readdir(dir)) != NULL)
{
if(stat(pent->d_name, &info))
{
printf("ERROR: stat%s: %s\n", pent->d_name, strerror(errno));
}
else
{
if(S_ISREG(info.st_mode))
{
if((strcmp(pent->d_name, ".cproject") == 0) || (strcmp(pent->d_name, ".project") == 0))
{
continue;
}
else
{
setup->tConfig.fn_data[total_num_of_files].filename = (char*)malloc(sizeof(pent->d_name));
setup->tConfig.fn_data[total_num_of_files].filename = strdup(pent->d_name); // <- Possible source of the storage problem
printf("Filename stored in fn_data[%d] = %s\n", total_num_of_files, setup->Config.fn_data[total_num_of_files].filename);
total_num_of_files++;
}
}
}
}
printf("\n");
printf("After Storage Process:\n");
for(int i = 0; i < total_num_of_files; i++)
{
printf("Filename stored in fn_data[%d] = %s\n", i, setup->tConfig.fn_data[i].filename);
}
}
closedir(dir);
}
Output results here
What can I do to resolve the corrupt storage of the filenames in the first few array locations? How come only the first few locations aren't properly storing the filenames, but the other locations are Ok? Is the issue with strdup, and if so, what's a good alternative for capturing and storing the file names in the array? Thanks in advance!
setup->tConfig.fn_data = malloc(total_num_of_files);
One byte per file?
Need, e.g., setup->tConfig.fn_data = malloc(total_num_of_files * sizeof(filename));
This:
setup->tConfig.fn_data[total_num_of_files].filename = (char*)malloc(sizeof(pent->d_name));
setup->tConfig.fn_data[total_num_of_files].filename = strdup(pent->d_name); // <- Possible source of the storage problem
makes no sense; the strdup() will overwrite the pointer returned by malloc() and that memory will be forever lost ("leaked") which is bad.
You don't have to allocate memory for strdup(), it does that for you. It's basically:
char * strdup(const char *s)
{
const size_t sz = strlen(s) + 1;
char * const p = malloc(sz);
if (p != NULL)
memcpy(p, s, sz);
return p;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am looping through my file structure with a C program. It I hit a new folder, i appending it's path to a linked list so I can look through all subdirectories iteratively.
The program consists of:
main function, calling the iterative function (which loops through the files)
When i loop through all the files once everything works fine. However when i have a while loop in my main function to call the iterative function more often, it always fails on the second time due to segmenatation error.
So i was investigating a bit and it seems that one element of the linked list is having an invalid address.
All addresses of my elements have this format and length: 0x2398ff0 or 0x2398ee0
However the illegal pointer has an address from 0x7f3770304c58
Does anyone have any thoughts why this address is so long?
I have checked throught printf("%p", element) every new address that gets added to the linked list, and this address never appear anywhere before in the code. It like magically appears.
I was thinking about a wild pointer maybe, but after i free any pointer i set it to NULL to, which should prevent this right?
Thanks for any tip. I haven't posted the code right now cause it is very long and thought maybe there are obvious things i just dont see.
EDIT: the entire code, including main function
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
void iterativefile(FILE *f, char** field, int looper){
DIR *d;
struct dirent *dir;
typedef struct nextpath { // Define element type of linked list
char *thispath;
struct nextpath *next;
}nextpath;
nextpath *startpath = malloc(sizeof(nextpath));
char * beginning = (char *) malloc(2); //create first element in linked list, starting on root node "."
strcpy(beginning, ".");
startpath->thispath = beginning;
int found = 0;
nextpath *currentzeiger = startpath;
nextpath *firstelement = startpath;
char *newdir, *currentfile, *currentpath;
do {
currentpath = currentzeiger->thispath;
d = opendir(currentpath);
if (!d){ //IF the path is invalid or cannot be opened
firstelement = currentzeiger->next;
free(currentzeiger);
currentzeiger = firstelement;
continue;
}
while((dir = readdir(d)) != NULL){
if (dir->d_type != DT_REG){ // current element is a directory -> add it to linked list
if (strcmp(dir->d_name, ".") != 0 && strcmp(dir->d_name, "..") != 0){
newdir = (char *) malloc(2+strlen(currentpath) + strlen(dir->d_name));
strcpy(newdir, currentpath);
strcat(newdir, "/");
strcat(newdir, dir->d_name);
nextpath *new = malloc(sizeof(nextpath)); // add new folder to linked list
new->thispath = NULL;
new->thispath = strdup(newdir);
new->next = currentzeiger->next;
currentzeiger->next = new;
free(newdir);
newdir = NULL;
}
}
else { // current element is a file -> check if already included in list, if not, add it
currentfile = (char *) malloc(2+strlen(currentpath)+strlen(dir->d_name));
strcpy(currentfile, currentpath);
strcat(currentfile, "/");
strcat(currentfile, dir->d_name);
found = 0;
if (field != NULL) {
for (int z = 0; z < looper; z++){
if (field[z] != NULL){
if(strcmp(currentfile,field[z]) == 0){
found = 1;
free(field[z]);
field[z] = NULL;
}
}
}
}
if (found == 0){
char *renamefile = (char *) malloc(strlen(currentpath) + 6);
strcpy(renamefile, currentpath);
strcat(renamefile, ".cbsm");
free(renamefile);
renamefile = NULL;
}
free(currentfile);
currentfile = NULL;
}
}
firstelement = currentzeiger->next;
free(currentzeiger->thispath);
currentzeiger->thispath = NULL;
free(currentzeiger);
currentzeiger = firstelement;
closedir(d);
}while(currentzeiger != NULL);
}
int main()
{
int counterofwhile = 1;
while(1){
printf("Loop number: %d\n", counterofwhile);
counterofwhile++;
FILE *fp = fopen("datasyn.txt", "rw+");
if (fp == NULL) {
printf("FILE ERROR");
FILE *fp = fopen("datasyn.txt", "ab+");
iterativefile(fp, NULL, 0);
}
else {
int lines = 0;
int ch = 0;
int len = 0;
int max_len = 0;
while((ch = fgetc(fp)) != EOF){
++len;
if (ch == '\n'){
if(max_len < len)
max_len = len;
++lines;
len = 0;
}
}
if (len)
++lines;
fprintf(stderr, "%d lines\n", lines);
if (lines > 0){
int numProgs = 0;
char *programs[lines];
char line[max_len + 1];
rewind(fp);
while(fgets(line, sizeof(line), fp)){
int new_line = strlen(line) - 1;
if (line[new_line] == '\n')
line[new_line] = '\0';
programs[numProgs++] = strdup(line);
}
iterativefile(fp, programs, numProgs);
for (int j = 0; j < numProgs; j++){
free(programs[j]);
}
}
else {
iterativefile(fp, NULL, 0);
}
sleep(1);
printf("Done\n");
fclose(fp);
}
}
return 0;
}
In the function iterativefile(), you don't use calloc() to allocate startpath and you don't set startpath->next to null. The memory returned by malloc() is not necessarily zeroed. When you subsequently use startpath->next, all hell breaks loose.
You also don't use the file pointer passed into iterativefile(). When you remove the parameter from the definition, you change the calls, and you've got a shadowed fp in main() (in the if (fp == NULL) block, you create a new FILE *fp which is really not needed). It really isn't clear what else is meant to happen; you've not given clear instructions on what the program is meant to be doing. I don't have the datasyn.txt file, but it shouldn't matter since the file stream is not used. I got lots of lines like FILE ERRORLoop number: 280 from the code, but no crash where previously I was getting a crash.
Compile with more warning options. I called the file fp17.c and compiled my hacked version using:
gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition fp17.c -o fp17
With a few other simple changes (static before the function; int main(void)), the code compiled cleanly (and would have needed -Wshadow to spot the shadowing if it hadn't been for an 'unused variable' warning that pointed me to it).
So I got this file and i want to scanf() only the digits inside the first {} than the digits inside the second {} and so on.
I've managed to call just the digits from the file, but I don't know how to separate them into groups
this is the file:
{5, 2, 3}, {1,5}, { }, { }, {3}, { }, { }
Below is the code I use so far
void main()
{
int rc=0,num,size;
FILE* f = fopen("graph-file.txt","rt");
if (f == NULL)
{
printf("Failed to open the file\n");
}
size = fscanf(f,"%d",&num);
fseek(f,1,SEEK_CUR);
while(rc != EOF)
{
if( rc == 1)
{
printf("%d\n",num);
}
fseek(f,1,SEEK_CUR);
rc = fscanf(f,"%d",&num);
}
}
Your code as it is has some issues, for example the mode string is wrong "rt"? You only need to specify "b" for binary and that only affects the end of line character which can be a problem if the file is read/written on different platforms.
To achieve what you want there is no simple way, as #JonathanLeffler suggests in this comment you could use a json library json-c1 is a very easy to use one.
If you want to do it yourself, try this code that I did just write
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int
append_number(int size, int **arrays, int value)
{
void *pointer;
pointer = realloc(arrays[0], (++size + 1) * sizeof(**arrays));
if (pointer == NULL)
return 0;
arrays[0] = pointer;
arrays[0][size] = value;
return 1;
}
int
get_value(const char *input)
{
if (input == NULL)
return -1;
while ((*input != '\0') && (isspace((unsigned char) *input) != 0))
input++;
if (*input == '\0')
return -1;
return atoi(input);
}
int *
extract_arrays(char *array)
{
int value;
int *list;
list = malloc(sizeof(*list));
if (list == NULL)
return NULL;
list[0] = 0;
while (array != NULL)
{
char *delimiter;
delimiter = strchr(array, ',');
if (delimiter != NULL)
*delimiter = '\0';
value = get_value(array);
if (value > 0)
list[0] += append_number(list[0], &list, value);
if (delimiter != NULL)
array = delimiter + 1;
else
array = NULL;
}
return list;
}
void
print_array(int *list)
{
fprintf(stdout, "[");
for (int j = 1 ; j < list[0] ; ++j)
fprintf(stdout, "%d ", list[j]);
if (list[0] > 0)
fprintf(stdout, "%d", list[list[0]]);
fprintf(stdout, "]\n");
}
int **
parse_line(char *line, size_t *count)
{
char *open;
char *close;
char *next;
int **arrays; // Depends on the maximum size of an inner array
*count = 0;
arrays = NULL;
next = line;
while ((next != NULL) && ((open = strchr(next, '{')) != NULL))
{
close = strchr(open, '}');
if (close != NULL)
{
void *pointer;
char *values;
*close = '\0';
next = strchr(close + 1, ',');
values = open + 1;
pointer = realloc(arrays, (*count + 1) * sizeof(*arrays));
if (pointer == NULL)
goto error;
arrays = pointer;
arrays[(*count)++] = extract_arrays(values);
}
else
next = open + 1;
}
return arrays;
error:
for (size_t i = 0 ; i < *count ; ++i)
free(arrays[i]);
free(arrays);
*count = 0;
return NULL;
}
int main(void)
{
char line[100];
size_t count;
int **arrays;
FILE *file;
file = fopen("graph-file.txt", "r");
if (file == NULL)
return -1; // Failure openning the file
while (fgets(line, sizeof(line), file) != NULL)
{
arrays = parse_line(line, &count);
for (size_t i = 0 ; i < count ; ++i)
{
print_array(arrays[i]);
// DO something with it ...
free(arrays[i]);
}
free(arrays);
}
fclose(file);
return 0;
}
Of course, there are a lot of possible optimizations (specially the realloc() parts), but I leave that to you.
Above, the int ** pointer returned by parse_line() contains count arrays where the first element is the length of each array.
1I know that on most linux distributions it can be installed with the package manager, and I have been using it a lot recently for some web development related projects.
Arrays are probably what you're going to need to accomplish this task. Arrays allow you to have various amounts of digits that you can store what you read into. That's how you can separate the groupings. The next part will be how to change which part of the array you're looking at, which this link should also help with.
C Arrays Tutorial.
If the numbers that you're trying to read will only be single digit numbers, then you could ditch the fseek and fscanf functions and use getc instead. Just check each read for anything that's not a number '0'-'9'.
C getc
Those websites I linked also have a lot of other good tutorials on them for learning C\C++.
Good luck.
Edit: less condescending.