-1

I am trying to find every line that has a specific in a text file and count them without using strstr, or getline. how can I change my code to work without it?

#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]){

FILE * fp;
char * s = argv[1];
int lines = 0, i;
fp = fopen("mytext.txt", "r");
if(fp == NULL){
    printf("error\n %d", fp);
    exit(1);
}
size_t lookfor;
char * lines = NULL;
size_t len = 0;
while ((lookfor = getline(&lines, &len, fp)) != -1) {
    if(strstr(lines, s) != NULL) {
        lines+= 1;
    }
}
fclose(fp);
printf("the number of lines that include the word 'great' are%d\n", lines);
return 0;
}
alpitaka
  • 55
  • 6
  • 2
    "Without library functions"? It's going to be pretty much impossible to open the file or read data from it without calling library functions. Which library functions are you allowed to use? – Andrew Henle Jan 31 '19 at 23:30
  • oh sorry, i'm only talking about without my strstr and getline – alpitaka Jan 31 '19 at 23:31
  • 2
    @AndrewHenle Do you consider system calls to be "library functions"? Because it is simple to read a file using `open`/`read`/`close`. – Jonathon Reinhart Jan 31 '19 at 23:35
  • 3
    What have you got against the function: `strstr()` and the function: `getline()`? – user3629249 Jan 31 '19 at 23:47
  • 1
    We are not supposed to do your own homework. Show us what *you* have tried. – Basile Starynkevitch Jan 31 '19 at 23:48
  • 1
    Suggest implementing a state machine and using `fgetc()` to input the file contents – user3629249 Jan 31 '19 at 23:48
  • 1
    Have you noticed that the posted code does not compile. Amongst other problems, it is missing the `string.h` header file – user3629249 Jan 31 '19 at 23:50
  • 1
    OT: regarding: `char * s = argv[1];` The code should never access beyond `argv[0]` with out first checking `argc` to assure the expected command line parameter was actually entered by the user – user3629249 Jan 31 '19 at 23:51
  • 1
    OT: regarding: `printf("error\n %d", fp);` Error messages should be output to `stderr`, not `stdout` and when the error indication is from a C library function, should also output (to `stderr`) the text reason the system thinks the error occurred. Suggest using `perror( "my error message" );` as that handles all the above correctly. Also, the `fp` is a pointer, not an integer, so the statement should be: `printf("error\n %p", (void*)fp);` – user3629249 Jan 31 '19 at 23:56
  • 1
    regarding: `char * lines = NULL; ..... lines+= 1;` Strongly suggest using an `int`, initialized to 0 not a `char*` – user3629249 Feb 01 '19 at 00:03
  • Your question lacks some [MCVE]. The given code is not one, it should not compile. So I downvoted the question and voted to close it. – Basile Starynkevitch Feb 01 '19 at 00:05
  • regarding: `printf("the number of lines that include the word 'great' are%d\n", lines);` How does the code know that the command line parameter is `great`? Suggest displaying the actual command line parameter, as pointed to be `s` – user3629249 Feb 01 '19 at 00:07
  • regarding: `while ((lookfor = getline(&lines, &len, fp)) != -1) {` the syntax is: `ssize_t getline(char **lineptr, size_t *n, FILE *stream);` Notice the returned type is `ssize_t` (a signed value) not `size_t` which is an unsigned value AND the comparison is to `-1` which is a signed value. In programming, details count – user3629249 Feb 01 '19 at 00:17
  • OOPS, I made an error, the `lines` should be a `char *`, initialized to `NULL`. However, then the statement: `lines+= 1` is nonsense. Suggest using a `int` variable as a counter – user3629249 Feb 01 '19 at 00:24
  • @JonathonReinhart Of course `open()` is almost always a **library function**. The "system call" distinction is completely artificial on just about every system. `open()` is a function in `libc.so`, for example, just like `fopen()` is. Worse, it's often a misleading distinction, as the mapping from function to system call isn't one-to-one. Both the `open()` and `fopen()` functions can map to the `openat()` system call. Labeling `open()` as a "system call" on POSIX systems is like labeling `OpenFile()` a "system call" on a Windows system. Who does that? Then don't do it on POSIX. – Andrew Henle Feb 01 '19 at 10:09

1 Answers1

2

Since you are including <stdio.h> you are implicitly allowing yourself to use the standard IO functions (If even this is forbidden, how would input or output happen in your program?).

Be sure to look into some C reference about the C standard library functions. Read the documentation of every function that you are using. Later, check also the C11 standard n1570.

On Linux, getline is declared in <stdio.h> but is not a standard IO function. It is in POSIX. That is documented in the getline(3) manual page (obtained with man getline command).

So you can, and you probably should, use functions like fopen and fgets and fgetc. On Linux, see also their man page, e.g. fgets(3), which reminds you that it is standardized in C99.

A simple approach would be to declare some buffer for your line, e.g.

char mylinebuf[128];

to document that you accept only lines smaller than 128 bytes, and to use

char* res = fgets(mylinebuf, sizeof(mylinebuf), fp);

Don't forget to test against failure of standard IO functions. In particular, fopen could fail and fgets could also fail.

A more clever approach might mimic what getline is doing (so perhaps write your own mygetline function), using only fgetc(3).

If you are forbidden to use strstr you could write your own mystrstr function doing the same (perhaps using strchr if you are allowed to use that, otherwise coding all by yourself). This is basic pointer stuff.

Writing your mystrstr above strchr is left as an exercise to the reader. And also writing your mystrchr using basic pointer operations.

If using GCC on Linux, always enable all warnings and debug info, so compile with gcc -Wall -Wextra -g.

Read also How to debug small programs. So on Linux learn to use the gdb debugger and valgrind. Avoid undefined behavior -UB- (and your program have several of them, e.g. when invoked without additional arguments). For example

     printf("error\n %d", fp);

is wrong and UB (and the compiler would have warned you with gcc -Wall -Wextra -g).

You need to improve your code to avoid UB, and that is much more than just changing it to avoid strstr.

BTW, in 2019, UTF-8 is used everywhere (in practice), and that might add complication to your program, if you want to be serious (you might want to use libunistring if you are allowed to, or else write your mystrstr to know about UTF-8, and check that your input file contents -or your program arguments- are valid UTF-8; it might not be the case.).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • Where is the change from ASCII to UTF-8 documented? What about older code that still uses ASCII? – user3629249 Feb 01 '19 at 00:28
  • That change is not documented (and ASCII is not in the C11 standard; you could code in C on IBM mainframes using EBCDIC), but UTF-8 has, in 2019, become common practice. – Basile Starynkevitch Feb 01 '19 at 00:36