Trouble using strcmp in c code - c

I've used strcmp before and it worked as expected, but it's not working for me in my current code.
I'm reading a .csv file with the names of a bunch of famous people. "Mark Zuckerberg" is the key name that triggers things that my code will eventually do (once I get past this bump in the road and this has nothing to do with what he's been in the news for lately). I'm using a counter (queue_size) to count the number of lines in the .csv file. My goal is to save the value of the counter when strcmp(temp_name, key) == 0 but I'm not entering that if statement and I can't see why.
The key appears in the .csv file as "Mark,Zuckerberg". I've tried using strtok to eliminate the comma. I was successful in doing that but strcmp() still isn't working (I adjusted the key to be "MarkZuckerberg"). I also added memset to clean the slate with each iteration but that didn't resolve the issue either.
Commenting the line, temp_name[strlen(temp_name) - 1] = '\0'; doesn't appear to change anything either. I know that my struct is getting all of the names because printf (I've since deleted) and my print_list function prints as expected.
I really need help finding out why I'm not entering that if statement.
Thanks in advance for any help that anyone can provide.
I think that it's something dumb that I'm overlooking but I just can't find it.
Here's my code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct char_node {
char name[40];
struct char_node *next;
} char_node;
typedef struct char_queue {
char_node *q_head;
char_node *q_tail;
int q_size;
} char_queue;
void enqueue(char_queue *q_ptr, char new_name[40]);
//int dequeue(char_queue *q_ptr);
void print_list(char_queue *queue);
int main() {
int queue_size = 0;
int m_z_position;
char_queue queue;
char temp_name[40];
char key[] = "Mark,Zuckerberg";
queue.q_head = NULL;
queue.q_tail = NULL;
queue.q_size = 0;
FILE *file_input;
file_input = fopen("party.csv", "r");
memset(temp_name, '\0', sizeof(temp_name));
while(fgets(temp_name, sizeof(temp_name), file_input)) {
temp_name[strlen(temp_name) - 1] = '\0';
if(strcmp(temp_name, key) == 0) {
printf("test\n");
m_z_position = queue_size;
}
enqueue(&queue, temp_name);
memset(temp_name, '\0', sizeof(temp_name));
queue_size++;
}
fclose(file_input);
//print_list(&queue);
printf("m_z_position = %d\n", m_z_position);
return 0;
}
void enqueue(char_queue *q_ptr, char new_name[40]) {
char_node *new_node = (char_node*)malloc(sizeof(char_node));
strcpy(new_node->name, new_name);
new_node->next = NULL;
int num;
if(q_ptr->q_size == 0) {
q_ptr->q_tail = new_node;
q_ptr->q_head = new_node;
} else {
q_ptr->q_tail->next = new_node;
q_ptr->q_tail = new_node;
}
(q_ptr->q_size)++;
return;
}
void print_list(char_queue *queue) {
char_node *temp_list;
if(queue->q_head != NULL) {
temp_list = queue->q_head;
while(temp_list != NULL) {
printf("%s\n", temp_list->name);
temp_list = temp_list->next;
}
}
printf("\n");
return;
}
I can't figure out how to add the file but here are the contents of the .csv file
Jeff,Bezo
Bill,Gates
Warren,Buffett
Berkshire,Hathaway
Bernard,Arnault
Amancio,Ortega
Carlos,Slim
Charles,Koch
David,Koch
Larry,Ellison
Michael,Bloomberg
Larry,Page
Sergey,Brin
Jim,Walton
S,Robson
Alice,Walton
Ma,Huateng
Francoise,Bettencourt
Mukesh,Ambani
Jack,Ma
Sheldon,Adelson
Steve,Ballmer
Li,Ka-shing
Hui,Ka
Lee,Shau
Wang,Jianlin
Beate,Heister
Phil,Knight
Jorge,Paulo
Francois,Pinault
Georg,Schaeffler
Susanne,Klatten
David,Thomson
Jacqueline,Mars
John,Mars
Joseph,Safra
Giovanni,Ferrero
Dietrich,Mateschitz
Michael,Dell
Masayoshi,Son
Serge,Dassault
Stefan,Quandt
Yang,Huiyan
Paul,Allen
Leonardo,Del
Dieter,Schwarz
Thomas,Peterffy
Theo,Albrecht
Len,Blavatnik
He,Xiangjian
Lui,Che
James,Simons
Henry,Sy
Elon,Musk
Hinduja,family
Tadashi,Yanai
Vladimir,Lisin
Laurene,Powell
Azim,Premji
Alexey,Mordashov
Lee,Kun-Hee
Lakshmi,Mittal
Wang,Wei
Leonid,Mikhelson
Charoen,Sirivadhanabhakdi
Pallonji,Mistry
Ray,Dalio
Takemitsu,Takizaki
William,Ding
R,Budi
Gina,Rinehart
German,Larrea
Carl,Icahn
Stefan,Persson
Michael,Hartono
Joseph,Lau
Thomas,A
Vagit,Alekperov
James,Ratcliffe
Donald,Bren
Iris,Fontbona
Gennady,Timchenko
Abigail,Johnson
Vladimir,Potanin
Lukas,Walton
Charlene,de
Zhang,Zhidong
Petr,Kellner
Andrey,Melnichenko
David,A
Klaus-Michael,Kuehne
Li,Shufu
Mikhail,Fridman
Rupert,Murdoch
Dhanin,Chearavanont
Robert,Kuok
Emmanuel,Besnier
Shiv,Nadar
Viktor,Vekselberg
Aliko,Dangote
Harold,Hamm
Steve,Cohen
Dustin,Moskovitz
Marcel,Herrmann
Reinhold,Wuerth
Charles,Ergen
Eric,Schmidt
Philip,Anschutz
Jim,Kennedy
Blair,Parry-Okeden
Alain,Wertheimer
Gerard,Wertheimer
Leonard,Lauder
Heinz,Hermann
Dilip,Shanghvi
Hasso,Plattner
Stephen,Schwarzman
Lei,Jun
Hans,Rausing
Alisher,Usmanov
Donald,Newhouse
Peter,Woo
Luis,Carlos
Robin,Li
Carlos,Alberto
Seo,Jung-Jin
Kumar,Birla
Alexander,Otto
Stefano,Pessina
Udo,A
Wang,Wenyin
Andrew,Beal
Lee,Man
John,Menard
Xu,Shihui
Zhou,Hongyi
Gong,Hongjia
Michael,Otto
David,Tepper
Roman,Abramovich
Liu,Qiangdong
Robert,A
Alberto,Bailleres
Uday,Kotak
Pierre,Omidyar
Walter,PJ
Dietmar,Hopp
Graeme,Hart
Eduardo,Saverin
Yan,Zhi
Radhakishan,Damani
German,Khan
Ronald,Perelman
Gautam,Adani
Micky,Arison
Pan,Zhengmin
Joseph,Tsai
Thomas,Frist
Mikhail,Prokhorov
Galen,Weston
Zong,Qinghou
Eyal,Ofer
Charles,Schwab
Gianluigi,A
Herbert,Kohler
Viktor,Rashnikov
Harry,Triguboff
August,von
Yao,Zhenhua
Jan,Koum
Cyrus,Poonawalla
James,Goodnight
Ken,Griffin
Giorgio,Armani
Ernesto,Bertarelli
Savitri,Jindal
Sunil,Mittal
James,Chambers
Katharine,Rayner
Margaretta,Taylor
Terry,Gou
Gordon,Moore
James,Irving
Stanley,Kroenke
Melker,Schorling
Johann,Graf
Guo,Guangchang
John,Malone
Xavier,Niel
Silvio,Berlusconi
Carl,Cook
David,Geffen
Hui,Wing
Walter,Kwok
George,Soros
Edward,Johnson
Massimiliana,Landini
David,Duffield
George,Kaiser
Patrick,Soon-Shiong
Zhou,Qunfei
Nicky,Oppenheimer
Sun,Piaoyang
Wu,Yajun
Alexei,Kuzmichev
Stephen,Ross
Vincent,Bollore
Pauline,MacMillan
Jay,Y
Anders,Holch
Eli,Broad
Michael,Kadoorie
Iskander,Makhmudov
Frederik,Paulsen
Sun,Hongbin
Christy,Walton
Shahid,Khan
Ananda,Krishnan
Carrie,Perrodo
Quek,Leng
Wang,Wenxue
John,Doerr
Patrick,Drahi
Eva,Gonda
Willi,A
Ricardo,Salinas
Suh,Kyung-Bae
Pollyanna,Chu
John,Fredriksen
Goh,Cheng
Sri,Prakash
Lu,Zhiqiang
Jorn,Rausing
Johann,Rupert
Jacques,Saade
Wu,Shaoxun
Leonid,Fedun
Kim,Jung-Ju
Sandra,Ortega
Jim,Pattison
Michael,Platt
Chan,Laiwa
David,Green
Hank,A
Dmitry,Rybolovlev
Tsai,Eng-Meng
Andreas,von
Oleg,Deripaska
Liu,Yongxing
Ludwig,Merckle
Brian,Acton
John,Grayken
Ann,Walton
Augusto,A
Finn,Rausing
Mark,Zuckerberg
Kirsten,Rausing
Odd,Reitan
Nassef,Sawiris
Wee,Cho
Aloys,Wobben
Leon,Black
Ivan,Glasenberg
John,Paulson
Wei,Jianjun
Francis,Choi
Erivan,Haub
Jason,Jiang
Suleiman,Kerimov
Ian,A
Pang,Kang
David,Shaw
Kushal,Pal
John,A
Acharya,Balkrishna
Guenther,Fielmann
Daniel,Gilbert
Antonia,Johnson
Vikram,Lal
Akira,Mori
Maria-Elisabeth,Schaeffler-Thumann
Albert,Frere
Richard,Kinder
Robert,Kraft
Ralph,Lauren
Bruno,Schroder
Nusli,Wadia
Pierre,Bellon
Les,Wexner
Benu,Gopal
David,Cheriton
Ma,Jianrong
Whitney,MacMillan
Dan,Olsson
Vivek,Chaand
Teh,Hong
Abdulla,bin
Maria,Asuncion
Ralph,Dommermuth
Frank,Lowy
Wolfgang,Marguerre
Marijke,Mars
Pamela,Mars
Valerie,Mars
Victoria,Mars
David,A
John,Gokongwei
Kwon,Hyuk-Bin
Nancy,Walton
Lin,Yu-Ling
Tom,A
Robert,Rowling
Dennis,Washington
Yao,Liangsong
Zhang,Jindong
Juan,Francisco
David,Sun
John,Tu
Martin,Viessmann
Stef,Wertheimer
Hansjoerg,Wyss
James,Dyson
Laurence,Graff
Jen-Hsun,Huang
Charles,Johnson
Jerry,Jones
Kei,Hoi
Kwee,family
Lee,Shin
Richard,LeFrak
Shigenobu,Nagamori
Steven,Rales
Friede,Springer
Yeung,Kin-man
Rinat,Akhmetov
Shari,Arison
Dannine,Avara
Rahel,Blocher
Andrew,Currie
Scott,Duncan
Milane,Frantz
Diane,Hendricks
Magdalena,Martullo-Blocher
Hiroshi,Mikitani
Gabe,Newell
Pan,Sutong
Anthony,Pratt
John,Reece
Randa,Williams
Zhang,Bangxin

I was fixing your code, but as this comment already state, your file use "\r\n" as end line code, can be fixed with str[strcspn(str, "\r\n")] = '\0'; just after your read.
But here, an other exemple of implementation of your code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct char_node {
struct char_node *next;
char name[];
} char_node;
typedef struct char_queue {
char_node *q_head;
char_node *q_tail;
size_t q_size;
} char_queue;
char_node *enqueue(char_queue *q_ptr, char const *new_name);
void print_list(char_queue const *queue);
int main(void) {
char_queue queue = { .q_head = NULL, .q_tail = NULL, .q_size = 0 };
char const key[] = "Mark,Zuckerberg";
FILE *file_input = fopen("party.csv", "r");
if (file_input == NULL) {
file_input = stdin;
}
char str[40];
size_t m_z_position = 0;
while (fgets(str, sizeof str, file_input)) {
str[strcspn(str, "\r\n")] = '\0';
if (strcmp(str, key) == 0) {
m_z_position = queue.q_size;
}
enqueue(&queue, str);
}
fclose(file_input);
print_list(&queue);
printf("m_z_position = %zu\n", m_z_position);
}
char_node *enqueue(char_queue *q_ptr, char const *name) {
size_t i = strlen(name) + 1;
char_node *node = malloc(sizeof *node + i);
if (!node) {
return NULL;
}
strcpy(node->name, name);
node->next = NULL;
if (q_ptr->q_size++ == 0) {
q_ptr->q_tail = q_ptr->q_head = node;
} else {
q_ptr->q_tail = q_ptr->q_tail->next = node;
}
return node;
}
void print_list(char_queue const *queue) {
for (char_node const *list = queue->q_head; list; list = list->next) {
printf("%s\n", list->name);
}
printf("\n");
}

I am afraid that .csv file contains "Mark,Zuckerberg" not Mark,Zuckerberg.
In if(strcmp(temp_name, key) == 0){ key is compared with temp_name.
Here key is Mark,Zuckerberg.
int strcmp(const char *s1, const char *s2);
The strcmp() and strncmp()
functions return an integer greater than, equal to, or less than 0,
according as the string s1 is greater than, equal to, or less than the
string s2.
strcmp will return positive number if temp_name is "Mark,Zuckerberg" because it contains additional 2 characters and, 0 if temp_name is Mark,Zuckerberg as key here is Mark,Zuckerberg clearly.

Related

Losing struct values after assigning 'next' and 'prev' struct pointers

I am creating a Book Management system in which the user can search by the title or the author of the book. The problem I am running into is when I try to get the values from the books. When searching for the author, all I get are symbols and an infinite for loop, instead of any of the authors that are already saved in config.
I am more than certain that it is something wrong with the way I am storing these values, but am not sure.
main.c:
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char * argv[]) {
struct Books books;
// Config works fine and dandy, don't need to worry about this
cfg = read_config(cfg, "test-cfg.cfg");
for (int size = 0; size < cfg.valuesSize; size++) {
// Gets values from the config and assigns the values to the struct Books
books.id = atoi(cfg.values[size][0][1]);
strcpy(books.name, cfg.values[size][1][1]);
strcpy(books.author, cfg.values[size][2][1]);
strcpy(books.description, cfg.values[size][3][1]);
// Assign prev and next in Books struct
struct Books nextBook;
books.next = &nextBook;
nextBook.prev = &books;
books = *books.next;
}
// This throws Frontend screens at the user
// While also pipelining to backend functions
while(true) {
int welcome = 1;
switch (welcome) {
case 1: {
struct Books booksFound[cfg.valuesSize];
int booksFoundPtr = 0;
int searchOption = 2;
getchar();
if (searchOption==2) {
printf("Enter the Author: ");
char bookAuthor[AUTHOR_MAX];
fgets(bookAuthor, AUTHOR_MAX, stdin);
// Here is where the code screws up.
// It gives me random symbols instead of the book author's name
for (; books.id >= 1; books = *books.prev) {
if (strncmp(books.author, bookAuthor, strlen(books.author))==0) {
booksFound[booksFoundPtr] = books;
booksFoundPtr++;
}
}
}
// Used for showing all matching book authors
for (int i = 0; i < booksFoundPtr; i++) {
printf("ID:%d\nTITLE:%s\nAUTHOR:%s\nDESCRIPTION:%s\n", booksFound[i].id, booksFound[i].name, booksFound[i].author, booksFound[i].description);
char option[2] = {'\0'};
fgets(option, 2, stdin);
switch(atoi(option)) {
case 1: {
if (i+1 == booksFoundPtr) {
i--;
}
break;
}
case 2: {
if (i-1 < 0) {
i--;
break;
}
else {
i-=2;
}
break;
}
default: {
break;
}
}
}
// Rewinds books for next use
while(books.id != cfg.valuesSize) {
books = *books.next;
}
continue;
}
default: {
continue;
}
}
break;
}
return 0;
}
books.h
#define NAME_MAX 60
#define AUTHOR_MAX 100
#define DESCRIPTION_MAX 240
struct Books {
int id;
char name[NAME_MAX];
char author[AUTHOR_MAX];
char description[DESCRIPTION_MAX];
struct Books * next;
struct Books * prev;
};

Mors Alphabet Segmentation Fault

My code doesn't adding second node to tree. It gives me SIGSEGV fault when i'm adding the second node.I think its about strcmp function but when i'm trying to understand how it works properly at the very bottom of main func it returns -1 so i've wrote it like this.And most of my variables named Turkish so here are the translations of them to make you understand more easily
dugum=node,kok=root;sol=left;sag=right;anne=mother
// C program to demonstrate insert operation in binary search tree
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct tree {
char *harf;
char *morskodu;
struct tree *left;
struct tree *right;
} agac;
agac *kok = NULL;
void ekle(char *harf, char *morskodu) {
if (kok == NULL) {
kok = (agac *)malloc(sizeof(agac));
kok->harf = harf;
kok->morskodu = morskodu;
kok->left = NULL;
kok->right= NULL;
} else {
agac *yeni = (agac *)malloc(sizeof(agac));
yeni->harf = harf;
yeni->morskodu = morskodu;
yeni->left = NULL;
yeni->right = NULL;
agac *dugum = kok, *anne;
while (dugum != NULL) {
anne = dugum;
if (harf <= dugum->harf)
dugum = dugum->left;
else
dugum = dugum->right;
}
if (harf <= dugum->harf)
anne->left = yeni;
else
anne->right = yeni;
}
}
void dolas(agac *dugum) {
if (dugum != NULL) {
printf(" %s ", dugum->harf);
dolas(dugum->left);
dolas(dugum->right);
}
}
void main() {
ekle("a", "-");
ekle("b", "-.");
dolas(kok);
int x = strcmp("A", "B");
printf("%d", x);
}
You try to dereference a NULL pointer.
while (dugum != NULL) {
anne = dugum;
if (harf <= dugum->harf)
dugum = dugum->sol;
else
dugum = dugum->sag;
}
This loop ends when dugum is NULL.
Directly after you try to access dugum->harf:
if (harf <= dugum->harf)
This leads to undefined behavior.
Also note that this comparisons compare the pointers to string literals, and is therefore also undefined behavior. To compare two C strings you should use strcmp.

How to efficiently find last key and value in GTree

I need to develop a set of functions to extend glib2 GTree with:
find first element
find last
find nearest (floor, ceil, greatest less than, least greater than)
Finding first is easy. You simply stop the g_tree_foreach() calback after first. But how to find the last element without traversing the whole tree?
I thought I could use g_tree_search() with a callback that keeps returning a positive value until found, but how do I know I'm currently on the last element?
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <glib.h>
static
gint compare_int(gconstpointer p1, gconstpointer p2) {
int i1 = GPOINTER_TO_INT(p1);
int i2 = GPOINTER_TO_INT(p2);
//printf("%d %d\n", i1, i2);
return i1 == i2 ? 0 : i1 > i2 ? 1 : -1;
}
static
gboolean traverse(gpointer key, gpointer value, gpointer data) {
//int ikey = GPOINTER_TO_INT(key);
const char *sval = (const char *)value;
printf("%s\n", sval);
return FALSE;
}
static
gint find_last(gconstpointer p, gpointer user_data) {
return 1;
}
static inline const char *NULS(const char *s) {
return s ? s : "NULL";
}
int main(int argc, char *argv[]) {
GTree *tree = g_tree_new(compare_int);
g_tree_insert(tree, GINT_TO_POINTER(10), "ten");
g_tree_insert(tree, GINT_TO_POINTER(-99), "minus ninety-nine");
g_tree_insert(tree, GINT_TO_POINTER(8), "eight");
g_tree_foreach(tree, traverse, NULL);
printf("=======\n%s\n", NULS((const char*)g_tree_search(tree, (GCompareFunc)find_last, NULL)));
return 0;
}
I didn't want to fully implement my own tree, because I wanted to perform advanced search on GTree instances received from 3rd-party code.
Instead I thought that Glib authors would hardly change their internal structures these days and that I could use their fields directly.
The result is the extended version of the internal function g_tree_find_node() from gtree.c. I added two parameters to control whether I want first, last or nearest node. The algorithm for nearest nodes differs from java's TreeMap, because our node doesn't have a pointer to its parent. Full code with the unit test is here: gtreeex.c.
typedef enum {
FIND_EXACT = 0,
FIND_FLOOR = 0x2,
FIND_CEIL = 0x20,
FIND_LOWER = (FIND_FLOOR + 1),
FIND_HIGHER = (FIND_CEIL + 1)
} find_mode;
static GTreeNode *
g_tree_find_node_ex (GTree *tree,
gconstpointer key,
GCompareDataFunc key_compare,
find_mode mode
)
{
GTreeNode *node;
gint cmp;
GTreeNode *last_lesser_node = NULL;
GTreeNode *last_greater_node = NULL;
node = tree->root;
if (!node)
return NULL;
while (1)
{
cmp = key_compare (key, node->key, tree->key_compare_data);
if (cmp == 0) {
if (mode == FIND_LOWER) {
cmp = -1;
} else if (mode == FIND_HIGHER) {
cmp = 1;
} else {
return node;
}
}
if (cmp < 0)
{
if (!node->left_child) {
if ( (mode & FIND_FLOOR) ) {
return last_lesser_node; /* can be null */
}
if ( (mode & FIND_CEIL) ) {
return node;
}
return NULL;
}
last_greater_node = node;
node = node->left;
}
else
{
if (!node->right_child) {
if ( (mode & FIND_CEIL) ) {
return last_greater_node; /* can be null */
}
if ( (mode & FIND_FLOOR) ) {
return node;
}
return NULL;
}
last_lesser_node = node;
node = node->right;
}
}
}
For better performance it's possible to use preprocessor macros instead of the two new parameters, replace if with #if and include the bits header multiple times.

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

FreeImage include in c

Is there any way to include http://freeimage.sourceforge.net/index.html in my c test program without first installing the library? It fails to compile because of some memset..
Here is my C code. Is there any way to make it work? Please try compiling it and tell me how to do it if it works?
#define NAZIV_DATOTEKE 50
#include <stdio.h>
#include "FreeImage.h"
void FreeImageErrorHandler(FREE_IMAGE_FORMAT fif, const char *message);
FIBITMAP* GenericLoader(const char* lpszPathName, int flag);
int main(){
FreeImage_Initialise();
FIBITMAP *dib, *ptr;
char ulaz_slika[NAZIV_DATOTEKE] = "bmp_24.bmp";
char izlaz_slika[NAZIV_DATOTEKE] = "free.bmp"; //podrazumevana vrednost
dib = GenericLoader(ulaz_slika, 0);
//slika = FreeImage_Load(FIF_BMP, "bmp_24.bmp", BMP_DEFAULT);
FreeImage_SetOutputMessage(FreeImageErrorHandler);
if (dib) {
printf("Ucitan \"%s\".\n", ulaz_slika);
}
FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(ulaz_slika, 0);
if ((fif != FIF_BMP) && (fif != FIF_ICO) && (fif != FIF_JPEG) && (fif != FIF_PNG) && (fif != FIF_TIFF)){
printf("Format slike nije podrzan.\n");
return 1;
}
ptr = FreeImage_ConvertTo24Bits(dib);
FreeImage_SetOutputMessage(FreeImageErrorHandler);
FreeImage_Unload(dib);
FreeImage_SetOutputMessage(FreeImageErrorHandler);
dib = ptr;
if (dib) {
printf("Konvertovan u RGB.\n");
}
const char *slika = (const char*)FreeImage_GetBits(dib);
if (FreeImage_Save(fif, dib, izlaz_slika, BMP_DEFAULT)) {
printf("Snimljen \"%s\".\n", izlaz_slika);
}
if (dib) {
FreeImage_Unload(dib);
}
FreeImage_DeInitialise();
return 0;
}
void FreeImageErrorHandler(FREE_IMAGE_FORMAT fif, const char *message){
printf("\n*** ");
if(fif != FIF_UNKNOWN) {
if (FreeImage_GetFormatFromFIF(fif))
printf("%s Format\n", FreeImage_GetFormatFromFIF(fif));
}
printf(message);
printf(" ***\n");
}
FIBITMAP* GenericLoader(const char* lpszPathName, int flag) {
FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
// check the file signature and deduce its format
// (the second argument is currently not used by FreeImage)
fif = FreeImage_GetFileType(lpszPathName, 0);
if(fif == FIF_UNKNOWN) {
// no signature ?
// try to guess the file format from the file extension
fif = FreeImage_GetFIFFromFilename(lpszPathName);
}
// check that the plugin has reading capabilities ...
if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) {
// ok, let's load the file
FIBITMAP *dib = FreeImage_Load(fif, lpszPathName, flag);
// unless a bad file format, we are done !
return dib;
}
return NULL;
}
No you cannot. To compile your source, the linker needs the library.

Resources