read a txt file line by line in C - c

I'm trying to retract strings from a txt file.
The file content is;
apple
pear
orange
basicly every line has one word and I would like to read every line and retract words into the string char* word[25] because the longer word is 24 characters. When I implement a simple code to read every character in ASCII between each line there was value 10 for end of line. So I created a for loop without any condition and added if condition to spot the 10 value end of line (LF). But it doesn't work and I'm sure I messed in something very basic in code or logic. Sorry if my code seems unlogical or very wrong, I'm fairly new. Also there are lots of libraries added cos I'm going to use them if I could done this step. TIA
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("Usage: ./word filename\n");
return 1;
}
FILE* ptr = fopen(argv[1], "r");
char ch;
char* word[45];
for (int i = 0; ;i++)
{
ch = fgetc(ptr);
word[i] = &ch;
if (ch == 10)
{
break;
}
}
printf("%s\n", *word);
return 0;
}
terminal output
~/snippets/ $ make word
clang -ggdb3 -O0 -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow word.c -lcrypt -lcs50 -lm -o word
~/snippets/ $ ./word lec3.txt
`
~/snippets/ $

What if you drop the pointers ..
char ch;
char word[45];
for (int i = 0; ;i++)
{
ch = fgetc(ptr);
word[i] = ch;
if (ch == 10)
{
break;
}
}
printf("%s\n", word);

You could do it dynamically too :
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
if (argc < 2)
{
printf("Usage: ./word filename\n");
return 1;
}
FILE *ptr = fopen(argv[1], "r");
char ch;
int i = 0;
char *word = calloc(45, sizeof(char));
for (ch = fgetc(ptr); ch != EOF; ch = fgetc(ptr), i++)
{
if (ch == '\n')
break;
word[i] = ch;
}
printf("%s\n", word);
free(word);
return 0;
}

Related

Minishell 'segmentation fault, core dumped' error in C

Following is a part of my code for my shell. The code works, but when I try to enter a command like "ls", my program crashes. I think that's a right error because I try to access to the "/bin" file.
void lecture (char cmd1[], char *argv[]){
int x = 0;
char ligne [1024];
char *aux [100], *pch;
while (1){
int mot = fgetc (stdin);
ligne[x] = (char) mot;
x++;
if (mot == (int)'\n') break;
}
aux[0] = strtok (ligne, " \n");
strcpy(cmd1,aux[0]);
for (int i = 1; i <= 1024; i++){
argv[i+1] = aux[i];
}
}
int main(){
char cmd1 [100];
char cmd2 [100];
int a = 10;
char *argv [20];
char *envp[] = {(char *) "PATH=/bin", 0};
while (1){
affichage();
lecture (cmd2, argv);
printf("Test");
if ( fork() != 0){
printf("Err");
wait (NULL);
}else{
strcpy(cmd1, "/bin/");
strcat(cmd1, cmd2);
execve(cmd1, argv, envp);
}
}
}
I get something working without SIGSEGV with following modification in lecture:
for (int i = 0; i < 20; i++){
Example:
./ms
ls
����: cannot access 'ls': No such file or directory
TestErr
...
But you can also debug this as I did with compiling in debug mode:
gcc -o ms -g -Wall -pedantic -Wextra -std=c11 ms.c
and using gdb to check where SIGSEGV occurs.
Note that you are expected to post a https://stackoverflow.com/help/minimal-reproducible-example with full code (here we are missing affichage) and
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

C Turning lines of an archive into arrays

I have an archive and I want to turn every line into an array: v[i].data.
However, when I run the code it shows zeros for the arrays.
Is there anything I should change?
Input
1760
02/20/18,11403.7
02/19/18,11225.3
02/18/18,10551.8
02/17/18,11112.7
02/16/18,10233.9
Actual Output
1761
0
Expected Output
1761
02/20/18,11403.7
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
typedef struct{
char data[20];
}vetor;
int main(int argc,char *argv[]){
FILE *csv;
if((csv=fopen(argv[1], "r")) == NULL )
{
printf("not found csv\n");
exit(1);
}
long int a=0;
char linha[256];
char *token = NULL;
if(fgets(linha, sizeof(linha), csv)) //counting lines
{
token = strtok(linha, "\n");
a =(1 + atoi(token));
}
printf("%d\n", a);
rewind(csv);
vetor *v;
v=(vetor*)malloc(a*sizeof(vetor));
char linha2[256];
while (fgets(linha2, sizeof(linha2), csv) != 0)
{
fseek(csv, +1, SEEK_CUR);
for(int i=0;i<a;i++)
{
fscanf(csv, "%[^\n]", v[i].data);
}
}
printf("%s\n", v[0].data);
fclose(csv);
return 0;
}
There were a number of mistakes so I went ahead and rewrote the problem areas with comments explaining what I did
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char data[20];
}vetor;
int main(int argc,char *argv[]){
FILE *csv;
if((csv=fopen(argv[1], "r")) == NULL )
{
printf("not found csv\n");
exit(1);
}
char line[20];
// Read number of lines
int num_lines = 0;
if (!fgets(line, sizeof(line), csv)) {
printf("Cannot read line\n");
exit(1);
}
char* token = strtok(line, "\n");
num_lines = atoi(token) + 1;
vetor* v = malloc(num_lines * sizeof(vetor));
// Fill in vetor
int i = 0;
while (fgets(line, sizeof(line), csv) != NULL) {
int len = strlen(line);
line[len-1] = '\0'; // replace newline with string terminator
strcpy(v[i].data, line); //copy line into v[i].data
i++;
}
printf("%d\n", num_lines);
for (i = 0; i < num_lines; i++) {
printf("%s\n", v[i].data);
}
return 0;
}
I think the main mistake was a misunderstanding of how best to read in each line of information. If I understood correctly you want each 02/20/18,11403.7 line to be an element in the vetor array.
The easiest way is to simply get each line one at a time with fgets
while (fgets(line, sizeof(line), csv) != NULL)
Change the ending character from newline to the string terminating character '\0'
int len = strlen(line);
line[len-1] = '\0';
Then copy the string into the ith element of vetor and update i for the next iteration of the loop.
strcpy(v[i].data, line);
i++;

How to delete '#' symbols from a given file C

file1
:once:echo Hello # this is a comment
:once:echo 1
:once:echo 2
:once:echo 3
:once:echo 4
Consider the file above, If I wanted to print out each line one by one how would I remove the "# this is a comment" and ':once:'
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv) {
FILE *file = fopen(argv[1], "r");
char buf[100];
char p;
while (fgets(buf, sizeof(buf), file)) {
if ((p = strchr(buf, '#')))
*p = '\0';
printf("%s\n", buf);
}
fclose(file);
}
I think I can use strchr to remove the comments but unsure how to go about this.
I want the output to be this
$ gcc -Wall a.c
$ ./a.out file1
echo Hello
echo 1
echo 2
echo 3
echo 4
Current output:
:once:echo Hello # This is a comment
:once:echo 1
:once:echo 2
:once:echo 3
:once:echo 4
Unsure why the extra space is there. I think I have the right approach with the strchr just unsure how to use.
You should change char p; to char *p;, otherwise this is not going to work at all. If you're looking for :once: only at the start of a line, you can use strncmp() to check the first six characters, and offset the start of the string if necessary.
Also, since fgets() retains line break characters, you may as well add \n and \0 when you encounter a # symbol, and then leave out the \n when printing each line. That way your output won't be filled with double line breaks.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv) {
FILE *file = fopen(argv[1], "r");
char buf[100];
char *p;
while (fgets(buf, sizeof(buf), file)) {
if ((p = strchr(buf, '#'))) {
*(p++) = '\n';
*p = '\0';
}
printf("%s", buf + (strncmp(buf, ":once:", 6) == 0 ? 6 : 0));
}
fclose(file);
}
This should work for you. I added a nested for inside of the while, to loop through buf and check for the '#' hash character. You should always be sure to check if the necessary file exists or not, instead of assuming that it does.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv) {
FILE *file;
if (!(file = fopen(argv[1], "r"))) {
fprintf(stderr, "The specified file does not exist\n");
return 1;
}
char buf[100];
int x;
while (fgets(buf, sizeof(buf), file)) {
for (x = 0; x < sizeof(buf); x++) {
if (buf[x] == '#')
buf[x] = '\0';
}
if (strncmp(buf, ":once:", 6) == 0)
printf("%s\n", buf + 6);
else
printf("%s\n", buf);
}
fclose(file);
return 0;
}

Lowercase to uppercase with opening new file

I tried to change all random lowercase letters to uppercase letters in this program.First of all, I have initialized in lowercase.txt AkfsASlkALfdk.Then I read from it and changing all the lowercase letters into capital ones.The problem is,when I opened the capital.txt is ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌAKFSASLKALFDK.Where did the error come from?I couldn't find it yet and I decided to ask you.
#pragma warning(disable:4996)
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
#include <conio.h>
int main()
{
int i;
char s[100];
char k[100];
FILE *kp;
kp = fopen("lowercase.txt", "r");
if (kp == NULL)
{
printf("Error in opening file.\n");
system("pause");
exit(1);
}
FILE *temp;
temp = fopen("capital.txt", "w");
if (kp == NULL)
{
printf("Error in opening file.\n");
system("pause");
exit(2);
}
printf("Opening file is successful.\n");
if (fscanf(kp, "%s", &s) != EOF)
{
for (i = 0; i < 100; i++)
{
if (s[i] >= 97 && s[i] <= 122)
{
s[i] -= 32;
}
}
}
fprintf(temp, "%s", k);
getch();
return 0;
}
Multiple issues in your code which together cause the issues
You are storing the opened FILE* in temp, but checking kp. I think that is because you copy pasted the check from above. Can be easily fixed by changing the variable
You perform the capitalization operation outside what was set by scanf. As suggested by #MOehm, change the loop condition to s[i]
Finally you are converting the string in place in s but are saving k in the file. k is never modified. Change fprintf(temp, "%s", k); to fprintf(temp, "%s", s);
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
char *append(const char *s, char c) {
int len = strlen(s);
char buf[len+2];
strcpy(buf, s);
buf[len] = c;
buf[len + 1] = 0;
return strdup(buf);
}
int main(int argc, char **argv)
{
char ch;
FILE *fp;
if (argc != 2)
return (0);
if ((fp = fopen(argv[1], "r")) == NULL)
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
char *res;
while((ch = fgetc(fp)) != EOF)
{
res = append(res, ch);
}
fclose(fp);
int i = 0;
while (i < strlen(res))
{
if (res[i] >= 97 && res[i] <= 122)
res[i] = res[i] - 32;
i++;
}
printf("%s\n", res);
return 0;
}
here is a quick example
read the file char by char and add each char in a char *. Then for each character lowercase char, sub 32 to get the uppercase char and write it then print. Give the filename as first parameter when you start the programm

What is the cause of my segment fault in C?

When I compile my code, I get no errors. However, when I attempt to run it, I get a segmentation fault (core dumped). Here is my main:
Original code
void main(int argc, char *argv[]){
if(argc < 3){
return;
}
char *stop_list_name = argv[1];
char *doc_names[argc - 2];
int i;
for(i = 0; i < argc; i++){
doc_names[i] = argv[i];
}
//create the array of stop words
char *stopWords[50];
char *word;
int word_counter = 0;
FILE *fp;
fp = fopen(stop_list_name, "r");
if(fp != NULL){
while(!feof(fp)){
fscanf(fp, "%s", word);
stopWords[word_counter] = word;
word_counter++;
}
}
fclose(fp);
for(i = 0; stopWords[i] != '\0'; i++){
printf("%s", stopWords[i]);
}
}
I'm pretty sure something is wrong in my while loop, but I don't exactly know what, or how to fix it.
Amended code
After seeing the answers, I modified my code so it looks like this, but it still crashes. What's wrong now?
int main(int argc, char *argv[]){
if(argc < 3){
return;
}
char *stop_list_name = argv[1];
char *doc_names[argc - 2];
int i;
for(i = 2; i < argc; i++){
doc_names[i-2] = argv[i];
}
//create the array of stop words
enum {MAX_STOP_WORDS = 50};
char *stopWords[MAX_STOP_WORDS];
int word_counter = 0;
FILE *fp = fopen(stop_list_name, "r");
if(fp != NULL){
char word[64];
int i;
for(i = 0; i < MAX_STOP_WORDS && fscanf(fp, "%63s", word) == 1; i++){
stopWords[i] = strdup(word);
}
word_counter = i;
fclose(fp);
}
for(i = 0; stopWords[i] != '\0'; i++){
printf("%s", stopWords[i]);
}
}
Problems in the original code
One possible source of problems is:
char *doc_names[argc - 2];
int i;
for(i = 0; i < argc; i++){
doc_names[i] = argv[i];
}
You allocate space for argc-2 pointers and proceed to copy argc pointers into that space. That's a buffer overflow (in this case, a stack overflow too). It can easily cause the trouble. A plausible fix is:
for (i = 2; i < argv; i++)
doc_names[i-2] = argv[i];
However, you really don't need to copy the argument list; you can just process the arguments from index 2 to the end. I note that the code shown doesn't actually use doc_names, but the out-of-bounds assignment can still cause trouble.
You are not allocating space to read a word into, nor allocating new space for each stop word, nor do you ensure that you do not overflow the bounds of the array in which you're storing the words.
Consider using:
enum { MAX_STOP_WORDS = 50 };
char *stopWords[MAX_STOP_WORDS];
int word_counter = 0;
FILE *fp = fopen(stop_list_name, "r");
if (fp != NULL)
{
char word[64];
for (i = 0; i < MAX_STOP_WORDS && fscanf(fp, "%63s", word) == 1; i++)
stopWords[i] = strdup(word);
word_counter = i;
fclose(fp);
}
This diagnosed problem is definitely a plausible cause of your crash. I used i (declared earlier in the code) in the loop because word_counter makes the loop control line too long for SO.
Strictly, strdup() is not a part of standard C, but it is a part of POSIX. If you don't have POSIX, you can write your own:
#include <stdlib.h>
#include <string.h>
char *strdup(const char *str)
{
size_t len = strlen(str) + 1;
char *result = malloc(len);
if (result != 0)
memmove(result, str, len);
return result;
}
You also have some other bad practices on display:
while (!feof(file)) is always wrong.
What should main() return in C and C++?
You should only call fclose(fp) if the fopen() worked, so you need to move the fclose() inside the if statement body.
Problems in the amended code
There's one important and a couple of very minor problems in the amended code:
Your loop that prints the stop words depends on a null pointer (curiously spelled as '\0' — it is a valid but unconventional spelling for a null pointer), but the initialization code doesn't set a null pointer.
There are (at least) two options for fixing that:
Add a null pointer:
for (i = 0; i < MAX_STOP_WORDS-1 && fscanf(fp, "%63s", word) == 1; i++)
stopWords[i] = strdup(word);
stopWords[i] = 0;
fclose(fp);
}
for (i = 0; stopWords[i] != '\0'; i++)
printf("%s\n", stopWords[i]);
Note that the upper bound is now MAX_STOP_WORDS - 1.
Or you can use wordCount instead of a condition:
for (i = 0; i < wordCount; i++)
printf("%s\n", stopWords[i]);
I'd choose the second option.
One reason for doing that is it avoids warnings about wordCount being set and not used — a minor problem.
And doc_names is also set but not used.
I worry about those because my default compiler options generate errors for unused variables — so the code doesn't compile until I fix it. That leads to:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
if (argc < 3)
{
fprintf(stderr, "Usage: %s stop-words docfile ...\n", argv[0]);
return 1;
}
char *stop_list_name = argv[1];
char *doc_names[argc - 2];
int i;
for (i = 2; i < argc; i++)
{
doc_names[i - 2] = argv[i];
}
int doc_count = argc - 2;
// create the array of stop words
enum { MAX_STOP_WORDS = 50 };
char *stopWords[MAX_STOP_WORDS];
int word_counter = 0;
FILE *fp = fopen(stop_list_name, "r");
if (fp != NULL)
{
char word[64];
int i;
for (i = 0; i < MAX_STOP_WORDS && fscanf(fp, "%63s", word) == 1; i++)
stopWords[i] = strdup(word);
word_counter = i;
fclose(fp);
}
for (i = 0; i < word_counter; i++)
printf("stop word %d: %s\n", i, stopWords[i]);
for (i = 0; i < doc_count; i++)
printf("document %d: %s\n", i, doc_names[i]);
return 0;
}
And, given a stop words file containing:
help
able
may
can
it
should
do
antonym
prozac
and compiling it (source file sw19.c, program sw19) with:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
> -Wold-style-definition -Werror sw19.c -o sw19
and running it as:
$ ./sw19 stopwords /dev/null
stop word 0: help
stop word 1: able
stop word 2: may
stop word 3: can
stop word 4: it
stop word 5: should
stop word 6: do
stop word 7: antonym
stop word 8: prozac
document 0: /dev/null
$
You are trying to store the scanned string to an uninitialized pointer,
fscanf(fp, "%s", word);
and word, is not even initialized.
You could use a static buffer for that, just like this
char word[100];
if (fscanf(fp, "%99s", word) != 1)
word[0] = '\0'; /* ensure that `word' is nul terminated on input error */
Also, while (!feof(fp)) is wrong, because the EOF marker wont be set until fscanf() attempts to read past the end of the file, so the code will iterate one extra time. And in that case you would store the same word twice.
Note that you will also need to allocate space for the array of pointers, maybe there you could use malloc().

Resources