What I wanted to create was a program that takes lines from an external file of the form {key: value}
. For example, we have the file t.dat
:
{myName: Mario}
{name2: Asdadas}
{someOtherData: _D123}
My program should have ordered this data in a decreasing manner based on the length of the key
(in our case, myName
, name2
, or someOtherData
) and if two keys with the same length are found, they should be ordered lexicographically based on the value
.
I did this by using a struct array
that will keep data for every line from the document:
typedef struct Line{
char key[50];
char value[50];
}Line;
and tried to take that data out from the file by using fgets
(to take every line) and strtok
.
This is my entire code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 512
typedef struct Line{
char key[50];
char value[50];
}Line;
int comp(const void* a, const void* b)
{
const Line *aa = a;
const Line *bb = b;
puts(bb->key);
if (strlen(aa->key) == strlen(bb->key)) {
return strcmp(aa->key, bb->key);
}
return strlen(bb->value)-strlen(aa->value);
}
int main(int argc, char** argv)
{
if (argc != 2)
{
printf("Invalid number of args.\n");
return -1;
}
FILE *f = fopen(argv[1], "rb");
if (!f)
{
printf("Unable to open the specified file.\n");
return -2;
}
Line* ln;
char buff[MAX];
int lineNumber = 0;
int isSet = 0;
int i = 0;
while (fgets(buff, MAX, f))
{
char *p = strtok(buff, " {}:\n\r\t");
while (p)
{
char word[MAX] = "";
if (isSet == 0)
{
ln = malloc(1*sizeof(ln));
isSet = 1;
}
else if (i == 0) ln = (Line*)realloc(ln, (lineNumber+1)*sizeof(ln));
word[0] = '\0';
if (i == 0) {
strcpy(word, p);
strcpy(ln[lineNumber].key, word);
i = 1;
}
else if (i == 1) {
strcpy(word, p);
strcpy(ln[lineNumber].value, word);
lineNumber++;
i = 0;
}
p = strtok(NULL, " {}:\n\r\t");
}
}
qsort(ln, lineNumber, sizeof(ln), comp);
puts("\n");
for (int i = 0; i<lineNumber; i++)
{
printf("%s\n", ln[i].key);
}
return 0;
}
The problem is, the data from the first line isn't read correctly (I'm referring to value
- "Mario"
. It contains elements from the key
, but certainly not the word Mario
). Thought this may be from the strtok
, but didn't find a solution for it.
Also, the data is not ordered properly using the provided comp
function. It isn't ordered at all. The output is the same as it was before the order.
What can I do? Thank you. If any more details are needed, please tell me and I'll make sure I'll post it.
The problem is
ln = (Line*)realloc(ln, (lineNumber+1)*sizeof(ln));
you want to reserve spaces for n elements, not for n pointers to element, switch to
ln = realloc(ln, (lineNumber+1)*sizeof(*ln)); // Don't cast
also, always use a temporary variable with realloc
:
Line *temp = realloc(ln, (lineNumber+1)*sizeof(*ln));
if (temp == NULL)
{
// raise error
}
ln = temp;
Same here
qsort(ln, lineNumber, sizeof(ln), comp);
each element occupies sizeof(*ln)
, not sizeof(ln)
, switch to
qsort(ln, lineNumber, sizeof(*ln), comp);