C - fclose() triggers a breakpoint - c
I'm writing a function (*rwObjects()) that will read a formatted file and save it's strings, one object at a time. Unfortunately, it's for my studies which have a restriction - stdio.h, stdlib.h and string.h is practically all I can use.
Here's the problem: whenever I run the code, when it gets to the fclose(input), VS17 says my project's triggered a breakpoint, and then opens a tab that says "wntdll.pdb not loaded" or something.
The question is: how do I not trigger the breakpoint and close the file properly? Or, if the problem isn't in the file, where is it?
Code (C):
#define _CRT_SECURE_NO_WARNINGS
#define cnCOUNTRY_LENGTH 3
#define cnOBJECT_NAME_LENGTH 30
#define cnOBJECT_MAX 1000
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//--Поле объекта objectType--
//Country (0) - строка названия страны
//ObjectName (1) - строка названия объекта
//Square (2) - площадь объекта
//Error (3) - ошибка в содержании строки
typedef enum IOOptions {Country, ObjectName, Square, Error} IOType;
//--Тип обрабатываемых объектов--
//char Country - строка названия страны
//char ObjectName - строка названия объекта
//int Square - площадь объекта
typedef struct object {
char Country[cnCOUNTRY_LENGTH];
char ObjectName[cnOBJECT_NAME_LENGTH];
int Square;
} objectType;
//--Копирование текущего элемента строки objects.txt--
//strMod - Строка, в которую идёт копирование
//strPos - Позиция в считываемой строке
//strBlueprint - Строка, из которой идёт копирование
//writeType - Поле объекта objectType. При "Country" - переводит вводимые символы в верхний регистр ('a' -> 'A' и т.д.)
void copyInputStr(char *strMod, int *strPos, char *strBlueprint, IOType writeType) {
for (*strPos; *strBlueprint != ' ' && *strBlueprint != '\n' && *strBlueprint != NULL; *strPos = *strPos + 1) {
*strMod = *strBlueprint;
if (writeType == Country) toupper(*strMod);
strBlueprint++; strMod++;
}
}
//--Запись текущего элемента строки objects.txt в текущий объект--
//strInput - Строка, из которой идёт запись
//objectOutput - Объект, в который идёт запись
//writeType - Поле объекта, в которое идёт запись
void writeObject(char *strInput, objectType *objectOutput, IOType writeType) {
if (writeType == Country)
strcpy(objectOutput->Country, strInput);
else if (writeType == ObjectName)
strcpy(objectOutput->ObjectName, strInput);
else if (writeType == Square)
objectOutput->Square = atoi(strInput);
else printf("Error 1. Invalid parameters");
}
//--Чтение objects.txt и запись в массив objectType--
//Возвращает указатель на первый элемент массива объектов
objectType *rwObjects() {
FILE *input = fopen("objects.txt", "r");
char objectQttStr[4], objectStr[38];
fgets(objectQttStr, 4, input);
objectType *objectList = (objectType *)malloc(atoi(objectQttStr)), *currentObject = objectList;
currentObject = (objectType *)malloc(atoi(objectQttStr));
for (int i = 0; i < atoi(objectQttStr); i++) {
fgets(objectStr, 38, input);
IOType inputType = Country;
for (int j = 0; objectStr[j] != NULL && objectStr[j] != '\n'; j++) {
char strBuf[cnOBJECT_NAME_LENGTH];
memset(&strBuf, 0, sizeof(strBuf));
copyInputStr(&strBuf, &j, &objectStr[j], inputType);
writeObject(&strBuf, currentObject, inputType);
inputType++;
}
currentObject++;
}
fclose(input); //this is where it happens
return objectList;
}
void main() {
objectType *objectList = rwObjects();
printf("");
}
This is one confusing program, but I've found no other way to conform the bloody rules, so let's put the coding style aside, shall we?
Also, I know that should it run successfully, nothing would happen - that is by design. It's not finished yet.
EDIT: Don't worry about validity of input data. All the input data formatting is explicitly stated in the task, ergo no checks are reqired. Still, for the curious, here it is:
objects.txt:
3
USA WelfareArrangement 120
Rus PoiskZemli 30
usa asdfEstate 1
EDIT 2: The moment I stopped using malloc, everything was fine. The question is - why exactly was it such a problem, and how would I create an array of the exact size I need, instead of creating max size evey time, if not with malloc?
First problem:
objectType *objectList = (objectType *)malloc(atoi(objectQttStr)), *currentObject = objectList;
currentObject = (objectType *)malloc(atoi(objectQttStr));
The malloc function allocates a given number of bytes. So if you have 5 objects, you only allocate 5 bytes. That's not enough for your structs. This results in you writing past the end of allocated memory which invokes undefined behavior.
If you want it to allocate space for a specific number of objects, you need to multiply by the object size:
objectType *objectList = malloc(sizeof(*objectList)*atoi(objectQttStr));
Also, don't cast the return value of malloc.
You also assign currentObject to the same value as objectList but then overwrite it with a separate memory allocation. So get rid of the second malloc.
Second problem:
memset(&strBuf, 0, sizeof(strBuf));
copyInputStr(&strBuf, &j, &objectStr[j], inputType);
writeObject(&strBuf, currentObject, inputType);
Your copyInputStr and writeObject function expect a char *, but you pass in the address of the strBuf array which has type char (*)[30]. Get rid of the address-of operator here:
memset(strBuf, 0, sizeof(strBuf));
copyInputStr(strBuf, &j, &objectStr[j], inputType);
writeObject(strBuf, currentObject, inputType);
Third problem:
void copyInputStr(char *strMod, int *strPos, char *strBlueprint, IOType writeType) {
for (*strPos; *strBlueprint != ' ' && *strBlueprint != '\n' && *strBlueprint != NULL; *strPos = *strPos + 1) {
*strMod = *strBlueprint;
if (writeType == Country) toupper(*strMod);
strBlueprint++; strMod++;
}
}
When you copy the characters in strMod, you're not adding a null byte at the end. A string in C is a null-terminated array of characters, so what you end up with is not a string but just an array of characters. When you later call strcpy on this array, the function doesn't find a null byte so it keeps reading until it does. This causes the function to read uninitialized bytes and/or read past the end of the array, which again invokes undefined behavior.
Add the null terminating byte after the loop. Also, the result of the toupper function isn't assigned to anything, so it does nothing. You need to assign it back to *strMod:
void copyInputStr(char *strMod, int *strPos, char *strBlueprint, IOType writeType) {
for (*strPos; *strBlueprint != ' ' && *strBlueprint != '\n' && *strBlueprint != NULL; *strPos = *strPos + 1) {
*strMod = *strBlueprint;
if (writeType == Country) *strMod = toupper(*strMod);
strBlueprint++; strMod++;
}
*strMod = 0;
}
Related
How to compare String to list of items in c
I saw another post about similar code but they only compared the string to one other string was wondering if this works / if there's a simple more beginner-friendly way I should learn. Thank you #include <cs50.h> #include <stdio.h> int main(void) { string user_imput = get_string("Fruit or Vegetable?, "); if (strcmp(user_imput, "apple"|| "blueberries" || "cherries" || "bananas" ||"grapes" || "oranges" || "watermelon" ||"lemons" == 0)); { printf("Fuit!, %s\n", user_imput); } else if (strcmp(user_imput, "potatoes" || "tomatoe" || "onions" || "carrot" || "bellpepper" || "lettuce" || "cucumbers" || "broccoli" == 0)); { printf("Vegtable! %s\n", user_imput); } else { printf("NA"); } }```
An easy way to do this is to create a function which searches through an array containing your strings. You then loop through comparing each one individually. If found, we return a truthy value right away. If the loop runs its course and finds nothing, we return a falsy value afterwards. int is_fruit(string food) { static const string fruits[] = { "apple", "blueberries", "cherries" /* ... */ }; for (size_t i = 0; i < (sizeof fruits / sizeof fruits[0]); i++) if (strcmp(fruits[i], food) == 0) return 1; return 0; } Then your if ... else looks something like: if (is_fruit(user_input)) { /* ... */ } else if (is_vegetable(user_input)) { /* ... */ } else { /* ... */ } A good exercise would be to complete the function above (fill out the array), and write a similar one for vegetables. An even better exercise would be to wring a more generic function that takes a string and any array of strings, and deciding if the array contains the string. Its function prototype would look like this: int string_array_contains(const string array[], size_t length, const string s); It would work very similarly to the function above, except you would have to pass in the length of the array, since sizeof cannot be used to determine the length of the array argument. If functions and arrays are too advanced for you at the moment, then simply know that you must compare each string individually using strcmp. Writing this by hand leads to very long, hard to maintain code: if (strcmp(user_input, "apple") == 0 || strcmp(user_input, "blueberries") == 0 /* ... */) { /* ... */ }
Why does my program keep getting stuck while running the mandelbrot brainf*** program?
I wanted to improve my C skills, so I search some program's ideas. Someone propose to create a simple Brainf*** interpreter and then a compiler. So here I am. I created the interpreter and it works as expected, except with the Mandelbrot program: A mandelbrot set fractal viewer in brainfuck written by Erik Bosman +++++++++++++[->++>>>+++++>++>+<<<<<<]>>>>>++++++>--->>>>>>>>>>+++++++++++++++[[ >>>>>>>>>]+[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-]>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+ <<<<<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>>+>>>>>>>>>>>>>>>>>>>>>>>>>> >+<<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+[>>>>>>[>>>>>>>[-]>>]<<<<<<<<<[<<<<<<<<<]>> >>>>>[-]+<<<<<<++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<+++++++[-[->>> >>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[[-]>>>>>>[>>>>> >>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>> [>>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<< <<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>+++++++++++++++[[ >>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[ >+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[ -<<+>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<< <<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<< [>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>> >>>>[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+ <<<<<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>> >>>>>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<< +>>>>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<< <]<+<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>> >>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<< <<<]>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<< <<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[-> >>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<< <<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]<<<<<<<[->+>>>-<<<<]>>>>>>>>>+++++++++++++++++++ +++++++>>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>[<<<<<<<+<[-<+>>>>+<<[-]]>[-<<[->+>>>- <<<<]>>>]>>>>>>>>>>>>>[>>[-]>[-]>[-]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>>>>>>[>>>>> [-<<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>[-<<<<<<<< <+>>>>>>>>>]>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>>>]+>[- ]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>>>>>>>>]<<< <<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+>>]< <[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[->>>> >>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-]<->>> [-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[>>>>>>[-< <<<<+>>>>>]<<<<<[->>>>>+<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>+>>>>>>>> ]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+ >>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[> [->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[- ]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>> [>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>++++++++ +++++++[[>>>>>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-<<<<<<<+ >>>>>>>]<<<<<<<[->>>>>>>+<<<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[ -]>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>>>]>[-<<<<<<[->>>>>+<++<<<<]>>>>>[-< <<<<+>>>>>]<->+>]<[->+<]<<<<<[->>>>>+<<<<<]>>>>>>[-]<<<<<<+>>>>[-<<<<->>>>]+<<<< [->>>>->>>>>[>>[-<<->>]+<<[->>->[-<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-] +>>>>>>[>>>>>>>>>]>+<]]+>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<<<<<<<<<<<[<<<<< <<<<]>>>>[-]+>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<< [<<<<<<<<<]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<< <<<+<[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<< <<<<<+>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<< <<<<<<<<<<]>>>>[-]<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+<]>>>>>>>>]<<< <<<<<+<[>[->>>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>[->>>>+<<<<]>]<[->>>>-<<<<<<< <<<<<<<+>>>>>>>>>>]<]>>[->>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>>+<<<< ]<<<<<<<<<<<]>>>>>>+<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>>>>>>>>>]<<<<<<<<< [>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<<<<<<< +>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<<<<<<< <<<<<]]>[-]>>[-]>[-]>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-< <<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[ [>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+ [>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->> [-<<+>>]<<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<< <[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[ >[-]<->>>[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[ >>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]> >>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>[-]>>>>+++++++++++++++[[>>>>>>>>>]<<<<<<<<<-<<<<< <<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<< <<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[- <<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>> >>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>>> [-<<<->>>]<<<[->>>+<<<]>>>>>>>>]<<<<<<<<+<[>[->+>[-<-<<<<<<<<<<+>>>>>>>>>>>>[-<< +>>]<]>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<<<]>>[-<+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<]> [-<<+>>]<<<<<<<<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>> >>>>>>]<<<<<<<<+<[>[->+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>[-<+>]>]<[-<-<<<<<<<<<<+>>>> >>>>>>>]<<]>>>[-<<+>[-<-<<<<<<<<<<+>>>>>>>>>>>]>]<[-<+>]<<<<<<<<<<<<]>>>>>+<<<<< ]>>>>>>>>>[>>>[-]>[-]>[-]>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>>>[-<<<<< <+>>>>>>]<<<<<<[->>>>>>+<<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>> >]>>[-<<<<<<<[->>>>>+<++<<<<]>>>>>[-<<<<<+>>>>>]<->+>>]<<[->>+<<]<<<<<[->>>>>+<< <<<]+>>>>[-<<<<->>>>]+<<<<[->>>>->>>>>[>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<< <<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>[-<<->>]+<<[->>->[-<<<+>>>]< <<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]< <<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+ <]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>[->>>+<<<]>]<[->>>- <<<<<<<<<<<<<+>>>>>>>>>>]<]>>[->>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>+<<< ]<<<<<<<<<<<]>>>>>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]]>>>>[-<<<<+> >>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<<[->>>- <<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[ ->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<<<<<<]]>>>>[-]<<<<]>>>>[-<<<<+>> >>]<<<<[->>>>+>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>[>>>>>> >>>]<<<<<<<<<[>[->>>>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<< <<<<<+>>>>>>>>>>>]<<]>[->>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<< <<<<]]>>>>>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>[-<<<<+ >>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<+>>>>> ]<<<<<[->>>>>+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>> >>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>> >>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[-<<+ >>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[> [->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[- ]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>> [>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<< <<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>> >>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<<+>>> >>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+ <<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>> >]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<<<<<] >>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<<<<< ]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[->>>+< <<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]> >>>>>>>]<<<<<<<<<[<<<<<<<<<]>>->>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>]<<+>>>>[-<<<< ->>>>]+<<<<[->>>>-<<<<<<.>>]>>>>[-<<<<<<<.>>>>>>>]<<<[-]>[-]>[-]>[-]>[-]>[-]>>>[ >[-]>[-]>[-]>[-]>[-]>[-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-]>>>>]<<<<<<<<< [<<<<<<<<<]>+++++++++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+>>>>>>>>>+<<<<<<<< <<<<<<[<<<<<<<<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+[-]>>[>>>>>>>>>]<<<<< <<<<[>>>>>>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<[<<<<<<<<<]>>>>>>>[-]+>>>]<<<< <<<<<<]]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+>>[>+>>>>[-<<<<->>>>]<<<<[->>> >+<<<<]>>>>>>>>]<<+<<<<<<<[>>>>>[->>+<<]<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<< <<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<<<<<<[->>>>>>+<<<<<<]< +<<<<<<<<<]>>>>>>>-<<<<[-]+<<<]+>>>>>>>[-<<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>->>[>> >>>[->>+<<]>>>>]<<<<<<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<< <<<<[->>>>>>+<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+<<< <<[<<<<<<<<<]>>>>>>>>>[>>>>>[-<<<<<->>>>>]+<<<<<[->>>>>->>[-<<<<<<<+>>>>>>>]<<<< <<<[->>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>[-< <<<<<<->>>>>>>]+<<<<<<<[->>>>>>>-<<[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<<<<<<<<<[<<< <<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<< <<[<<<<<<<<<]>>>>[-]<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>-<<<<<[<<<<<<< <<]]>>>]<<<<.>>>>>>>>>>[>>>>>>[-]>>>]<<<<<<<<<[<<<<<<<<<]>++++++++++[-[->>>>>>>> >+<<<<<<<<<]>>>>>>>>>]>>>>>+>>>>>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-<<<<<< <<+>>>>>>>>]<<<<<<<<[->>>>>>>>+[-]>[>>>>>>>>>]<<<<<<<<<[>>>>>>>>[-<<<<<<<+>>>>>> >]<<<<<<<[->>>>>>>+<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+>>]<<<<<<<<<<]]>>>>>>>>[-<<<<< <<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+>[>+>>>>>[-<<<<<->>>>>]<<<<<[->>>>>+<<<<<]>>>>>> >>]<+<<<<<<<<[>>>>>>[->>+<<]<<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[-]<- >>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<]<+<<<<<< <<<]>>>>>>>>-<<<<<[-]+<<<]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>>->[>>> >>>[->>+<<]>>>]<<<<<<<<<[>[-]<->>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<< <<<<<[->>>>>>>+<<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>> +>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<<->>>>>>]+< <<<<<[->>>>>>->>[-<<<<<<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+<<<<<<<<<<<<<<<<<[<<<<<<< <<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>> -<<[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>> >>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>[-]<<<++++ +[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>->>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<[<<<< <<<<<]]>>>] I don't understand why, but my program keeps getting stuck in some sort of endless loop. I try to debug it using gdb but it's hard to find the right breakpoint in order to see why it stuck. The program is as follows: #include <stdio.h> #include <stdlib.h> // Brainfuck instructions // > Math stuff #define INCR '+' // +1 on current MS #define DECR '-' // -1 on current MS // > Memory slot stuff #define FORW '>' // Go to next MS #define BACK '<' // Go to previous MS // > Logic stuff #define SJMP '[' // Loop till current MS value is equal to zero #define EJMP ']' // Jump to the beginning of the loop // > I/O stuff #define PRTC '.' // Print character with MS value as ASCII code #define GETC ',' // Get an user input ASCII character code typedef unsigned char byte; // The brainfuck program struct typedef struct { byte *values; int size; int index; byte *loops_starts; int loop_size; int loop_index; } BrainfuckProgram; void initialize(BrainfuckProgram *bfp) { bfp->values = malloc(bfp->size * sizeof(*bfp->values)); bfp->loops_starts = malloc(bfp->size * sizeof(*bfp->loops_starts)); } int allocate_values(BrainfuckProgram *bfp) { byte *newMem = realloc(bfp->values, bfp->size * sizeof(byte)); if (!newMem) { return 1; } bfp->values = newMem; return 0; } int allocate_new_loop(BrainfuckProgram *bfp) { byte *newMem = realloc(bfp->loops_starts, bfp->loop_size * sizeof(byte)); if (!newMem) { return 1; } bfp->loops_starts = newMem; return 0; } void set_value(BrainfuckProgram *bfp, byte value) { int tempValue = value < 0 ? 255: value % 256; *(bfp->values + bfp->index) = tempValue; } int get_value(BrainfuckProgram *bfp) { return *(bfp->values + bfp->index); } // FILE functions int get_file_name(int argc, char *argv[], char** fname) { if (argc == 1) { printf("File name is missing\n"); return 1; } *fname = argv[1]; return 0; } int get_file_size(FILE *file) { fseek(file, 0L, SEEK_END); int size = ftell(file); rewind(file); return size; } // Main function int main(int argc, char *argv[]) { // Vector part BrainfuckProgram bfp = { .values = NULL, .size = 1, .index = 0, .loops_starts = NULL, .loop_index = 0, .loop_size = 0 }; initialize(&bfp); // FILE Part char* fname = NULL; int error = get_file_name(argc, argv, &fname); if (error) { goto exit; } // Create file variable FILE *fin = NULL; fin = fopen(fname, "r"); int size = get_file_size(fin); // Create a char array of the right size byte *prog = NULL; prog = malloc(size * sizeof(*prog)); // Read 1 byte size times fread(prog, 1, size, fin); for (int i = 0; i < size; i++) { byte current = *(prog+i); switch (current) { case INCR: set_value(&bfp, get_value(&bfp) + 1); break; case DECR: set_value(&bfp, get_value(&bfp) - 1); break; case FORW: // if index+1 == size then we are at the // last element of the vector cause // size = index - 1 if (bfp.index+1 == bfp.size) { bfp.size++; int error = allocate_values(&bfp); if (error) { printf("an error occured while forwarding pointer"); goto close; } } bfp.index++; break; case BACK: // bfp.index == 0 then !bfp.index == true if (!bfp.index) { printf("can go back from index 0\n"); goto close; } bfp.index--; break; case SJMP: if (bfp.loop_index == bfp.size) { bfp.loop_size++; int error = allocate_new_loop(&bfp); if (error) { printf("an error occured while forwarding pointer"); goto close; } } bfp.loop_index++; *(bfp.loops_starts + bfp.loop_index) = i; break; case EJMP: if (bfp.loop_index == -1) { printf("cannot go back"); goto close; } if (get_value(&bfp) != 0) { i = *(bfp.loops_starts + bfp.loop_index); } else { bfp.loop_index--; } break; case PRTC: printf("%c", get_value(&bfp)); break; case GETC: ; // Semicolon here because of the label error byte buf; scanf("%c", &buf); set_value(&bfp, buf); break; } } close: fclose(fin); exit: ; return 0; } I'd like to have some C related advice on what I have done wrong too.
The Mandelbrot program takes a decent time to run on a good interpreter. Yours, well, it isn't that good. That's why it "hangs" at the start. Some good ideas that you had, performance-wise: precalculating loops Some bad ideas, performance-wise: Using abstracted allocation functions instead of calling realloc using scanf and printf instead of getchar and putchar Some odd things that you did: Manually truncating an unsigned char when wraparound is implicit checking if an unsigned char is less than 0 using *(x + y) syntax instead of array indexing x[y] I don't think you actually use those precalculated loops, if you do then probably not correctly You also probably create a new precalculated loop every time you go over the loop again Using the get_value and set_value functions instead of pointers (this will be a performance issue if you don't compile with optimizations) A couple suggestions: Try to avoid calling functions when you don't need to as much as possible. Write a BrainFuck->C compiler using this reference. On second thought, maybe you should try to debug this program instead. You may also use my interpreter as a reference if you're OK with GPLv3. Note that it doesn't precalculate loops.
Saving from a linked list to a file and loading it back
I'm having trouble loading from a file into a linked list, been trying the whole day first of all this is my struct typedef struct Sensor { int id; int intervalo; char local[30]; char tipo[30]; //bool active; int active; struct Sensor* anterior; struct Sensor* proximo; } Sensor; this is my save function which i think its working fine, since the file gets created and the content is there. void gravaLista(Sensor* l) { FILE *ficheiro; Sensor* temp = l; ficheiro = fopen("sensores.txt", "r+t"); if (ficheiro == NULL) { ficheiro = fopen("sensores.txt", "w+t"); } while (temp != NULL) { fprintf(ficheiro, "%d%d%d%30s%30s", temp->id, temp->intervalo, temp->active, temp->local, temp->tipo); temp = temp->proximo; } fclose(ficheiro); } now where i cant seem to make this work regardless of what i read about it is the load function. heres what i have atm int CarregaTodos(Sensor** l) { Sensor sens; FILE *ficheiro; int i = 0; ficheiro = fopen("sensores.txt", "r+t"); if (ficheiro == NULL) { printf("no file\n", "sensores.txt"); return i; } rewind(ficheiro); while (fscanf(ficheiro, "%d%d%d%30s%30s", &sens.id, &sens.intervalo, &sens.active, &sens.local, &sens.tipo) == 5) { //novo() function returns a pointer to a new element and insereSensor adds the new element to the last position of the list insereSensorFim(&l, novo(sens.id, sens.intervalo, sens.local, sens.tipo)); //this function inserts the new element at the end of the list } fclose(ficheiro); return i; } the helper functions work fine outside of the load function, but when i try to print the list after loading nothing gets printed. what am i missing? edit: ill just post the helper functions too Sensor* novo(int id, int tempo, char* l, char* t) { Sensor* novoSensor = (Sensor*)malloc(sizeof(struct Sensor)); //novoSensor->id = ++(*totalSens); novoSensor->id = id; novoSensor->intervalo = tempo; strcpy(novoSensor->local, l); strcpy(novoSensor->tipo, t); novoSensor->active = 1; novoSensor->anterior = NULL; novoSensor->proximo = NULL; //gravaSensor(novoSensor, (*totalSens), 1); return novoSensor; } void insereSensorFim(Sensor** Lista, Sensor* novo) { Sensor* atual = *Lista; if ((*Lista == NULL)) (*Lista = novo); else { while (atual->proximo != NULL) { atual = atual->proximo; } atual->proximo = novo; novo->anterior = atual; } } edit2: its fixed now, thanks to everyone who commented, you can read all the comments or just https://stackoverflow.com/a/44078897/8038340
Using printf() and scanf() properly is surprisingly hard. It's possible to do all sorts of magic with them, but you need to know how they work to be able to perform that magic. In the example code, you make life more difficult for yourself by not including a record delimiter in the output. A newline is the conventional and simplest delimiter, but you can choose others if you wish, or no delimiter. However, if you choose no delimiter, you have to know information about the data that is not given in the question. If the strings never contain spaces, you can be less stringent in your formatting. But you must have some way of knowing where one number ends and the next one starts — you can't simply smush all the numbers together as the sample printf() format does unless they're all negative, or you add a plus sign to the positive number (%+d). There has to be some way to tell scanf() when to stop reading one and start on the next number. This code is an elaboration of what I wrote in numerous comments. The output format uses fixed width fields; this makes it easier to read them. It does not assume there are no spaces in the strings, so it uses %29c to read 29 characters, and adds a null-terminator and removes trailing blanks via strip_blanks(). It includes code to print lists; it uses that code. #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct Sensor { int id; int intervalo; char local[30]; char tipo[30]; int active; struct Sensor *anterior; struct Sensor *proximo; } Sensor; static void insereSensorFim(Sensor **Lista, Sensor *novo); static Sensor *novoSensor(int id, int tempo, char *l, char *t); static const char *outfile = "sensores.txt"; static void gravaLista(Sensor *l) { FILE *ficheiro = fopen(outfile, "w"); if (ficheiro == NULL) { fprintf(stderr, "Failed to open file '%s' for writing\n", outfile); exit(1); } Sensor *temp = l; while (temp != NULL) { fprintf(ficheiro, "%11d%11d%11d%-29.29s%-29.29s", temp->id, temp->intervalo, temp->active, temp->local, temp->tipo); temp = temp->proximo; } fclose(ficheiro); } /* Strip trailing blanks and null terminate string */ static inline void strip_blanks(char *data, size_t size) { assert(size > 0); size_t offset = size - 1; data[offset--] = '\0'; while (offset > 0 && data[offset] == ' ') data[offset--] = '\0'; } static int CarregaTodos(Sensor **l) { Sensor sens; FILE *ficheiro; int i = 0; ficheiro = fopen(outfile, "rt"); if (ficheiro == NULL) { fprintf(stderr, "Failed to open file '%s'\n", outfile); exit(1); } while (fscanf(ficheiro, "%11d%11d%11d%29c%29c", &sens.id, &sens.intervalo, &sens.active, sens.local, sens.tipo) == 5) { strip_blanks(sens.local, sizeof(sens.local)); strip_blanks(sens.tipo, sizeof(sens.tipo)); insereSensorFim(l, novoSensor(sens.id, sens.intervalo, sens.local, sens.tipo)); } fclose(ficheiro); return i; } static inline void str_copy(char *dst, const char *src, size_t size) { assert(size > 0); strncpy(dst, src, size - 1); dst[size - 1] = '\0'; } static Sensor *novoSensor(int id, int tempo, char *l, char *t) { Sensor *novoSensor = (Sensor *)malloc(sizeof(struct Sensor)); if (novoSensor == NULL) { fprintf(stderr, "Failed to allocate %zu bytes memory\n", sizeof(struct Sensor)); exit(1); } novoSensor->id = id; novoSensor->intervalo = tempo; str_copy(novoSensor->local, l, sizeof(novoSensor->local)); str_copy(novoSensor->tipo, t, sizeof(novoSensor->tipo)); novoSensor->active = 1; novoSensor->anterior = NULL; novoSensor->proximo = NULL; return novoSensor; } static void insereSensorFim(Sensor **Lista, Sensor *novo) { Sensor *atual = *Lista; if ((*Lista == NULL)) *Lista = novo; else { while (atual->proximo != NULL) atual = atual->proximo; atual->proximo = novo; novo->anterior = atual; } } static void print_sensor(Sensor *sensor) { printf("%5d %5d %1d [%-29s] [%-29s]\n", sensor->id, sensor->intervalo, sensor->active, sensor->local, sensor->tipo); } static void print_sensor_list(const char *tag, Sensor *list) { printf("%s:\n", tag); while (list != 0) { print_sensor(list); list = list->proximo; } } static void free_sensor_list(Sensor *list) { while (list != 0) { Sensor *next = list->proximo; free(list); list = next; } } int main(void) { Sensor *list = 0; print_sensor_list("Empty", list); insereSensorFim(&list, novoSensor(10231, 23, "abc123-bothersome", "d92-x41-ccj-92436x")); insereSensorFim(&list, novoSensor(20920, 25, "def456-troublesome", "e81-p42-ggk-81366x")); insereSensorFim(&list, novoSensor(30476, 83, "ghi789-wearisome", "f70-q43-omm-70296x")); print_sensor_list("After insertion", list); gravaLista(list); free_sensor_list(list); list = 0; print_sensor_list("Emptied", list); CarregaTodos(&list); print_sensor_list("After rereading", list); insereSensorFim(&list, novoSensor(231, 325, "jkl012 blank laden stream", "minimum mess or cleaning")); insereSensorFim(&list, novoSensor(6812, -11, "mno345 longer than was expected", "maximum type of untidiness at work")); print_sensor_list("After extending", list); free_sensor_list(list); return 0; } When run, it produces the output: Empty: After insertion: 10231 23 1 [abc123-bothersome ] [d92-x41-ccj-92436x ] 20920 25 1 [def456-troublesome ] [e81-p42-ggk-81366x ] 30476 83 1 [ghi789-wearisome ] [f70-q43-omm-70296x ] Emptied: After rereading: 10231 23 1 [abc123-bothersome ] [d92-x41-ccj-92436x ] 20920 25 1 [def456-troublesome ] [e81-p42-ggk-81366x ] 30476 83 1 [ghi789-wearisome ] [f70-q43-omm-70296x ] After extending: 10231 23 1 [abc123-bothersome ] [d92-x41-ccj-92436x ] 20920 25 1 [def456-troublesome ] [e81-p42-ggk-81366x ] 30476 83 1 [ghi789-wearisome ] [f70-q43-omm-70296x ] 231 325 1 [jkl012 blank laden stream ] [minimum mess or cleaning ] 6812 -11 1 [mno345 longer than was expect] [maximum type of untidiness at] The output file, sensores.txt, looks like this: 10231 23 1abc123-bothersome d92-x41-ccj-92436x 20920 25 1def456-troublesome e81-p42-ggk-81366x 30476 83 1ghi789-wearisome f70-q43-omm-70296x When split into records, that is: 10231 23 1abc123-bothersome d92-x41-ccj-92436x 20920 25 1def456-troublesome e81-p42-ggk-81366x 30476 83 1ghi789-wearisome f70-q43-omm-70296x The integer width of 11 allows for a negative 32-bit number in each of the first two columns. If you know that the numbers are smaller, you can reduce the space used. In the scanf(), you could omit the lengths on the integer fields; it would work the same because numeric formats automatically skip white space. The printf() could add newlines; the scanning code needn't change at all because scanf() doesn't care about newlines when it is expecting a number (or a string — only %c, %[…] scan sets, and %n do not skip leading white space). You could also arrange for some character that won't appear in the character strings (perhaps Control-A, '\1') to separate the strings. Then the scanning code could look for that and you could have variable length output. Left to my own devices, I'd probably use a variable-length record with newline for the record delimiter, and a suitable field separator for the two strings, and a less rigid scanf() format. I'd read the lines with fgets() or POSIX getline() and then scan the lines using sscanf(). This would work nicely unless you can have newlines in your strings. As I put it recently in another answer — lightly paraphrased: Read the POSIX specification of printf() and scanf() for the full details. They do have some (clearly marked) extensions over standard C printf() and scanf(), but they serve for both POSIX and standard C. Then re-read them. And re-re-read them. And do that daily for a week, and then weekly for a month, and then monthly for a year, and then yearly ever after. It will repay the effort.
fprintf(ficheiro, "%d%d%d%30s%30s"... I suggest you put a delimiter, say coma or #. Imagine, your id is 11, intervalo is 10, when saved, it's 1110. How do you know, when reading from the file, the id is 11 instead of 1 or 111? change insereSensorFim(&l, to insereSensorFim(l, In insereSensorFim, you use a while loop to find the tail, it's not efficient. Let *Lista always points to the tail and skip the loop. For example, void insereSensorFim(Sensor** tail, Sensor* novo) { if (*tail != NULL) { (*tail)->proximo = novo; novo->anterior = (*tail); } *tail = nova; }
You have to separate your integers when writing to the file or else they will just look like one big number to the reading function. You could try replacing fprintf(ficheiro, "%d%d%d%30s%30s", ...); with fprintf(ficheiro, "%d;%d;%d;%29s;%29s", ...); (29 instead of 30 because you don't write the string terminating '\0') and then should be able to read back with fscanf(ficheiro, "%d;%d;%d;%29s;%29s", ...);. EDIT: After writing a smaller test code and some debugging, I figured out that if you want to use %s in the formatting of fscanf() so that the white space is stripped of the end of the strings and they're \0 terminated for you, then this would work: #include <stdio.h> #include <stdlib.h> #include <string.h> void test_save(void) { FILE *ficheiro; ficheiro = fopen("sensores.txt", "r+t"); if (ficheiro == NULL) { ficheiro = fopen("sensores.txt", "w+t"); } fprintf(ficheiro, "%d;%d;%d;%-29s ;%-29s\n", 12, 138, 131, "Local_test", "Tipo_test"); fprintf(ficheiro, "%d;%d;%d;%-29s ;%-29s\n", 21, 218, 213, "Local_test_2", "Second_tipo_test"); fclose(ficheiro); } void test_read(void) { FILE *ficheiro; ficheiro = fopen("sensores.txt", "r+t"); if (ficheiro == NULL) { printf("no file %s\n", "sensores.txt"); return; } int id, intervalo, active; char local[30], tipo[30]; while (fscanf(ficheiro, "%d;%d;%d;%29s ;%29s\n", &id, &intervalo, &active, local, tipo) == 5) { printf("id: %d intervalo: %d active: %d\tlocal: [%s]\ttipo: [%s]\n", id, intervalo, active, local, tipo); } fclose(ficheiro); } int main(void) { test_save(); test_read(); } Output of this test program: id: 12 intervalo: 138 active: 131 local: [Local_test] tipo: [Tipo_test] id: 21 intervalo: 218 active: 213 local: [Local_test_2] tipo: [Second_tipo_test] As seen by the file writen by this test-program, each record is writen in one line: 12;138;131;Local_test ;Tipo_test 21;218;213;Local_test_2 ;Second_tipo_test
Printing an array of structs in C
I'm trying to print an array of structs that contain two strings. However my print function does not print more than two indices of the array. I am not sure why because it seems to me that the logic is correct. This is the main function const int MAX_LENGTH = 1024; typedef struct song { char songName[MAX_LENGTH]; char artist[MAX_LENGTH]; } Song; void getStringFromUserInput(char s[], int maxStrLength); void printMusicLibrary(Song library[], int librarySize); void printMusicLibraryTitle(void); void printMusicLibrary (Song library[], int librarySize); void printMusicLibraryEmpty(void); int main(void) { // Announce the start of the program printf("%s", "Personal Music Library.\n\n"); printf("%s", "Commands are I (insert), S (sort by artist),\n" "P (print), Q (quit).\n"); char response; char input[MAX_LENGTH + 1]; int index = 0; do { printf("\nCommand?: "); getStringFromUserInput(input, MAX_LENGTH); // Response is the first character entered by user. // Convert to uppercase to simplify later comparisons. response = toupper(input[0]); const int MAX_LIBRARY_SIZE = 100; Song Library[MAX_LIBRARY_SIZE]; if (response == 'I') { printf("Song name: "); getStringFromUserInput(Library[index].songName, MAX_LENGTH); printf("Artist: "); getStringFromUserInput(Library[index].artist, MAX_LENGTH); index++; } else if (response == 'P') { // Print the music library. int firstIndex = 0; if (Library[firstIndex].songName[firstIndex] == '\0') { printMusicLibraryEmpty(); } else { printMusicLibraryTitle(); printMusicLibrary(Library, MAX_LIBRARY_SIZE); } This is my printing the library function // This function will print the music library void printMusicLibrary (Song library[], int librarySize) { printf("\n"); bool empty = true; for (int i = 0; (i < librarySize) && (!empty); i ++) { empty = false; if (library[i].songName[i] != '\0') { printf("%s\n", library[i].songName); printf("%s\n", library[i].artist); printf("\n"); } else { empty = true; } } }
I think the problem is caused due to setting : empty = true outside the for loop and then checking (!empty) which will evaluate to false. What I am surprised by is how is it printing even two indices. You should set empty = false as you are already checking for the first index before the function call.
The logic has two ways to terminate the listing: 1) if the number of entries is reached, or 2) if any entry is empty. I expect the second condition is stopping the listing before you expect. Probably the array wasn't built as expected (I didn't look at that part), or something is overwriting an early or middle entry.
you gave the definition as: typedef struct song { char songName[MAX_LENGTH]; char artist[MAX_LENGTH]; }Song; the later, you write if (library[i].songName[i] != '\0') which really seems strange: why would you index the songname string with the same index that the lib? so I would naturally expect your print function to be: // This function will print the music library void printMusicLibrary (Song library[], int librarySize) { for (int i = 0; i < librarySize; i ++) { printf("%s\n%s\n\n", library[i].songName, library[i].artist); } } note that you may skip empty song names by testing library[i].songName[0] != '\0' (pay attention to the 0), but I think it would be better not to add them in the list (does an empty song name make sens?) (If you decide to fix that, note that you have an other fishy place: if (Library[firstIndex].songName[firstIndex] == '\0') with the same pattern)
Parsing code for GPS NMEA string
i am trying to parse the incoming GPGGA NMEA GPS string using Arduino uno and below code. What i am trying to do is that i am using only GPGGA NMEA string to get the values of Latitude, longitude and altitude.In my below code, i had put certain checks to check if incoming string is GPGGA or not, and then store the further string in a array which can be further parsed suing strtok function and all the 3 GPS coordinates can be easily find out. But i am unable to figure out how to store only GPGGA string and not the further string.I am using a for loop but it isn't working. I am not trying to use any library.I had came across certain existing codes like this. Here is the GPGGA string information link i am trying to have following functionlity i) Check if incoming string is GPGGA ii) If yes, then store the following string upto EOL or upto * (followed by checksum for the array) in a array, array length is variable(i am unable to find out solution for this) iii) Then parse the stored array(this is done, i tried this with a different array) #include <SoftwareSerial.h> SoftwareSerial mySerial(10,11); // 10 RX / 11 TX void setup() { Serial.begin(9600); mySerial.begin(9600); } void loop() { uint8_t x; char gpsdata[65]; if((mySerial.available())) { char c = mySerial.read(); if(c == '$') {char c1 = mySerial.read(); if(c1 == 'G') {char c2 = mySerial.read(); if(c2 == 'P') {char c3 = mySerial.read(); if(c3 == 'G') {char c4 = mySerial.read(); if(c4 == 'G') {char c5 = mySerial.read(); if(c5 == 'A') {for(x=0;x<65;x++) { gpsdata[x]=mySerial.read(); while (gpsdata[x] == '\r' || gpsdata[x] == '\n') { break; } } } else{ Serial.println("Not a GPGGA string"); } } } } } } } Serial.println(gpsdata); } Edit 1: Considering Joachim Pileborg, editing the for loop in the code. I am adding a pic to show the undefined output of the code. Input for the code: $GPGGA,092750.000,5321.6802,N,00630.3372,W,1,8,1.03,61.7,M,55.2,M,,*76 $GPGSA,A,3,10,07,05,02,29,04,08,13,,,,,1.72,1.03,1.38*0A $GPGSV,3,1,11,10,63,137,17,07,61,098,15,05,59,290,20,08,54,157,30*70 $GPGSV,3,2,11,02,39,223,19,13,28,070,17,26,23,252,,04,14,186,14*79 $GPGSV,3,3,11,29,09,301,24,16,09,020,,36,,,*76 $GPRMC,092750.000,A,5321.6802,N,00630.3372,W,0.02,31.66,280511,,,A*43 $GPGGA,092751.000,5321.6802,N,00630.3371,W,1,8,1.03,61.7,M,55.3,M,,*75 $GPGSA,A,3,10,07,05,02,29,04,08,13,,,,,1.72,1.03,1.38*0A $GPGSV,3,1,11,10,63,137,17,07,61,098,15,05,59,290,20,08,54,157,30*70 $GPGSV,3,2,11,02,39,223,16,13,28,070,17,26,23,252,,04,14,186,15*77 $GPGSV,3,3,11,29,09,301,24,16,09,020,,36,,,*76 $GPRMC,092751.000,A,5321.6802,N,00630.3371,W,0.06,31.66,280511,,,A*45
After a quick check of the linked article on the NMEA 0183 protocol, this jumped out at me: <CR><LF> ends the message. This means, that instead of just read indiscriminately from the serial port, you should be looking for that sequence. If found, you should terminate the string, and break out of the loop. Also, you might want to zero-initialize the data string to begin with, to easily see if there actually is any data in it to print (using e.g. strlen).
You could use some functions from the C library libnmea. Theres functions to split a sentence into values by comma and then parse them.
Offering this as a suggestion in support of what you are doing... Would it not be useful to replace all of the nested if()s in your loop with something like: EDIT added global string to copy myString into once captured char globalString[100];//declare a global sufficiently large to hold you results void loop() { int chars = mySerial.available(); int i; char *myString; if (chars>0) { myString = calloc(chars+1, sizeof(char)); for(i=0;i<chars;i++) { myString[i] = mySerial.read(); //test for EOF if((myString[i] == '\n') ||(myString[i] == '\r')) { //pick this... myString[i]=0;//strip carriage - return line feed(or skip) //OR pick this... (one or the other. i.e.,I do not know the requirements for your string) if(i<chars) { myString[i+1] = mySerial.read() //get remaining '\r' or '\n' myString[i+2]=0;//add null term if necessary } break; } } if(strstr(myString, "GPGGA") == NULL) { Serial.println("Not a GPGGA string"); //EDIT strcpy(globalString, "");//if failed, do not want globalString populated } else { //EDIT strcpy(globalString, myString); } } //free(myString) //somewhere when you are done with it } Now, the return value from mySerial.available() tells you exactly how many bytes to read, you can read the entire buffer, and test for validity all in one.
I have a project that will need to pull the same information out of the same sentence. I got this out of a log file import serial import time ser = serial.Serial(1) ser.read(1) read_val = ("nothing") gpsfile="gpscord.dat" l=0 megabuffer='' def buffThis(s): global megabuffer megabuffer +=s def buffLines(): global megabuffer megalist=megabuffer.splitlines() megabuffer=megalist.pop() return megalist def readcom(): ser.write("ati") time.sleep(3) read_val = ser.read(size=500) lines=read_val.split('\n') for l in lines: if l.startswith("$GPGGA"): if l[:len(l)-3].endswith("*"): outfile=open('gps.dat','w') outfile.write(l.rstrip()) outfile.close() readcom() while 1==1: readcom() answer=raw_input('not looping , CTRL+C to abort') The result is this: gps.dat $GPGGA,225714.656,5021.0474,N,00412.4420,W,0,00,50.0,0.0,M,18.0,M,0.0,0000*5B
Using "malloc" every single time you read a string is an enormous amount of computational overhead. (And didn't see the corresponding free() function call. Without that, you never get that memory back until program termination or system runs out of memory.) Just pick the size of the longest string you will ever need, add 10 to it, and declare that your string array size. Set once and done. There are several C functions for getting substrings out of a string, strtok() using the coma is probably the least overhead. You are on an embedded microcontroller. Keep it small, keep overhead down. :)
#include <stdio.h> #include <string.h> #define GNSS_HEADER_LENGTH 5 #define GNSS_PACKET_START '$' #define GNSS_TOKEN_SEPARATOR ',' #define bool int #define FALSE 0 #define TRUE 1 //To trim a string contains \r\n void str_trim(char *str){ while(*str){ if(*str == '\r' || *str == '\n'){ *str = '\0'; } str++; } } /** * To parse GNSS data by header and the index separated by comma * * $GPGSV,1,1,03,23,39,328,30,18,39,008,27,15,33,035,33,1*5A * $GNRMC,170412.000,V,,,,,,,240322,,,N,V*2D * $GNGGA,170412.000,,,,,0,0,,,M,,M,,*57 * * #data_ptr the pointer points to gps data * #header the header for parsing GPGSV * #repeat_index the header may repeat for many lines * so the header index is for identifying repeated header * #token_index is the index of the parsing data separated by "," * the start is 1 * #result to store the result of the parser input * * #result bool - parsed successfully **/ bool parse_gnss_token(char *data_ptr, char *header, int repeat_index, int token_index, char *result) { bool gnss_parsed_result = FALSE; // To check GNSS data parsing is success bool on_header = FALSE; // For header int header_repeat_counter = 0; int header_char_index = 0; // each char in header index // For counting comma int counted_token_index = 0; // To hold the result character index bool data_found = FALSE; char *result_start = result; char header_found[10]; while (*data_ptr) { // 1. Packet start if (*data_ptr == GNSS_PACKET_START) { on_header = TRUE; header_char_index = 0; // to index each character in header data_found = FALSE; // is data part found data_ptr++; } // 2. For header parsing if (on_header) { if (*data_ptr == GNSS_TOKEN_SEPARATOR || header_char_index >= GNSS_HEADER_LENGTH) { on_header = FALSE; } else { header_found[header_char_index] = *data_ptr; if (header_char_index == GNSS_HEADER_LENGTH - 1) { // Now Header found header_found[header_char_index + 1] = '\0'; on_header = FALSE; if (!strcmp(header, header_found)) { // Some headers may repeat - to identify it set the repeat index if (header_repeat_counter == repeat_index) { //printf("Header: %s\r\n", header_found ); data_found = TRUE; } header_repeat_counter++; } } header_char_index++; } } // 3. data found if (data_found) { // To get the index data separated by comma if (counted_token_index == token_index && *data_ptr != GNSS_TOKEN_SEPARATOR) { // the data to parse *result++ = *data_ptr; gnss_parsed_result = TRUE; } if (*data_ptr == GNSS_TOKEN_SEPARATOR) { // if , counted_token_index++; // The comma counter for index } // Break if the counted_token_index(token_counter) greater than token_index(search_token) if (counted_token_index > token_index) { break; } } // Appending \0 to the end *result = '\0'; // To trim the data if ends with \r or \n str_trim(result_start); // Input data data_ptr++; } return gnss_parsed_result; } int main() { char res[100]; char *nem = "\ $GNRMC,080817.000,A,0852.089246,N,07636.289920,E,0.00,139.61,270322,,,A,V*04\r\n\\r\n\ $GNGGA,080817.000,0852.089246,N,07636.289920,E,1,5,1.41,11.246,M,-93.835,M,,*5E\r\n\ $GNVTG,139.61,T,,M,0.00,N,0.00,K,A*2F\r\n\ $GNGSA,A,3,30,19,17,14,13,,,,,,,,1.72,1.41,0.98,1*0A\r\n\ $GNGSA,A,3,,,,,,,,,,,,,1.72,1.41,0.98,3*02\r\n\ $GNGSA,A,3,,,,,,,,,,,,,1.72,1.41,0.98,6*07\r\n\ $GPGSV,3,1,12,06,64,177,,30,60,138,15,19,51,322,18,17,42,356,27,1*68\r\n\ $GPGSV,3,2,12,14,36,033,17,07,34,142,17,13,32,267,17,02,21,208,,1*6C\r\n\ $GPGSV,3,3,12,15,05,286,,01,05,037,,03,03,083,,20,02,208,,1*6B\r\n\ $GAGSV,1,1,00,7*73\r\n\ $GIGSV,1,1,00,1*7D\r\n\ $GNGLL,0852.089246,N,07636.289920,E,080817.000,A,A*43\r\n\ $PQTMANTENNASTATUS,1,0,1*4F\r\n"; printf("Parsing GNRMC\r\n"); printf("===============\r\n"); for(int i=1;i<=16;i++){ parse_gnss_token(nem, "GNRMC", 0, i, res); printf("Index: %d, Result: %s\r\n", i, res); } printf("Parsing GNVTG (First Parameter)\r\n"); printf("================================"); // GNVTG - Header, 0 - Repeat Index(if header is repeating), 1 - Value Index, parse_gnss_token(nem, "GNVTG", 0, 1, res); printf("\r\nGNVTG: %s\r\n", res); return 0; }