I want my program to read a file containing words separated by blank spaces and then prints words one by one. This is what I did:
char *phrase = (char *)malloc(LONGMAX * sizeof(char));
char *mot = (char *)malloc(TAILLE * sizeof(char));
FILE *fp = NULL;
fp = fopen("mots.txt", "r");
if (fp == NULL) {
printf("err ");
} else {
fgets(phrase, LONGMAX, fp);
while (phrase[i] != '\0') {
if (phrase[i] != " ") {
mot[m] = phrase[i];
i++;
m++;
} else {
printf("%s\n", phrase[i]);
mot = "";
}
}
}
but it isn't printing anything! Am I doing something wrong? Thanks!
The i in the following:
while (phrase[i]!='\0'){
Should be initialized to 0 before being used, then incremented as you iterate through the string.
You have not shown where/how it is created.
Also in this line,
if(phrase[i]!=" "){
the code is comparing a char: (phrase[i]) with a string: ( " " )
// char string
if(phrase[i] != " " ){
change it to:
// char char
if(phrase[i] != ' '){
//or better yet, include all whitespace:
if(isspace(phrase[i]) {
There is no error checking in the following, but it is basically your code with modifications. Read comments for explanation on edits to fgets() usage, casting return of malloc(), how and when to terminate the output buffer mot, etc.:
This performs the following: read a file containing words separated by blank spaces and then prints words one by one.
int main(void)
{
int i = 0;
int m = 0;
char* phrase=malloc(LONGMAX);//sizeof(char) always == 0
if(phrase)//test to make sure memory created
{
char* mot=malloc(TAILLE);//no need to cast the return of malloc in C
if(mot)//test to make sure memory created
{
FILE* fp=NULL;
fp=fopen("_in.txt","r");
if(fp)//test to make sure fopen worked
{//shortcut of what you had :) (left off the print err)
i = 0;
m = 0;
while (fgets(phrase,LONGMAX,fp))//fgets return NULL when no more to read.
{
while(phrase[i] != NULL)//test for end of last line read
{
// if(phrase[i] == ' ')//see a space, terminate word and write to stdout
if(isspace(phrase[i])//see ANY white space, terminate and write to stdout
{
mot[m]=0;//null terminate
if(strlen(mot) > 0) printf("%s\n",mot);
i++;//move to next char in phrase.
m=0;//reset to capture next word
}
else
{
mot[m] = phrase[i];//copy next char into mot
m++;//increment both buffers
i++;// "
}
}
mot[m]=0;//null terminate after while loop
}
//per comment about last word. Print it out here.
mot[m]=0;
printf("%s\n",mot);
fclose(fp);
}
free(mot);
}
free(phrase);
}
return 0;
}
phrase[i]!=" "
You compare character (phrase[i]) and string (" "). If you want to compare phrase[i] with space character, use ' ' instead.
If you want to compare string, use strcmp.
printf("%s\n",phrase[i]);
Here, you use %s for printing the string, but phrase[i] is a character.
Do not use mot=""; to copy string in c. You should use strcpy:
strcpy(mot, " ");
If you want to print word by word from one line of string. You can use strtok to split string by space character.
fgets(phrase,LONGMAX,fp);
char * token = strtok(phrase, " ");
while(token != NULL) {
printf("%s \n", token);
token = strtok(NULL, " ");
}
OT, your program will get only one line in the file because you call only one time fgets. If your file content of many line, you should use a loop for fgets function.
while(fgets(phrase,LONGMAX,fp)) {
// do something with pharse string.
// strtok for example.
char * token = strtok(phrase, " ");
while(token != NULL) {
printf("%s \n", token);
token = strtok(NULL, " ");
}
}
Your program has multiple problems:
the test for end of file is incorrect: you should just compare the return value of fgets() with NULL.
the test for spaces is incorrect: phrase[i] != " " is a type mismatch as you are comparing a character with a pointer. You should use isspace() from <ctype.h>
Here is a much simpler alternative that reads one byte at a time, without a line buffer nor a word buffer:
#include <ctype.h>
#include <stdio.h>
int main() {
int inword = 0;
int c;
while ((c = getchar()) != EOF) {
if (isspace(c)) {
if (inword) {
putchar('\n');
inword = 0;
}
} else {
putchar(c);
inword = 1;
}
}
if (inword) {
putchar('\n');
}
return 0;
}
Related
Mainly a Java/Python coder here. I am coding a tokenizer for an assignment. (I explicitly cannot use strtok().) The code below is meant to separate the file text into lexemes (aka words and notable characters).
char inText[256];
fgets(inText, 256, inf);
char lexemes[256][256];
int x = 0;
char string[256] = "\0";
for(int i=0; inText[i] != '\0'; i++)
{
char delims[] = " (){}";
char token = inText[i];
if(strstr(delims, &inText[i]) != NULL)
{
if(inText[i] == ' ') // <-- Problem Code
{
if(strlen(string) > 0)
{
strcpy(lexemes[x], string);
x++;
strcpy(string, "\0");
(*numLex)++;
}
}
else if(inText[i] == '(')
{
if(strlen(string) > 0)
{
strcpy(lexemes[x], string);
x++;
strcpy(string, "\0");
(*numLex)++;
}
strcpy(lexemes[x], &token);
x++;
(*numLex)++;
}
else
{
strcpy(lexemes[x], &token);
x++;
(*numLex)++;
}
}
else
{
strcat(string, (char[2]){token});
}
}
For some odd reason, my code cannot recognize the space character as ' ', as 32, or by using isspace(). There are no error messages, and I have confirmed that the code is reaching the space in the text.
This is driving me insane. Does anyone have any idea what is happening here?
You are using the function strstr incorrectly.
if(strstr(delims, &inText[i]) != NULL)
the function searches exactly the string pointed to by the pointer expression &inText[i] in the string " (){}".
Instead you need to use another function that is strcspn.
Something like
i = strcspn( &inText[i], delims );
or you can introduce another variable like for example
size_t n = strcspn( &inText[i], delims );
depending on the logic of the processing you are going to follow.
Or more probably you need to use the function strchr like
if(strchr( delims, inText[i]) != NULL)
I have a file that contains words and their synonyms each on a separate line.
I am writing this code that should read the file line by line then display it starting from the second word which is the synonym.
I used the variable count in the first loop in order to be able to count the number of synonyms of each word because the number of synonyms differs from one to another. Moreover I used the condition synonyms[i]==',' because each synonym is separate by a comma.
The purpose of me writing such code is to put them in a binary search tree in order to have a full dictionary.
The code doesn't contain any error yet it is not working.
I have tried to each the loop but that didn't work too.
Sample input from the file:
abruptly - dead, short, suddenly
acquittance - release
adder - common, vipera
Sample expected output:
dead short suddenly
acquittance realse
common vipera
Here is the code:
void LoadFile(FILE *fp){
int count;
int i;
char synonyms[50];
char word[50];
while(fgets(synonyms,50,fp)!=NULL){
for (i=0;i<strlen(synonyms);i++)
if (synonyms[i]==',' || synonyms[i]=='\n')
count++;
}
while(fscanf(fp,"%s",word)==1){
for(i=1;i<strlen(synonyms);i++){
( fscanf(fp,"%s",synonyms)==1);
printf("%s",synonyms);
}
}
}
int main(){
char fn[]="C:/Users/CLICK ONCE/Desktop/Semester 4/i2206/Project/Synonyms.txt";
FILE *fp;
fp=fopen(fn,"rt");
if (fp==NULL){
printf("Cannot open this file");
}
else{
LoadFile(fp);
}
return 0;
}
Here is my solution. I have split the work into functions for readability. The actual parsing is done in parsefunction. That function thakes into account hyphenated compound words such as seventy-two. The word and his synonyms must be separated by an hyphen preceded by at least one space.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// Trim leading and trailing space characters.
// Warning: string is modified
char* trim(char* s) {
char* p = s;
int l = strlen(p);
while (isspace(p[l - 1])) p[--l] = 0;
while (*p && isspace(*p)) ++p, --l;
memmove(s, p, l + 1);
return s;
}
// Warning: string is modified
int parse(char* line)
{
char* token;
char* p;
char* word;
if (line == NULL) {
printf("Missing input line\n");
return 0;
}
// first find the word delimiter: an hyphen preceded by a space
p = line;
while (1) {
p = strchr(p, '-');
if (p == NULL) {
printf("Missing hypen\n");
return 0;
}
if ((p > line) && (p[-1] == ' ')) {
// We found an hyphen preceded by a space
*p = 0; // Replace by nul character (end of string)
break;
}
p++; // Skip hyphen inside hypheneted word
}
word = trim(line);
printf("%s ", word);
// Next find synonyms delimited by a coma
char delim[] = ", ";
token = strtok(p + 1, delim);
while (token != NULL) {
printf("%s ", token);
token = strtok(NULL, delim);
}
printf("\n");
return 1;
}
int LoadFile(FILE* fp)
{
if (fp == NULL) {
printf("File not open\n");
return 0;
}
int ret = 1;
char str[1024]; // Longest allowed line
while (fgets(str, sizeof(str), fp) != NULL) {
str[strcspn(str, "\r\n")] = 0; // Remove ending \n
ret &= parse(str);
}
return ret;
}
int main(int argc, char *argv[])
{
FILE* fp;
char* fn = "Synonyms.txt";
fp = fopen(fn, "rt");
if (fp == NULL) {
perror(fn);
return 1;
}
int ret = LoadFile(fp);
fclose(fp);
return ret;
}
I think the biggest conceptual misunderstanding demonstrated in the code is a failure to understand how fgets and fscanf work.
Consider the following lines of code:
while(fgets(synonyms,50,fp)!=NULL){
...
while(fscanf(fp,"%49s",word)==1){
for(i=1;i<strlen(synonyms);i++){
fscanf(fp,"%49s",synonyms);
printf("%s",synonyms);
}
}
}
The fgets reads one line of the input. (Unless there is an input line that is greater than 49 characters long (48 + a newline), in which case fgets will only read the first 49 characters. The code should check for that condition and handle it.) The next fscanf then reads a word from the next line of input. The first line is effectively being discarded! If the input is formatted as expected, the 2nd scanf will read a single - into synonyms. This makes strlen(synonyms) evaluate to 1, so the for loop terminates. The while scanf loop then reads another word, and since synonyms still contains a string of length 1, the for loop is never entered. while scanf then proceeds to read the rest of the file. The next call to fgets returns NULL (since the fscanf loop has read to the end of the file) so the while/fgets loop terminates after 1 iteration.
I believe the intention was for the scanfs inside the while/fgets to operate on the line read by fgets. To do that, all the fscanf calls should be replaced by sscanf.
Whenever a word from wordlist passes as a valid word, strcat(code,wordlist[i]) is called to add the word to world list.
So if at the first line "am" is put, code=am.
Or if abhcgmsopa bqcedpwon abmnpc abcdponm dfajbbmmn cabnmo is put at the first line, the three corresponding valid words are put.
However at the second line the values in code get overwritten and extra characters are put, even though code is initialized outside the while-loop and strcat should append the values to the end of code. Then when the while-loop ends, code is replaced by the entirely by "xq", where x was the first letter put into code and q is from "quitting".
Code isn't reinitialized or changed aside from what is appended to it.
How can I prevent this?
Thanks
*Edit: I defined some stack functions before the main but edited it out here to minimize the code
int main(int argc, char const *argv[])
{
char input[300];
char code[]="";
int ci;
/* set up an infinite loop */
while (1)
{
//break;
/* get line of input from standard input */
printf ("\nEnter input to check or q to quit\n");
fgets(input, 300, stdin);
/* remove the newline character from the input */
int i = 0;
while (input[i] != '\n' && input[i] != '\0')
{
i++;
}
input[i] = '\0';
/* check if user enter q or Q to quit program */
if ( (strcmp (input, "q") == 0) || (strcmp (input, "Q") == 0) )
break;
/*Start tokenizing the input into words separated by space
We use strtok() function from string.h*/
/*The tokenized words are added to an array of words*/
char delim[] = " ";
char *ptr = strtok(input, delim);
int j = 0 ;
char *wordlist[300];
while (ptr != NULL)
{
wordlist[j++] = ptr;
ptr = strtok(NULL, delim);
}
/*Run the algorithm to decode the message*/
//j=words in line;i=i-th word we are evaluating
//k=k-th letter in i-th word
stack1 st;
for(int i=0;i<j;i++){
//stack1 st;
init(&st);
for(int k=0;k<strlen(wordlist[i]);k++){
if((int)wordlist[i][k]<101 && (int)wordlist[i][k]>96){ //check if this letter is a/b/c/d with ascii
push(&st,&wordlist[i][k]);
printf("%c added\n",st.ptr[st.inUse-1]);
}
else{
if(wordlist[i][k]==top(&st)+12){ //check if letter is m/n/o/p corresponding to a/b/c/d from top()
pop(&st);
}
}
}
if(is_empty(&st)){
printf("%s is valid\n",wordlist[i]);
strcat(code,wordlist[i]);
strcat(code," ");
}
else{
printf("%s is invalid\n",wordlist[i]);
clear(&st);
}
printf("code:%s\n",code);
}
printf("code after loop: %s",code);
}
printf("code: %s\n",code);
for(int i=0;i<300;i++){
if ((int)code[i]<101 && (int)code[i]>96){
printf("%c",code[i]);
}
if(!((int)code[i]<96+26 && (int)code[i]>96)){
printf(" ");
}
}
printf("code:%s",code);
printf ("\nGoodbye\n");
return 0;
}
The problem is that your code variable is an array of 1 character! This line:
char code[]="";
declares it as an empty string (no characters) plus a null terminator.
You need to assign it as an array big enough to hold the maximum possible answer! If this is, say, 500, then use this:
char code[500]="";
I am trying to read in a file that contains digits operated by commas and store them in an array without the commas present.
For example: processes.txt contains
0,1,3
1,0,5
2,9,8
3,10,6
And an array called numbers should look like:
0 1 3 1 0 5 2 9 8 3 10 6
The code I had so far is:
FILE *fp1;
char c; //declaration of characters
fp1=fopen(argv[1],"r"); //opening the file
int list[300];
c=fgetc(fp1); //taking character from fp1 pointer or file
int i=0,number,num=0;
while(c!=EOF){ //iterate until end of file
if (isdigit(c)){ //if it is digit
sscanf(&c,"%d",&number); //changing character to number (c)
num=(num*10)+number;
}
else if (c==',' || c=='\n') { //if it is new line or ,then it will store the number in list
list[i]=num;
num=0;
i++;
}
c=fgetc(fp1);
}
But this is having problems if it is a double digit. Does anyone have a better solution? Thank you!
For the data shown with no space before the commas, you could simply use:
while (fscanf(fp1, "%d,", &num) == 1 && i < 300)
list[i++] = num;
This will read the comma after the number if there is one, silently ignoring when there isn't one. If there might be white space before the commas in the data, add a blank before the comma in the format string. The test on i prevents you writing outside the bounds of the list array. The ++ operator comes into its own here.
First, fgetc returns an int, so c needs to be an int.
Other than that, I would use a slightly different approach. I admit that it is slightly overcomplicated. However, this approach may be usable if you have several different types of fields that requires different actions, like a parser. For your specific problem, I recommend Johathan Leffler's answer.
int c=fgetc(f);
while(c!=EOF && i<300) {
if(isdigit(c)) {
fseek(f, -1, SEEK_CUR);
if(fscanf(f, "%d", &list[i++]) != 1) {
// Handle error
}
}
c=fgetc(f);
}
Here I don't care about commas and newlines. I take ANYTHING other than a digit as a separator. What I do is basically this:
read next byte
if byte is digit:
back one byte in the file
read number, irregardless of length
else continue
The added condition i<300 is for security reasons. If you really want to check that nothing else than commas and newlines (I did not get the impression that you found that important) you could easily just add an else if (c == ... to handle the error.
Note that you should always check the return value for functions like sscanf, fscanf, scanf etc. Actually, you should also do that for fseek. In this situation it's not as important since this code is very unlikely to fail for that reason, so I left it out for readability. But in production code you SHOULD check it.
My solution is to read the whole line first and then parse it with strtok_r with comma as a delimiter. If you want portable code you should use strtok instead.
A naive implementation of readline would be something like this:
static char *readline(FILE *file)
{
char *line = malloc(sizeof(char));
int index = 0;
int c = fgetc(file);
if (c == EOF) {
free(line);
return NULL;
}
while (c != EOF && c != '\n') {
line[index++] = c;
char *l = realloc(line, (index + 1) * sizeof(char));
if (l == NULL) {
free(line);
return NULL;
}
line = l;
c = fgetc(file);
}
line[index] = '\0';
return line;
}
Then you just need to parse the whole line with strtok_r, so you would end with something like this:
int main(int argc, char **argv)
{
FILE *file = fopen(argv[1], "re");
int list[300];
if (file == NULL) {
return 1;
}
char *line;
int numc = 0;
while((line = readline(file)) != NULL) {
char *saveptr;
// Get the first token
char *tok = strtok_r(line, ",", &saveptr);
// Now start parsing the whole line
while (tok != NULL) {
// Convert the token to a long if possible
long num = strtol(tok, NULL, 0);
if (errno != 0) {
// Handle no value conversion
// ...
// ...
}
list[numc++] = (int) num;
// Get next token
tok = strtok_r(NULL, ",", &saveptr);
}
free(line);
}
fclose(file);
return 0;
}
And for printing the whole list just use a for loop:
for (int i = 0; i < numc; i++) {
printf("%d ", list[i]);
}
printf("\n");
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int individualAverage(int data[][20],int j)
{
int k,average=0;
for(k=0;k<10;k++)
{
average += data[k][j];
}
return average;
}
int main()
{
int var,indAvg=0;
int i=0,j,k;
char *experiments[20];
int data[10][20];
char str[100],str2[100];
char *ptr, *token;
int no_line=1;
while(fgets(str,100,stdin) != NULL && (strcmp(str,"*** END ***") && strcmp(str,"*** END ***\n")))
{
if(no_line % 2 == 0)
{
k=0;
token = strtok (str," ");
while (token != NULL)
{
sscanf (token, "%d", &var);
data[k++][i] = var;
token = strtok (NULL," ");
}
i++;
}
else
{
ptr = strdup(str);
experiments[i] = ptr;
}
no_line++;
}
fgets(str,100,stdin);
token = strtok(str," ");
while(token != NULL && (strcmp(token,"4") && strcmp(token,"4")))
{
sscanf (token, "%d", &var);
printf("DATA SET ANALYSIS\n1.\tShow all the data\n2.\tCalculate the average for an experiment\n3.\tCalculate the average across all experiments\n4.\tQuit\nSelection: %d\n\n",var);
switch(var)
{
case 1 :
for(j=0;j<i;j++)
{
printf("%s",experiments[j]);
for(k=0;k<10;k++)
{
printf("%d ",data[k][j]);
}
printf("\n");
}
printf("\n");
break;
case 2 :
printf("What experiment would you like to use?\n");
token = strtok (NULL," ");
sscanf (token, "%s", &str);
for(j=0;j<i;j++)
{
if(strcmp(experiments[j],str) == 0)
{
indAvg = individualAverage(data,j);
printf("Experiment: %s",experiments[j]);
printf("The individual average of the experiment is %d\n",indAvg);
break;
}
}
}
token = strtok(NULL," ");
}
}
OK, so I have a method that takes lines of redirection input. The lines come in pairs. First line is the name of an experiment, and the second line has the 10 values separated by spaces for that experiment. After these pairs, there is an ending line "*** END ***"
After this line, there is one last line holding the instructions of what to do with the data.
I'm currently having a problem where I've used fgets() to store the strings of the first pairs of lines into a variable which I declared as char *experiments[20];
Each of strings that this array is pointing to will have '\n' at the end of the string because of fgets()
Back to the last line of instructions. You have values 1-4. Right now I'm looking at instruction 2. It tells the average of an experiment. So after 2 on the last line, there must be the name of one of the experiments. I've used:
char str[100];
int var;
char *token;
token = strtok(str, " ");
sscanf (token, "%d", &var);
to get the first value on the line into var (pretend it's 2). So after that would be a string. Say it's Test 1, I'll use
token = strtok (NULL," ");
sscanf (token, "%s", &str);
to get the value into str, and then I'll compare it to experiments for all possible indexes.
HOWEVER, because fgets() gives '\n' at the end of the lines, all of the experiments strings will have '\n' at the end while str will just have the name of the experiment WITHOUT '\n' therefore they will never be equal even if '\n' is the only difference between the strings.
Any solutions?
Since you know that there may be a \n at the end of the string, you could check for it, and remove it if it's there:
size_t len = strlen(str);
if (len != 0 && str[len-1] == '\n') {
str[len-1] = '\0';
}
This would terminate the line at \n, so your strcmp would succeed. An alternative is to use strncmp, and pass the length of the target string. This runs the risk of false positives when there's a longer suffix that \n, though.
You could also read your data like this:
fscanf(f, "%99[^\n]", str);
You can make your own version of fgets that doesn't store the new-line character when it encounters one, and call it myfgets. Something like this would replicate fgets's behaviour, I think, produced with respect to the description given in MSDN:
char * myfgets( char * str, int n, FILE * stream ) {
if ( n <= 0 ) return NULL; // won't accept less than or equal to zero length
int currentPos = 0;
while ( n-- > 0 ) {
int currentChar = fgetc( stream );
if ( currentChar == EOF ) return NULL;
if ( currentChar == '\n' ) break;
// if these two lines were in reversed order,
// it would behave same as the original fgets
str[currentPos++] = currentChar;
}
return str;
}
But of course the other solution is simpler, hehe...