LibCurl undefined references - c

Trying to make a translation program in C using Libcurl. Text editor is Atom and using gnu compiler.
When compiling as "gcc example.c" i get these errors:
Navid#LAPTOP-ASS7BGNB /c/users/navid/desktop/Lipcurl/libcurl-sample-master/curl
$ gcc projektzwei.c
C:\Users\Navid\AppData\Local\Temp\ccwZwaAr.o:projektzwei.c:(.text+0xa18): undefined reference to `_imp__curl_easy_init'
C:\Users\Navid\AppData\Local\Temp\ccwZwaAr.o:projektzwei.c:(.text+0xa4a): undefined reference to `_imp__curl_easy_setopt'
C:\Users\Navid\AppData\Local\Temp\ccwZwaAr.o:projektzwei.c:(.text+0xa83): undefined reference to `_imp__curl_easy_setopt'
C:\Users\Navid\AppData\Local\Temp\ccwZwaAr.o:projektzwei.c:(.text+0xa90): undefined reference to `_imp__curl_easy_perform'
C:\Users\Navid\AppData\Local\Temp\ccwZwaAr.o:projektzwei.c:(.text+0xaa6): undefined reference to `_imp__curl_easy_strerror'
C:\Users\Navid\AppData\Local\Temp\ccwZwaAr.o:projektzwei.c:(.text+0xacf): undefined reference to `_imp__curl_easy_cleanup'
collect2.exe: error: ld returned 1 exit status
And when compiling as "gcc projektzwei.c -lcurl" i get this error:
Navid#LAPTOP-ASS7BGNB /c/users/navid/desktop/Lipcurl/libcurl-sample-master/curl
$ gcc projektzwei.c -lcurl
c:/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/bin/ld.exe: cannot find -lcurl
collect2.exe: error: ld returned 1 exit status
This is my code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "stdafx.h"
#include "libcurl/include/curl/curl.h"
#ifdef _DEBUG
#pragma comment(lib, "libcurl/lib/libcurl_a_debug.lib")
#else
#pragma comment(lib, "libcurl/lib/libcurl_a.lib")
#endif
#define TEXT_MAX 2000
#define CANDIDAT_INPUT 2 /*Amount of valid inputs for candidat*/
#define PARTY_INPUT 14 /*Amount of valid inputs for parties*/
void prepare_files(char *Key);
void Introduction(int Sprog);
void Assemble_URL_To_Translate(int Sprog, FILE *fp);
char *create_URL(char Key[], char Source[], char Target[], char Message[]);
const char *chosen_language(int Target);
int valid_input_checker(const char **index, int array_lenght, char input[]);
void create_message(FILE *fp, char *Message);
void fil_print(FILE *fp);
void Partier(char input[], int Sprog, char chosen_party[]);
const char *chosen_party(char parti_input[]);
void Candidat_Exist(char parti_input[], int Sprog, char chosen_party[]);
char *delete_space(char text[]);
void match_and_insert(int(*str_pred)(char*), char str[], int str_in_len, const char *prefix, char str_out[], int str_out_len);
int space_detector(char* cp);
void translator(void);
int main(void)
{
int Sprog;
/*User is asked to choose language*/
printf("Choose language:\n"
"(1) Dansk\n(2) English\n(3) Turk\n(4) Polski\n(5) Alearabia"
"\n(6) Deutsch\n(7) Kurdi\n(8) Romanesc\n(9) Bosanski\n(10) Soomaali\n");
scanf("%d", &Sprog);
Introduction(Sprog); /*Initializes the program with the given language*/
return 0;
}
void prepare_files(char *Key)
{
FILE *fp;
fp = fopen("API.txt", "r");
if (fp == NULL)
{
printf("Filen kunne ikke �bnes.\n");
exit(EXIT_FAILURE);
}
while (!feof(fp))
{
fscanf(fp, "%s", Key);
}
}
void Assemble_URL_To_Translate(int Sprog, FILE *fp)
{
/*laver api key, target, message og url*/
char SOURCE[5] = "da";
char TARGET[5];
char MESSAGE[TEXT_MAX];
char KEY[100];
char URL[TEXT_MAX];
URL[0] = '\0';
prepare_files(KEY);
strcpy(TARGET, chosen_language(Sprog));
create_message(fp, MESSAGE);
fp = fopen("Translate_Input.txt", "w");
strcat(URL, create_URL(KEY, SOURCE, TARGET, MESSAGE));
fprintf(fp, "%s", URL);
fil_print(fp);
}
void Introduction(int Sprog)
{
/*Function to print introduction at the chosen language and ask the user what their next move is.*/
FILE *fp;
char parti_input[5]; /*Array for user input*/
const char *valid_inputs[PARTY_INPUT] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "b" }; /*All the valid input options in the scanf*/
char party[50]; /*Array to store the string containing what party has been chosen*/
/*This will be replaced when we got a translator function.*/
fp = fopen("Introduktion.txt", "r");
Assemble_URL_To_Translate(Sprog, fp);
translator();
do /*Asks the user to tell us what party they want to have a look at or optionally, go back.*/
{
printf("Press:\n"
"(1) Alternativet\n(2) Det Konversative Folkeparti\n(3) DF\n(4) Enhedslisten\n"
"(5) Fjordlisten\n(6) Kristendemokraterne\n(7) Liberal Alliance\n(8) Nationalpartiet\n"
"(9) Nye Borgerlige\n(10) Radikale Venstre\n(11) SF\n(12) Socialdemokraterne\n(13) Venstre\n"
"(b) for at gaa tilbage\n");
scanf("%s", &parti_input);
}
while (valid_input_checker(valid_inputs, PARTY_INPUT, parti_input) == 0);
if (strchr(parti_input, 'b') != NULL)
{
main();
}
else
{
strcpy(party, chosen_party(parti_input));
Partier(parti_input, Sprog, party);
}
}
char *create_URL(char Key[], char Source[], char Target[], char Message[])
{
char URL[TEXT_MAX] = "https://www.googleapis.com/language/translate/v2?key=&source=&target=&q=";
char *URLptr = URL;
sprintf(URL, "https://www.googleapis.com/language/translate/v2?key=%s&source=%s&target=%s&q=", Key, Source, Target);
Message = delete_space(Message);
strcat(URL, Message);
return URLptr;
}
const char *chosen_language(int Target)
{
/*Finds out what party has been chosen and returns it as a string.*/
const char *sprog[] = { "da", "en", "tr", "pl", "ar", "de", "ku", "ro", "bs", "so" };
return sprog[Target - 1]; /*-1 cause array index starts at 0, but the users lowest valid input is 1*/
}
const char *chosen_party(char parti_input[])
{
/*Finds out what party has been chosen and returns it as a string.*/
int input_tal = atoi(parti_input);
const char *partier[] = { "Alternativet", "Det_Konversative_Folkeparti", "DF", "Enhedslisten"
,"Fjordlisten", "Kristendemokraterne", "Liberal_Alliance", "Nationalpartiet"
,"Nye_Borgerlige", "Radikale_Venstre", "SF", "Socialdemokraterne", "Venstre" };
return partier[input_tal - 1]; /*-1 cause array index starts at 0, but the users lowest valid input is 1*/
}
int valid_input_checker(const char **index, int array_lenght, char input[])
{
/*Algoritme to find out if the entered input from the user is valid.*/
for (int i = 0; i < array_lenght; i++)
{
if (strcmp(index[i], input) == 0) /*If we find a match, we return 1*/
{
return 1;
}
else if (i == array_lenght && (strcmp(index[i], input) != 0)) /*If we have been through the entire index og valid input without a match, we return 0*/
{
return 0;
}
}
return 0;
}
void create_message(FILE *fp, char *Message)
{
int ch;
int i = 0;
while ((ch = fgetc(fp)) != EOF)
{
Message[i] = ch;
i++;
}
Message[i] = '\0';
fclose(fp); /*As soon as we are done with the file we close it. ALWAYS do this.*/
}
void fil_print(FILE *fp)
{
/*Simple algoritme to print a file.*/
int ch;
int i = 0;
char str[400]; /*Array where the file is getting stored*/
while ((ch = fgetc(fp)) != EOF)
{
str[i] = ch;
i++;
}
str[i] = '\0';
//printf("%s\n", str); /*Prints the file*/
fclose(fp); /*As soon as we are done with the file we close it. ALWAYS do this.*/
}
void Partier(char parti_input[], int Sprog, char chosen_party[])
{
/*Function to print the overview of what the chosen party stands for and gives the user the option to view the candidats or go back.*/
FILE *fp;
char kandidat_input[5]; /*This is the input we get from the user, which tells us whether they user wants to look at candidats for the party, og go back.*/
const char *valid_inputs[CANDIDAT_INPUT] = { "1", "b" }; /*Array of valid inputs for the scanf*/
char party_intro[50]; /*Array to store the path for the party overview file.*/
sprintf(party_intro, "Partier/%s/M�rkesager.txt", chosen_party); /*Stores the path*/
printf("party: %s\n", party_intro); /*Nice to have, not necessary. Tells you what path it is going to print from.*/
fp = fopen(party_intro, "r"); /*Opens the file at the given path*/
fil_print(fp); /*Prints the file*/
do/*User is asked to tell what their next move is*/
{
printf("tryk:\n"
"(1) Se partiets kandidater\n");
printf("(b) for at gaa tilbage\n");
scanf("%s", &kandidat_input);
}
while (valid_input_checker(valid_inputs, CANDIDAT_INPUT, kandidat_input) == 0); /*We have a function 'valid_input_checker' which returns either 1 or 0. If 1,
the users input was valid and the program will proceed. If 0, the input was incorrect
and the user is asked again to type something.*/
if (strchr(kandidat_input, 'b') != NULL) /*Checks if the input was 'b'*/
{
Introduction(Sprog);
}
else
Candidat_Exist(parti_input, Sprog, chosen_party);
}
void Candidat_Exist(char parti_input[], int Sprog, char chosen_party[])
{
/*Prints every single candidat for the given party.*/
FILE *fp;
char user_input[5];
char candidattxt[50]; /*Array to later store the string used to open the candidat text file in fopen.*/
char path[40]; /*Array to tell your computer where it is going to find the text file.*/
sprintf(path, "Partier/%s/Kandidat_\0", chosen_party); /*Takes the users chosen party and adds it to the path, to determine where we are going to find the text files.*/
int size = 2;
/*Algoritme to check if the next candidat exist and will print it if it does. If it exist, the 'size' is incremented by 1, so we keep cycling through the list of
candidats. If it doesn't, we break.*/
for (int i = 1; i < size; i++)
{
sprintf(candidattxt, "%s%d.txt", path, i); /*All candidates are saved as "Kandidat_X" where X is an integer starting at 1. We finish the path by specifying what
file want to check.*/
fp = fopen(candidattxt, "r"); /*Opens the candidats text file*/
if (fp != NULL) /*Checks if the file exist*/
{
/*printf("candi: %s\n", candidattxt); Command to show you what candidat is getting printet*/
fil_print(fp);
fclose(fp);
size++;
}
else if (fp == NULL)
{
break;
}
}
do/*User is asked to tell what their next move is*/
{
printf("tryk:\n(b) for at gaa tilbage\n");
scanf("%s", &user_input);
}
while (strcmp(user_input, "b") != 0); /*We have a function 'valid_input_checker' which returns either 1 or 0. If 1,
the users input was valid and the program will proceed. If 0, the input was incorrect
and the user is asked again to type something.*/
Partier(parti_input, Sprog, chosen_party);
}
char *delete_space(char text[])
{
char str_res[TEXT_MAX];
char *str_res_ptr = str_res;
int i, j, k;
/* Initialize str_res til zero */
for (i = 0; i < TEXT_MAX; ++i)
str_res[i] = '\0';
printf("len: %d\n", strlen(text));
match_and_insert(space_detector, text, 200, "%20", str_res, TEXT_MAX);
for (j = 0, k = 0; j < 200; j++)
{
str_res[j - k] = str_res[j];
if (str_res[j] == ' ')
k++;
}
str_res[j] = '\0';
return str_res_ptr;
}
void match_and_insert(int(*str_pred)(char*), char str[], int str_in_len, const char *prefix, char str_out[], int str_out_len)
/*Shoutout til Kurt N�rmark*/
{
int i = 0, o = 0;
while (i < str_in_len)
{
int match_result = str_pred(str + i);
if (match_result > 0)
{
strcpy(str_out + o, prefix);
o += strlen(prefix);
strncpy(str_out + o, str + i, match_result);
i += match_result; o += match_result;
}
else if (match_result == 0)
{
str_out[o++] = str[i++];
}
else
{
printf("Should not happen!\n");
exit(EXIT_FAILURE);
}
}
}
int space_detector(char* cp)
{
int result = isspace(cp[0]);
if (result)
return 1;
else
return 0;
}
void translator(void)
{
CURL *curl;
CURLcode res;
int ch, i = 0;
char Message[2000];
FILE *fp2;
fp2 = fopen("Translate_Input.txt", "r");
while ((ch = fgetc(fp2)) != EOF)
{
Message[i] = ch;
i++;
}
Message[i] = '\0';
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, Message);
FILE *fp = fopen("target.txt", "w");
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
/* Check for errors */
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
fclose(fp);
}
}
I've searched around a bit and it seems most people get it fixed by adding the
-lcurl at the end of the gcc command but it just doesn't work for me. Any ideas?

Based on this line:
#include "libcurl/include/curl/curl.h"
it looks like you've not installed curl on your machine, you've just downloaded the source and compiled it. That's not the wrong way to do it, but it does make your life more difficult.
Firstly you need to correct the above line as it should be
#include <curl/curl.h>
You then need to tell the compiler where the include files are by adding "-Ilibcurl/include". By doing this, it means that if/when you install libcurl properly, you won't need to make any changes to your code - you can just remove the -I option.
Secondly, you also need to tell the compiler (technically the linker) where the libraries are with the -L option. It looks like that should be "-Llibcurl/lib/"
So to summarise, having fixed the include line as per above, your command to compile your code should look like:
gcc -Ilibcurl/include -Llibcurl/lib projektzwei.c -lcurl

Related

My delete function deletes the wrong record of struct

I have this function which is supposed to delete the recipe requested by the user. I've always deleted records in this way, but I don't know why this time it doesn't work in the right way. Sometimes it states that there's no match but it deletes the recipe or it deletes all the recipes inside the file and I don't get it why since I basically created a temp file in which writing all the records except for the one the user wants to delete and I used a function that worked for another record so I really don't get it. Is that because the length of ingredients and procedure is not the same for all the recipes?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int stringCmpi (char *s1,char *s2);
struct _recipe
{
char name[40];
int count_i;
char ingredients[20][40];
char diff[12];
int timr;
int calories;
int count_p;
char procedure[30][500];
} recipe;
int main()
{
FILE* fbr;
FILE* temp;
char ricetta_name[] = "ricette.bin";
char temp_name[] = "temp.bin";
fbr = fopen("ricette.bin", "rb");
temp = fopen("temp.bin", "wb");
int found = 0;
char name_t[40];
int i;
char space = '\n';
if(fbr == NULL)
{
printf("Couldn't open the file.\n");
exit(1);
}
if(fbr == NULL)
{
printf("Couldn't open the file.\n");
exit(1);
}
printf("Write the name of the recipe you want to delete:\n");
fgets(name_t,sizeof(name_t),stdin);
space = getchar();
while(fread(&recipe,sizeof(recipe),1,fbr) && found == 0)
{
if(stringCmpi(name_t,recipe.name) == 0)
{
found = 1;
printf("Match found. Recipe deleted.\n");
}
else
{
fwrite(&recipe,sizeof(recipe),1,temp);
}
if(!found)
{
printf("No match.\n");
}
}
fclose(fbr);
fclose(temp);
remove(ricetta_name);
rename(temp_name,ricetta_name);
system("PAUSE");
return 0;
}
int stringCmpi (char *s1,char *s2)
{
int i=0;
for(i=0; s1[i]!='\0'; i++)
{
if( toupper(s1[i])!=toupper(s2[i]) )
return 1;
}
return 0;
}
The problem is here:
while(fread(&recipe,sizeof(recipe),1,fbr) && found == 0)
Once you find a recipe, you exit the loop, so the remaining elements are not copied to the new file. I recommend you delete the && found == 0 clause.
Furthermore:
if(!found)
{
printf("No match.\n");
}
This is actually inside the while loop, so it will report No match multiple times. Please move it outside the loop.
Proper indentation would help you see the actual structure of the program. This is how the posted program looks with consistent indentation:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int stringCmpi (char *s1,char *s2);
struct _recipe
{
char name[40];
int count_i;
char ingredients[20][40];
char diff[12];
int timr;
int calories;
int count_p;
char procedure[30][500];
} recipe;
int main()
{
FILE* fbr;
FILE* temp;
char ricetta_name[] = "ricette.bin";
char temp_name[] = "temp.bin";
fbr = fopen("ricette.bin", "rb");
temp = fopen("temp.bin", "wb");
int found = 0;
char name_t[40];
int i;
char space = '\n';
if(fbr == NULL)
{
printf("Couldn't open the file.\n");
exit(1);
}
if(fbr == NULL)
{
printf("Couldn't open the file.\n");
exit(1);
}
printf("Write the name of the recipe you want to delete:\n");
fgets(name_t,sizeof(name_t),stdin);
space = getchar();
while(fread(&recipe,sizeof(recipe),1,fbr) && found == 0)
{
if(stringCmpi(name_t,recipe.name) == 0)
{
found = 1;
printf("Match found. Recipe deleted.\n");
}
else
{
fwrite(&recipe,sizeof(recipe),1,temp);
}
if(!found)
{
printf("No match.\n");
}
}
fclose(fbr);
fclose(temp);
remove(ricetta_name);
rename(temp_name,ricetta_name);
system("PAUSE");
return 0;
}
int stringCmpi (char *s1,char *s2)
{
int i=0;
for(i=0; s1[i]!='\0'; i++)
{
if( toupper(s1[i])!=toupper(s2[i]) )
return 1;
}
return 0;
}
The program is checking that fbr is not NULL twice. Probably the second check should be for temp.
The programs stops reading and copying when the recipe to be deleted is found; this means that the following records are not copied over.
The program complains that the recipe was not found for each recipe until the desired one is found.
Suggestions:
Modify the while loop condition eliminating the && ! found, so that all records are copied except those matching the given name.
Move the check for if (! found) outside the loop.
Bonus:
The function stringCmpi() stops comparing at the end of string s1; which means that "abc" and "abcdef" will compare equal. You probably want to change return 0 to return s1 [i] != s2 [i].
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct _recipe
{
char name[40];
int count_i;
char ingredients[20][40];
char diff[12];
int timr;
int calories;
int count_p;
char procedure[30][500];
} recipe;
int main(int argc, char *argv[])
{
FILE* fbr;
FILE* temp;
char *ricetta_name = "recipe.bin";
char *temp_name = "temp.bin";
int found = 0;
char name_t[40];
// Use command line arguments if possible
if (argc == 2)
{
ricetta_name = argv[1];
}
if((fbr = fopen(ricetta_name, "rb")) == NULL)
{
printf("Couldn't open the file %s.\n", ricetta_name);
exit(1);
}
if((temp = fopen(temp_name, "wb")) == NULL)
{
printf("Couldn't open the file %s.\n", temp_name);
exit(1);
}
printf("Write the name of the recipe you want to delete:\n");
fgets(name_t, sizeof(name_t), stdin);
// Remove '\n'
if (name_t[strlen(name_t) - 1] == '\n')
name_t[strlen(name_t) - 1] = 0;
while(fread(&recipe,sizeof(recipe), 1, fbr))
{
// Use standard strcasecmp()
if(strcasecmp(name_t, recipe.name) == 0)
{
found = 1;
printf("Match found. Recipe deleted.\n");
}
else
{
fwrite(&recipe, sizeof(recipe), 1, temp);
}
}
if (!found)
{
printf("No match.\n");
}
fclose(fbr);
fclose(temp);
remove(ricetta_name);
rename(temp_name,ricetta_name);
return 0;
}
Please format your code: add space(' ') after comma(','). And use standard function if possible.

adding char into an array and returning

Im new to c and am trying to understand pointers.
here I am opening a file and reading the lines given. Im trying to append these lines into an array and return it from the function. I dont seem to be appending or accessing the array correctly. output[count] = status; gives an error with mismatched char and char *.
Im essentially trying to get an array with a list of words given by a file where each element in the array is a word.
char *fileRead(char *command, char output[255]) {
int count = 0;
char input[255];
char *status;
FILE *file = fopen(command, "r");
if (file == NULL) {
printf("Cannot open file\n");
} else {
do {
status = fgets(input, sizeof(input), file);
if (status != NULL) {
printf("%s", status);
strtok(status, "\n");
// add values into output array
output[count] = status;
++count;
}
} while (status);
}
fclose(file);
return output;
}
I access fileRead via:
...
char commandArray[255];
char output[255];
int y = 0;
char *filename = "scriptin.txt";
strcpy(commandArray, fileRead(filename, output));
// read from array and pass into flag function
while (commandArray[y] != NULL) {
n = flagsfunction(flags, commandArray[y], sizeof(buf), flags.position, &desc, &parentrd, right, left, lconn);
y++;
...
Example of Read from file Line by line then storing nonblank lines into an array (array of pointer to char (as char*))
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//for it does not exist because strdup is not a standard function.
char *strdup(const char *str){
char *ret = malloc(strlen(str)+1);
if(ret)
strcpy(ret, str);
return ret;
}
//Read rows up to 255 rows
int fileRead(const char *filename, char *output[255]) {
FILE *file = fopen(filename, "r");
if (file == NULL) {
perror("Cannot open file:");
return 0;
}
int count = 0;
char input[255];
while(count < 255 && fgets(input, sizeof(input), file)) {
char *line = strtok(input, "\n");
if(line)//When it is not a blank line
output[count++] = strdup(line);//Store replica
}
fclose(file);
return count;
}
int main(void){
char *output[255];//(`char *` x 255)
int number_of_read_line = fileRead("data.txt", output);
for(int i = 0; i < number_of_read_line; ++i){
printf("%s\n", output[i]);
free(output[i]);//Discard after being used
}
return 0;
}

Read from a text file and use each line to compare if they are anagrams

I must modify my program to accept input from
a file called anagrams.txt.This file should have two strings per line, separated by the # character. My program should read
each pair of strings and report back if each pair of strings is an anagram. For example consider the following content of anagrams.txt:
hello#elloh
man#nam
Astro#Oastrrasd
Your program should print out the following:
hello#elloh - Anagrams!
man#nam - Anagrams!
Astro#Oastrrasd- Not anagrams!
I should compile in g++
Here is the code to read from text:
int main()
{
char input[30];
if(access( "anagrams.txt", F_OK ) != -1) {
FILE *ptr_file;
char buf[1000];
ptr_file =fopen("anagrams.txt","r"); if (!ptr_file)
return 1;
while (fgets(buf,1000, ptr_file)!=NULL)
printf("%s",buf);
fclose(ptr_file);
printf("\n");
}
else{ //if file does not exist
printf("\nFile not found!\n");
}
return 0;
}
Code to find if the text are anagrams:
#include <stdio.h>
int find_anagram(char [], char []);
int main()
{
char array1[100], array2[100];
int flag;
printf("Enter the string\n");
gets(array1);
printf("Enter another string\n");
gets(array2);
flag = find_anagram(array1, array2);
if (flag == 1)
printf(" %s and %s are anagrams.\n", array1, array2);
else
printf("%s and %s are not anagrams.\n", array1, array2);
return 0;
}
int find_anagram(char array1[], char array2[])
{
int num1[26] = {0}, num2[26] = {0}, i = 0;
while (array1[i] != '\0')
{
num1[array1[i] - 'a']++;
i++;
}
i = 0;
while (array2[i] != '\0')
{
num2[array2[i] -'a']++;
i++;
}
for (i = 0; i < 26; i++)
{
if (num1[i] != num2[i])
return 0;
}
return 1;
}
You can try something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAXLINE 1000
#define MAXLETTER 256
int is_anagram(char *word1, char *word2);
void check_lines(FILE *filename);
int cmpfunc(const void *a, const void *b);
void convert_to_lowercase(char *word);
int
main(int argc, char const *argv[]) {
FILE *filename;
if ((filename = fopen("anagram.txt", "r")) == NULL) {
fprintf(stderr, "Error opening file\n");
exit(EXIT_FAILURE);
}
check_lines(filename);
fclose(filename);
return 0;
}
void
check_lines(FILE *filename) {
char line[MAXLINE];
char *word1, *word2, *copy1, *copy2;
while (fgets(line, MAXLINE, filename) != NULL) {
word1 = strtok(line, "#");
word2 = strtok(NULL, "\n");
copy1 = strdup(word1);
copy2 = strdup(word2);
convert_to_lowercase(copy1);
convert_to_lowercase(copy2);
if (is_anagram(copy1, copy2)) {
printf("%s#%s - Anagrams!\n", word1, word2);
} else {
printf("%s#%s - Not Anagrams!\n", word1, word2);
}
}
}
void
convert_to_lowercase(char *word) {
int i;
for (i = 0; word[i] != '\0'; i++) {
word[i] = tolower(word[i]);
}
}
int
is_anagram(char *word1, char *word2) {
qsort(word1, strlen(word1), sizeof(*word1), cmpfunc);
qsort(word2, strlen(word2), sizeof(*word2), cmpfunc);
if (strcmp(word1, word2) == 0) {
return 1;
}
return 0;
}
int
cmpfunc(const void *a, const void *b) {
if ((*(char*)a) < (*(char*)b)) {
return -1;
}
if ((*(char*)a) > (*(char*)b)) {
return +1;
}
return 0;
}
Since this looks like a University question, I won't provide a full solution, only a hint.
All you have to do is replace the stdin input part of the anagram-finding file with the code you wrote to read from a file: it's as simple as changing
printf("Enter the string\n");
gets(array1);
printf("Enter another string\n");
gets(array2);
to
// before program:
#define SIZE 1000
// inside main
if (access("anagrams.txt", F_OK) == -1){
printf("\nFile not found!\n");
return 1; // Abort the program early if we can't find the file
}
FILE *ptr_file;
char buf[1000];
ptr_file = fopen("anagrams.txt","r");
if (!ptr_file)
return 1;
char array1[SIZE], array2[SIZE];
while (fgets(buf, 1000, ptr_file)!=NULL){
// do all your anagram stuff here!
// there is currently one line of the input file stored in buf
// Hint: You need to split buf into array_1 and array_2 using '#' to separate it.
}
fclose(ptr_file);
printf("\n");
Additional comments:
Don't ever ever ever use gets. gets doesn't check that the string it writes to can hold the data, which will cause your program to crash if it gets input bigger than the array size. Use fgets(buf, BUF_SIZE, stdin) instead.
Beautiful code is good code. People are more likely to help if they can read your code easily. (fix your brackets)
Just for interest, a more efficient algorithm for checking anagrams is to use qsort to sort both arrays, then a simple string matcher to compare them. This will have cost O(mnlog(m+n)), as opposed to O(m^2 n^2), awith the current algorithm
You need to split every line you read by fgets (as you did) in to two strings, and pass them to your find_anagram function. You can do that using strtok:
int main()
{
int flag;
char buf[1000];
FILE *ptr_file;
//Check file existence
//Open the file for reading
while (fgets (buf, 1000, ptr_file) != NULL)
{
char *array1 = strtok(buf, "#");
char *array2 = strtok(NULL, "\n");
flag = find_anagram (array1, array2);
//Check flag value to print your message
}
return 0;
}
//put your find_anagram function
Don't forget to #include <string.h> to use strtok().

merging and sorting a text file in C

I am supoosed write a function that reads two text files line by line, compare them, delete the duplicates and but them into a third file in alphabetical order...I have been working on this for over a month and I am still stuck I have tried several ways to do this and come up with nothing...I was in formed that i have to use strcmp to do this and I cant use any other predefined sorting function...I have also looked around on this site and cannot find much that helps with this...any help would be greatly appreciated..Here is what I have so far:
#include<stdio.h>
#include<string.h>
main (void)
{
char str [200];
char str2 [200];
char new [100];
char temp [100];
int row = 10;
FILE *fa = fopen ("book1.dat", "r");
FILE *fb = fopen ("book2.dat", "r");
FILE *fc = fopen ("fixed.txt", "w");
int i;
int j;
int k;
while (fgets (str, 200, fa) !=NULL && fgets (str2, 200, fb) !=NULL)
{
puts(str);
puts(str2);
if (strcmp( str, str2) ==0 )
{
strcpy (str , new);
} else {
strcpy (new, str);
strcpy (new, str2);
}
}
for ( i = 0; i < row; i++)
{
for (j = i+1; j< row; j++)
{
if(strcmp(new[i], new [j]) > 0)
{
strcpy (temp, new);
strcpy(new, new);
strcpy(new, temp);
}
}
}
for (i = 0; i < length; i ++)
{
fputs(new, fc);
}
}
Your use of strcpy() is peculiar. Recall its signature:
char *strcpy(char *dest, const char *src)
Here's a usage that doesn't make immediate sense to me:
strcpy (new, str); // new now has str
strcpy (new, str2); // new now has str2
You've effectively overwritten something there. I would start from there, and see what else may not be working as you intend. Furthermore, if you can use gcc, look into using gdb as well to debug your code. (You would need to compile with the -g flag.)
First off, can you assume the duplicates from book1 and book2 line up nicely?
Think about how you would detect if the first entry in book1 is identical to the last entry in book2.
Secondly, you have to sort your output alphabetically. Sorting algorithms is kind of one of those common things that students are forced to do all the time. It builds character. For bonus kudos, implement quick sort.
sample a way.
error handling is omitted.
since we are using the sort function of the library sqort, implement your own.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINE_MAX_SIZE 256
typedef struct filePos {
FILE *fp;
long pos;
} FilePos;
typedef struct myfile {
int lines;
int capacity;
FILE *fp;
FilePos *filePoss;
} MyFile;
MyFile *myfopen(const char *filepath){
char buff[LINE_MAX_SIZE];
MyFile *mfp;
mfp = (MyFile*)malloc(sizeof(MyFile));
mfp->lines = 0;
mfp->capacity=16;
mfp->filePoss=NULL;
mfp->filePoss=(FilePos*)realloc(mfp->filePoss, sizeof(FilePos)*(mfp->capacity *= 2));
mfp->fp = fopen(filepath, "r");
do{
mfp->filePoss[mfp->lines].fp = mfp->fp;
mfp->filePoss[mfp->lines].pos = ftell(mfp->fp);
if(++mfp->lines == mfp->capacity){
mfp->filePoss=(FilePos*)realloc(mfp->filePoss, sizeof(FilePos)*(mfp->capacity *= 2));
}
}while(NULL!=fgets(buff, LINE_MAX_SIZE, mfp->fp));
--mfp->lines;
return mfp;
}
void myfclose(MyFile *mfp){
free(mfp->filePoss);
fclose(mfp->fp);
free(mfp);
}
char *myfgets(FilePos *p, char *buff){
fseek(p->fp, p->pos, SEEK_SET);
return fgets(buff, LINE_MAX_SIZE, p->fp);
}
int myfcomp(const void *a, const void *b){
char buff_a[LINE_MAX_SIZE];
char buff_b[LINE_MAX_SIZE];
FilePos *fpa,*fpb;
fpa=(FilePos*)a;
fpb=(FilePos*)b;
myfgets(fpa, buff_a);
myfgets(fpb, buff_b);
return strcmp(buff_a, buff_b);
}
void myfsort(MyFile *mfp){
qsort(mfp->filePoss, mfp->lines, sizeof(FilePos), myfcomp);
}
void myfprint(MyFile *mfp){
char buff[LINE_MAX_SIZE];
int i;
for(i=0;i<mfp->lines ;++i)
printf("%s", myfgets(mfp->filePoss + i, buff));
}
void merge(const char *inpfile1, const char *inpfile2, const char *outfile){
FILE *fo;
MyFile *fi1, *fi2;
char buff_f1[LINE_MAX_SIZE];
char buff_f2[LINE_MAX_SIZE];
char buff_fo[LINE_MAX_SIZE];
char *outbuff=NULL;
int fi1_line, fi2_line;
int eof1, eof2;
fo=fopen(outfile, "w");
fi1=myfopen(inpfile1);
fi2=myfopen(inpfile2);
myfsort(fi1);
myfsort(fi2);
fi1_line=fi2_line=0;
eof1=eof2=0;
*buff_fo='\0';
while(1){
if(!eof1 && outbuff != buff_f2){
myfgets(&(fi1->filePoss[fi1_line]), buff_f1);
}
if(!eof2 && outbuff != buff_f1){
myfgets(&(fi2->filePoss[fi2_line]), buff_f2);
}
if(!eof1 && !eof2){
if(strcmp(buff_f1, buff_f2) <= 0){
outbuff=buff_f1;
++fi1_line;
} else {
outbuff=buff_f2;
++fi2_line;
}
} else if(!eof1 && eof2){
outbuff=buff_f1;
++fi1_line;
} else if(eof1 && !eof2){
outbuff=buff_f2;
++fi2_line;
} else {
break;
}
if(strcmp(outbuff, buff_fo) != 0){//duplicate check
strcpy(buff_fo, outbuff);
fputs(buff_fo, fo);
}
if(fi1->lines == fi1_line)
eof1 = !0;
if(fi2->lines == fi2_line)
eof2 = !0;
}
myfclose(fi2);
myfclose(fi1);
fclose(fo);
}
int main(){
merge("book1.txt", "book2.txt", "fixed.txt");
return 0;
}

Reading information from text file in C

I'm new to C; please try to help me as much as you can.
I'm getting as arguments to main() pointers to files,
so in a for loop I fopen() them and want to send them to a function that will
read the text info inside them and put it in char variables.
Here is an example file:
#station name
Station Name : A1
#octan of fuel 6.54 full service price 6.40 self service
Octan95,6.54,6.40
Octan98,8.30,8.15
#carNum,Octan,numOfLiters,Kind of service
22-334-55,95,31.3,FullService
22-334-55,95,31.3,SelfService
11-444-77,95,12,FullService
11-444-77,95,44.1,FullService
11-444-77,95,11.22,SelfService
The text has fields separated with commas, and I need the information between those commas to be added to vars.
What will be the best way or function to read these text files?
Also should I expect '\n' after each line or will it stream as one big char[] without the new line character?
read file line by line
use strtok function to get everything in between commas
read file line by line and use sscanf with return-value to get everything in between commas
Some 200 lines of code later...and using a slightly modified version of your data file (note that the second header line in the original is missing all the commas):
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
** Example data:
**
** #station name
** Station Name : A1
** #octan of fuel,full service price,self service price
** Octan95,6.54,6.40
** Octan98,8.30,8.15
** #carNum,Octan,numOfLiters,Kind of service
** 22-334-55,95,31.3,FullService
** 22-334-55,95,31.3,SelfService
** 11-444-77,95,12,FullService
** 11-444-77,95,44.1,FullService
** 11-444-77,95,11.22,SelfService
**
** - Header lines are followed by one or more data lines
** - Number of fields in header matches number of fields in each data line
** - Commas separate fields and do not appear within fields (not full CSV)
*/
/* A Line structure holds the fields for one line */
typedef struct Line
{
size_t num_fields;
char **fields;
} Line;
/* A Section structure holds the header line and the set of data lines */
typedef struct Section
{
size_t num_rows;
size_t num_cols;
Line header;
Line *lines; /* Array of lines - num_rows entries in array */
} Section;
/* An Info structure holds all the sections for a single file */
typedef struct Info
{
size_t num_sections;
Section *sections;
} Info;
static void err_exit(const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
exit(1);
}
static void *xrealloc(void *old_data, size_t nbytes)
{
void *new_data = realloc(old_data, nbytes);
if (new_data == 0)
err_exit("Out of memory!\n");
return new_data;
}
static void *xmalloc(size_t nbytes)
{
void *new_data = malloc(nbytes);
if (new_data == 0)
err_exit("Out of memory!\n");
return new_data;
}
/* Duplicate a string of given length (excluding NUL) */
static char *xstrndup(const char *str, size_t len)
{
char *new_data = xmalloc(len+1);
memmove(new_data, str, len);
new_data[len] = '\0';
return new_data;
}
static void dump_line(FILE *fp, const Line * const line)
{
size_t i;
const char *pad = "";
for (i = 0; i < line->num_fields; i++)
{
fprintf(fp, "%s%*s", pad, 1, line->fields[i]);
pad = " ";
}
fputc('\n', fp);
}
static void dump_section(FILE *fp, const char *tag, const Section * const section)
{
if (tag != 0)
fprintf(fp, "Dump Section: %s\n", tag);
fprintf(fp, "Number of columns: %zd\n", section->num_cols);
fprintf(fp, "Number of lines: %zd\n", section->num_rows);
dump_line(fp, &section->header);
for (size_t i = 0; i < section->num_rows; i++)
dump_line(fp, &section->lines[i]);
}
static void dump_info(FILE *fp, const char *tag, const Info * const info)
{
size_t i;
fprintf(fp, "Dump Information: %s\n", tag);
fprintf(fp, "Number of sections: %zd\n", info->num_sections);
for (i = 0; i < info->num_sections; i++)
{
char title[20];
snprintf(title, sizeof(title), "%d", i+1);
dump_section(fp, title, &info->sections[i]);
}
fprintf(fp, "End of Information Dump\n");
}
static int num_fields(const char *buffer)
{
size_t posn = 0;
size_t next;
int count = 0;
while ((next = strcspn(buffer + posn, ",\n")) > 0)
{
count++;
if (buffer[posn+next] == '\n')
break;
posn += next + 1;
}
return count;
}
static void set_line(Line *line, int nfields, const char *buffer)
{
size_t posn = 0;
line->num_fields = nfields;
line->fields = xmalloc(nfields * sizeof(*line->fields));
for (int i = 0; i < nfields; i++)
{
size_t next = strcspn(buffer+posn, ",\n");
line->fields[i] = xstrndup(buffer+posn, next);
if (buffer[posn+next] == '\n')
{
if (i != nfields - 1)
err_exit("Internal error: field count mismatch\n");
break;
}
posn += next + 1;
}
}
static int add_section(Info *info, char *buffer)
{
int nfields = num_fields(buffer);
int nsections = info->num_sections + 1;
info->sections = xrealloc(info->sections, nsections * sizeof(*info->sections));
info->num_sections = nsections;
Section *new_section = &info->sections[nsections-1];
new_section->num_cols = nfields;
new_section->num_rows = 0;
set_line(&new_section->header, nfields, buffer);
new_section->lines = 0;
return nfields;
}
/* Beware - very compact code! */
static void add_line_to_section(Section *section, const char *buffer, int nfields)
{
section->lines = xrealloc(section->lines, (section->num_rows + 1) * sizeof(*section->lines));
set_line(&section->lines[section->num_rows++], nfields, buffer);
}
static int peek(FILE *fp)
{
int c;
if ((c = getc(fp)) != EOF)
ungetc(c, fp);
return c;
}
static void read_info(FILE *fp, Info *info)
{
char buffer[1024];
while (fgets(buffer, sizeof(buffer), fp) != 0)
{
if (*buffer != '#')
err_exit("Format error: expected line beginning '#' (got '%.*s')\n",
10, buffer);
int nfields = add_section(info, buffer+1);
int c;
Section *cursect = &info->sections[info->num_sections-1];
while ((c = peek(fp)) != EOF && c != '#')
{
if (fgets(buffer, sizeof(buffer), fp) != 0)
{
int lfields = num_fields(buffer);
if (lfields != nfields)
err_exit("Mismatch in number of fields (got %d, wanted %) at '%*s'\n",
lfields, nfields, 20, buffer);
add_line_to_section(cursect, buffer, nfields);
}
}
}
}
int main(int argc, char **argv)
{
int i;
Info info = { 0, 0 };
for (i = 1; i < argc; i++)
{
FILE *fp;
if ((fp = fopen(argv[i], "r")) != 0)
{
read_info(fp, &info);
dump_info(stdout, "After loop", &info);
}
else
fprintf(stderr, "Failed to open file %s (%s)\n", argv[i], strerror(errno));
}
dump_info(stdout, "End of main loop", &info);
return 0;
}
The code is not optimal in most senses - it allocates far too many small bits of memory. I also got lazy and didn't write the code to free the memory. I don't think it would be a good idea to hand this in as your code, though.

Resources