How to properly use strcasecmp in c - c

I am reading one line from a file which contains on the first line the word "hello". And then I am comparing it with "hello" using strcasecmp, however it is telling me it is still different
char *line = NULL;
size_t len = 100;
printf("%s", argv[1]);
FILE * fp = fopen(argv[1], "r");
if (fp == NULL) {
printf("empty\n");
exit(0);
}
getline(&line, &len, fp);
if (strcasecmp(line, "hello") == 0) {
printf("same");
}

strcasecmp will only return 0 if the strings are the same (except for the case), not if the first string starts with the second string.
And getline reads the newline character at the end of the line, so if you type "hello" the string you get in "line" will be "hello\n".

this is from the man page for getline()
getline()
reads an entire line from stream, storing the address of the
buffer containing the text into *lineptr.
The buffer is null-terminated
and includes the newline character, if one was found.
Notice that part about including the newline character.
So, either limit the length of the comparison or better, trim the new line char, using something similar to:
char * newline = NULL;
if( NULL != (newline = strchr( line, '\n' ) )
{ // then newline found
*newline = '\0';
}

Related

Write a program that reads strings and writes them to a file

Here's my task, below is most of the code done and finally my specific question
Write a program that reads strings and writes them to a file. The string must be dynamically allocated and the string can be of arbitrary length. When the string has been read it is written to the file. The length of the string must be written first then a colon (‘:’) and then the string. The program stops when user enters a single dot (‘.’) on the line.
For example:
User enters: This is a test
Program writes to file: 14:This is a test
Hint: fgets() writes a line feed at the end of the string if it fits in the string. Start with a small length, for example 16 characters, if you don’t see a line feed at the end then realloc the string to add more space and keep on adding new data to the string until you see a line feed at the end. Then you know that you have read the whole line. Then remove any ‘\r’ or ‘\n’ from the string and write the string length and the string to the file. Free the string before asking for a new string.
MY CODE:
#pragma warning(disable: 4996)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_NAME_SZ 256
int main()
{
char key[] = ".\n";
char* text;
text = (char*)malloc(MAX_NAME_SZ);
if (text == NULL)
{
perror("problem with allocating memory with malloc for *text");
return 1;
}
FILE* fp;
fp = fopen("EX13.txt", "w");
if (fp == NULL)
{
perror("EX13.txt not opened.\n");
return 1;
}
printf("Enter text or '.' to exit: ");
while (fgets(text, MAX_NAME_SZ, stdin) && strcmp(key, text))
{
fprintf(fp, "%ld: %s", strlen(text) - 1, text);
printf("Enter text or '.' to exit: ");
}
free((void*)text);
fclose(fp);
puts("Exit program");
return 0;
}
SPECIFIC QUESTION:
How can I make the program to allow arbitrarily long lines so there shouldn't be no limit at all for line length? Thanks
You could declare a pointer to char, read char by char and keep using reallocating the pointer until you get to the '\n':
int main()
{
char key[] = "."; //Excluded the \n since I'm not using fget
char* text;
FILE* fp;
fp = fopen("EX13.txt", "w");
if (fp == NULL)
{
perror("EX13.txt not opened.\n");
return 1;
}
printf("Enter text or '.' to exit: ");
int cont = 0;
while (1) //read all chars
{
if(!cont) //if it is the first, allocate space for 1
text = (char*) malloc(sizeof (char));
else //otherwise increase the space allocated by 1
text = (char*) realloc(text, (cont + 1) * sizeof(char));
scanf("%c", &text[cont]); //read a single char
if(text[cont] == '\n') //see if it is the end of line
{
text[cont] = 0; //if it is the end of line, then it is the end of the string
if(!strcmp(key, text)) //if the string is just a dot, end the loop
break;
fprintf(fp, "%ld: %s\n", cont, text);
printf("Enter text or '.' to exit: ");
cont = 0; //restarting the counter for the next input
free(text); // freeing after each iteration. you can optimize to maintain the space and only increase after getting to a bigger string than the previous you had so far
}
else //if it is not the end of the string, increase its size by 1
cont++;
}
free((void*)text);
fclose(fp);
puts("Exit program");
return 0;
}
Suggest using getline()
This seems to be a class room assignment, so I will not be writing the code for you.
Note: for the getline() function to be visible in linux, at the beginning of your code, you will need a statement similar to:
#define _GNU_SOURCE
or
#define _POSIX_C_SOURCE 200809L
getline(3)
NAME
getdelim, getline -- get a line from a stream
LIBRARY
Standard C Library (libc, -lc)
SYNOPSIS
#include <stdio.h>
ssize_t
getdelim(char ** restrict linep, size_t * restrict linecapp,
int delimiter, FILE * restrict stream);
ssize_t
getline(char ** restrict linep, size_t * restrict linecapp,
FILE * restrict stream);
DESCRIPTION
The getdelim() function reads a line from stream, delimited by the char-
acter delimiter. The getline() function is equivalent to getdelim() with
the newline character as the delimiter. The delimiter character is
included as part of the line, unless the end of the file is reached.
The caller may provide a pointer to a malloced buffer for the line in
*linep, and the capacity of that buffer in *linecapp. These functions
expand the buffer as needed, as if via realloc(). If linep points to a
NULL pointer, a new buffer will be allocated. In either case, *linep and
*linecapp will be updated accordingly.
RETURN VALUES
The getdelim() and getline() functions return the number of characters
written, excluding the terminating NUL character. The value -1 is
returned if an error occurs, or if end-of-file is reached.
EXAMPLES
The following code fragment reads lines from a file and writes them to
standard output. The fwrite() function is used in case the line contains
embedded NUL characters.
char *line = NULL;
size_t linecap = 0;
ssize_t linelen;
while ((linelen = getline(&line, &linecap, fp)) > 0)
fwrite(line, linelen, 1, stdout);
ERRORS
These functions may fail if:
[EINVAL] Either linep or linecapp is NULL.
[EOVERFLOW] No delimiter was found in the first SSIZE_MAX characters.
These functions may also fail due to any of the errors specified for
fgets() and malloc().
Note: you will need to pass to free() the line, when the code is through with it, to avoid a memory leak.
Note: to remove any trailing '\n' you can use:
line[ strcspn( line, "\n" ) ] = '\0';
Note: after removing any trailing '\n' you can use:
size_t length = strlen( line );
To get the length of the line in bytes.
Then print that length and the line using:
printf( "%zu:%s", length, line );

switching from getchar to fgets

I am trying to switching my use of getchar to fgets but, when using getchar, the entire code does not work.
//fgets(line, sizeof(line), stdin);
while(fgets(line, sizeof(line), stdin))
{
portNum[sizeof(line)] = (char)line;
}
while((c = getchar()) != '\n')
{
portNum[num++] = c;
}
portNum[num] = '\0';
How can I make equal for those two functions to work properly?
You usage of fgets is wrong.
fgets Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or the end-of-file is reached, whichever happens first.
In your case fgets will read all the characters until newline is encountered.
Also, the parameters usage is wrong.
char * fgets ( char * str, int num, FILE * stream );
str => Pointer to an array of chars where the string read is copied.
num => Maximum number of characters to be copied into str (including the
terminating null-character).
stream => Pointer to a FILE object that identifies an input stream.
stdin can be used as argument to read from the standard input.
Refer to the fgets documentation for more information.
fgets man page
OP's fgets() usage is unclear and portNum[sizeof(line)] = (char)line; is certainly in error.
Instead: how to make the below getchar() code more fgets()-like:
// assumed missing code
#define N 100
int c;
char portNum[N];
size_t num = 0;
// size and EOF detection added (which should have been there)
while(num + 1 < sizeof portnum && (c = getchar()) != '\n' && c != EOF) {
portNum[num++] = c;
}
portNum[num] = '\0';
// assumed missing code
if (c == EOF && num == 0) Handle_EndOfFile_or_InputError();
else ...
This can be replaced with fgets() code
#define N 100
char portNum[N+1]; // 1 larger for the \n
if (fgets(portNum, sizeof portNum, stdin)) {
// lop off potential trailing \n
portNum[strcspn(portNum, "\n")] = '\0';
...
} else {
Handle_EndOfFile_or_InputError();
}

strip new line character from end from char* [duplicate]

This question already has answers here:
Removing trailing newline character from fgets() input
(14 answers)
Closed 6 years ago.
I have a char* line on which I used while (fgets(line, line_size, fNames) != NULL). now the problem is I also get a new line character, which I want to strip.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main() {
int i;
char fileName[30];
FILE *fNames, *fCurrent;
char *line = NULL, command[100];
char letters3[3];
size_t len = 0;
//size_t read;
const size_t line_size = 300;
line = malloc(line_size);
if (access("fileNames.lst", F_OK) == -1)
system("crunch 3 3 abcd -o fileNames.lst");
else
printf("fileNames.lst already exists.\n");
fNames = fopen("./fileNames.lst","r");
while (fgets(line, line_size, fNames) != NULL) {
printf("Making File: %s.lst\n", line);
strcpy(command, "crunch 8 8 -t ");
strcpy(command, line);
strcpy(command, strcat(command," -o"));
puts(command);
strcpy(line, strcat(line, ".lst"));
fCurrent = fopen(line, "w");
//system(command);
fclose(fCurrent);
//system("read -r -p \"Press space to continue...\" key");
}
return 0;
}
There are problems in your code:
You do not check the return value of fopen(), nor that of malloc().
strcpy(command, strcat(command," -o")); and strcpy(line, strcat(line, ".lst")); invoke undefined behavior as you call strcpy on overlapping strings.
strcpy(command, line); overwrites the string you just copied to command with strcpy(command, "crunch 8 8 -t ");.
You do not check the lengths before copying or concatenating strings into line and command. You should use snprintf() for both a safer and simpler method.
To get rid of the trailing linefeed in line left by fgets(), you can either write:
line[strcspn(line, "\n")] = '\0';
or you can write this:
char *p = strchr(line, '\n');
if (p != NULL)
*p = '\0';
or even this one that removes the linefeed at the end of the string:
size_t len = strlen(line);
if (len > 0 && line[len - 1] == '\n')
line[--len] = '\0';
With both of the latter methods, you can track whether there was indeed a linefeed or not. The absence of a linefeed at the end of the line can mean one of several possibilities:
The line was truncated because it does not fit in the buffer provided. You should be careful to handle this condition because the string read does not correspond to the actual file contents. It could happen in your case if a filename is longer than 298 bytes, which is possible on many modern file systems.
The end of file was reached but no linefeed is present in the file at the end of the last line. This is probably not an error, but could indicate that the input file was truncated somehow.
The input file contains a '\0' byte, which causes early termination of the line read by fgets(). This would not be allowed as part of a filename and is quite unlikely to occur in text files, unless the file was encoded as ucs2 or UTF-16.
I think you are searching for this one. It is very easy to use and it does the job.
line[strcspn(line, "\n")] = '\0';

How to determine if fgets stopped before all letters were read?

I do something like this:
char buf[100];
int n = 0;
char save[100][100];
while (fgets(buf,100, file)!=NULL) {
strcpy(save[n], buf);
printf("%s",buf);
n++;
}
I opened a FILE = *file with error handling before.
I only want to read the lines that have less than or equal to 100 characters. Those that feature more characters, I want to ignore and write some special message to the "save" array or to the perror or stout stream.
However, how can I possibly know whether I got exactly 100 characters or my fgets has simply stopped reading at its limit?
How can I know whether I got more than 100 in the first place?
Don't use fgets(), use getline(). With fgets(), once you read a too-long line (however you identify it), you'll have to keep reading that line and discarding it until you reach a new line. In other words, you have a need to track state, which isn't needed if you use getline() since it gives you the entire line, and tells you how long it is:
FILE *fp = // fopen() however you need to
char *lineArray[ MAX_LINES ];
int ii = 0;
char *line = NULL;
size_t len = 0UL;
// loop until getline() fails
for ( ;; )
{
ssize_t lineLen = getline( &line, &len, fp );
if ( lineLen == -1L )
{
break;
}
if ( lineLen > 100L )
{
// handle too-long line
}
else
{
lineArray[ ii ] = strdup( line );
ii++;
}
}
You might want to strip any trailing newline characters from each line before copying the line to the array.
Note that I used strdup() to copy the line - that's not a C Standard function, but it is POSIX.
First let us assume that fgets() is not going to read a null character. If it does, the following method may be insufficient.
I only want to read the lines that have less than or equal to 100 characters. Those that feature more characters, I want to ignore and write some special message to the "save" array
Problem 1. Is the '\n' or Enter part of the 100 characters? Let us assume it is not.
OP appears to still want to read the line, be it longer or shorter than 100 or COLS characters, it is just a question of what to do with it then.
Recommend a buffer of COLS+3. One for the null character, one for the '\n' and one for extra long line detection.
#define ROWS 100
#define COLS 100
char save[ROWS][COLS+1]; // +1 for \0
char buf[COLS + 3];
int n = 0;
while (n < ROWS && fgets(buf, sizeof buf, file)!=NULL) {
size_t len = strlen(buf);
bool EOLorEOFfound = false;
// lop off potential \n
if (len > 0 && buf[len - 1] == '\n') {
buf[--len] = '\0';
EOLorEOFfound = true;
}
// if line is too long ...
if (len > COLS) {
// consume rest of line
while (!EOLorEOFfound) {
int ch = fgetc(file);
EOLorEOFfound = ch == '\n' || ch == EOF;
}
// write some special message to the "save" array
assert(COLS >= 3);
strcpy(save[n], "***");
}
// Line not too long
else {
strcpy(save[n], buf); // or memcpy(save[n], buf, len+1);
printf("%s\n", buf);
}
n++;
}
You could check the string length and the last character. If the length is 99 characters and the last character is not a newline, then there are more characters on the line that fgets didn't read (though the remaining characters might just be the newline).
If fgets read the whole line, either the length of the string will be less than 99 or the last character will be a newline (which fgets always adds if it fits in the buffer).
Note that I say 99 characters, as an array of 100 character will only fit 99 characters plus the string terminator character '\0'. If you want to read up to (and including) 100 characters, your buffer needs to be 101 characters large.
Example showing it in "action". The first two outputs is from reading lines that are longer, and fgets didn't read all of the line. The second two lines of output are when fgets read the whole lines.

detect EOL in C using fgets

I'm attempting to read a single line from a file using the following...
while(fgets(c,BUF,f) != EOL){
puts(c);
}
Where EOL = #define EOL '\n' however, I get the warning... comparison between pointer and integer
What is the correct way to achieve what I'm trying?
fgets reads a string, and the result type is char*
I'd think you are thinking of fgetc instead?
Why don't you try fgetc instead? Then you can compare the ASCII code of '/n' like this
while (fgetc (file) != '\n'){
puts(c);
}
You need to dereference the returned char* and compare that to your EOL ... not compare the actual pointer address itself to the end-of-line character.
Change your code to this:
char* return_val = NULL;
while((return_val = fgets(c,BUF,f)) != NULL && *return_val != EOF)
{
puts(c);
}
if (retun_val == NULL)
{
//handle error
}
You have to examine the contents of c after the call to fgets to determine if a newline was included in the returned string:
for (;;) {
if (fgets(c, BUF, f) == NULL) { /* handle error */ }
if (strchr(c, EOL) != NULL) {
puts(c);
} else {break; }
}
fgets reads characters from the stream and writes them in the buffer until either the buffer is almost full or it finds a '\n' (it returns NULL if the operation fails).
So you can know how many characeters were read (including the '\n') with strlen ...
ret = fgets(buffer, sizeof buffer, stdin);
if (ret == NULL) /* deal with error */;
chars = strlen(buffer);
Now, one of 2 things may have hapenned: either a '\n' was read before the buffer got full or the buffer gor full before a '\n' was read. You can know which was it by examining the last character in the buffer
if (buffer[chars - 1] == '\n') /* full line read */;
else /* incomplete line */;
Note that chars is always (*) 1 or more, so the expression buffer[chars - 1] is ok.
(*) it could be 0 only with binary data for input, but that denies the use of strlen and other string functions.

Resources