I tried to make a program that tells you how many words, lines and characters are in a text file, but the function fopen() fails to open the file. I tried both absolute and relative paths to the text file but I get the same output. Can you please tell me what's wrong?
My compiler is gcc version 4.6.3 (Linux)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 256
void tokenize(const char *filename)
{
FILE *f=NULL;
char line[N],*p;
unsigned long int ch=0,wd=0,ln=0;
int t;
f=fopen(filename,"rt");
if(f==NULL)
{
perror("The following error occurred");
exit(1);
}
fgets(line,N,f);
while(!feof(f))
{
ln++;
p=strtok(line," ");
while(p!=NULL)
{
wd++;
t=strlen(p);
ch+=t;
printf("Word number %lu with length %d: %s\n",wd,t,p);
p=strtok(NULL," ");
}
fgets(line,N,f);
}
printf("%lu lines, %lu words, %lu characters\n",ln,wd,ch);
fclose(f);
}
int main(void)
{
char filename[80];
size_t slen;
printf("Enter filename path:\n");
fgets(filename,80,stdin);
slen = strlen (filename);
if ((slen > 0) && (filename[slen-1] == '\n'))
filename[slen-1] = '\0';
printf("You have entered the following path: %s\n",filename);
tokenize(filename);
return 0;
}
output:
Enter filename path:
input.txt
You have entered the following path: input.txt
The following error occurred: No such file or directory
You've retained the newline character from the input in your filename. You can see this when you echo the filename in your output: notice the blank line.
You'll need to strip off this newline before you pass it to your function. There are a few ways to do this, here's one:
size_t idx = strlen(filename);
if ((idx > 0) && filename[idx - 1] == '\n')
filename[idx - 1] = '\0';
You need to remove the trailing newline character from your string, with something like:
size_t slen = strlen (filename);
if ((slen > 0) && (filename[slen-1] == '\n'))
filename[slen-1] = '\0';
And, while I applaud your use of fgets for user input (since it can be protected from buffer overflow), there's still a couple of edge cases you haven't considered, such as when the line is too long, or the user flags end of input). See here for a more robust solution.
You can declare a function like:
void rmnewline(char *s)
{
int l=strlen(s);
if(l>0 && s[l-1]=='\n')
s[l-1]='\0';
}
and call it before using your char array.
Related
I am attempting to store multiple strings from stdin into a temporary variable.
Each string will be entered following a new line character.
This is my attempt:
#include <stdio.h>
int main() {
for (int i=0; i<10; i++) {
char string;
scanf("%s\n", &string);
printf("%d\n", i);
}
}
The for loop does not run as intended, it only loops twice, seems scanf is interfering with the loop.
stdin:
test
test
stdout:
7631717
Is there a way to store input/each line from stdin dynamically into a char variable without a fixed size/length?
to not be limited to a given size reading a string you can use the modifier 'm' :
char * p;
if (scanf("%ms", &p) == 1) {
...use p;
free(p); /* when stop to be usefull
}
From the man of scanf :
An optional 'm' character. This is used with string conversions (%s, %c, %[), and
relieves the caller of the need to allocate a corresponding buffer to hold the
input: instead, scanf() allocates a buffer of sufficient size, and assigns the
address of this buffer to the corresponding pointer argument, which should be a
pointer to a char * variable (this variable does not need to be initialized before
the call). The caller should subsequently free(3) this buffer when it is no longer
required.
The previous way allows to red a 'word', to read a full line removing spaces (' ', newline, tab ...) at the beginning:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char * p;
if (scanf(" %m[^\n]", &p) == 1) {
printf("'%s'\n", p);
free(p);
}
else
puts("error (EOF...)");
return 0;
}
Compilation and execution:
/tmp % gcc -Wall c.c
/tmp % ./a.out
aze qsd
'aze qsd'
/tmp % ./a.out < /dev/null
error (EOF...)
/tmp %
If you do not have that modifier (not posix ...) to read a full line as it is you can do :
#include <stdio.h>
#include <stdlib.h>
int main()
{
char * p = malloc(1);
size_t len = 0;
int c;
while (((c = getchar()) != '\n') && (c != EOF)) {
p = realloc(p, len+1);
if (p == NULL) {
puts("not enough memory");
return -1;
}
p[len++] = c;
}
p[len] = 0;
printf("'%s'\n", p);
free(p);
return 0;
}
Compilation and execution :
/tmp % gcc -Wall c.c
/tmp % ./a.out
aze qsd
' aze qsd'
/tmp % ./a.out < /dev/null
''
/tmp %
char string; is not a string but a single character. Reading in a string with format %s into a single character is undefined behaviour as soon as you enter at least one character. This is because the string termination character will be appended, too.
Write ...
char string[100];
scanf("%99s", string);
and everything should be fine.
BTW: If you intend to read in complete lines (including white spaces at the beginning, in between and at the end), consider using fgets instead of scanf.
Is there a way to store input/each line from stdin dynamically into a char variable without a fixed size/length?
If willing to going the POSIX route, use getline() to "store input/each line from stdin dynamically".
Lop off the potential trailing new-line if desired
char *line = NULL;
size_t len = 0;
ssize_t nread;
while ((nread = getline(&line, &len, stdin)) != -1) {
if (nread > 0 && line[nread-1] == '\n') line[--nread] = 0;
printf("Retrieved line of length %zu: <%s>\n", nread, line);
}
free(line);
I suspect nread > 0 && line[nread-1] == '\n' can be reduced to line[nread-1] == '\n' as I see not case where nread returns 0.
I'm a student, I am wondering...
How can I make a program that can Get some data from my text file to a variable on my program and print them
Example:
My Text File
I,Ate,Cookies
She,Drink,Coffee
Tom,Wears,Pyjamas
My code
main()
{
FILE *fp=fileopen("c:\\textfile.txt","r");
char name[20],action[20],item[20];
prinf("Enter name: \n");
scanf("%s",&name);
/* I dont Know what to do next */
}
I though about some checking code:
if (name==nametxt) /*nametxt is the first line on the text file */
{
printf("%s\n %s\n %s\n",name,action,item);
}
If the name is "I",the output would look like this :
Enter name:
I
I
Eat
Cookies
A help will satisfy my curiosity thanks in advance
You are reading characters from file until you receive new line character (\n) or fill an array, then you return characters stored in an array passed by caller.
From this returned array you may get separated values with strtok.
Repeat until you receive 0 from getline (Getline received EOF from file.)
Here is simple example with your own getline function which you may modify.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int getline(char s[],int lim, FILE * fp)
{
int c, i;
for (i=0; i < lim-1 && (c=fgetc(fp))!=EOF && c!='\n'; ++i)
{
s[i] = c;
}
if (c == '\n')
{
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
int main()
{
FILE * fp = fopen("c:\\textfile.txt", "r");
char line[100];
char * ptr;
while (getline(line, 100, fp))
{
ptr = strtok(line, ",");
while( ptr != NULL )
{
printf(" %s\n", ptr);
ptr = strtok(NULL, ",");
}
}
return 0;
}
Output
I
Ate
Cookies
She
Drink
Coffee
Tom
Wears
Pyjamas
Storing strings into variable isnt tough, here is an example
strcpy(name, ptr);
But be careful, writing outside of bounds have undefined behavior.
strncpy(name, ptr, 100); You can limit number of copied characters with strncpy, but be careful, this function is error-prone.
You can do like this,
Go on reading characters from a file, after every character is read compare with ',' character.
If the character read is ',' then you have finished reading the name, otherwise store it in a character array and continue reading the file.
Once you hit ',' character, terminate the character array with null character(Now you have a complete name with you).
Compare this character array with a string you receive as input using a strcmp(String compare function). If its it matches decide what you wanna do?
I hope i am clear.
There is different ways to read data from a FILE * in C :
You read only one character : int fgetc(FILE *fp);.
You read a whole line : char *fgets(char *buf, int n, FILE *fp); (take care to buf, it must point to allocate memory).
You read a formatted string, which is your case here : int fscanf(FILE *stream, const char *format, ...), it works like printf() :
This way :
char name[20], action[20], item[20];
FILE *f = fopen("myfile.txt", "r");
if (! f)
return;
if (3 == fscanf(f, "%19[^,\n],%19[^,\n],%19[^,\n]\n", name, action, item))
printf("%s %s %s\n", name, action, item)
%30[^,\n], here is used to read of whole object of your line, except , or \n, which will read item by item the content of your string.
start with like this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DATA_FILE "data.txt"
#define LEN 19
#define SIZE (LEN+1)
//Stringification
#define S_(n) #n
#define S(n) S_(n)
enum { NOT_FOUND, FIND };
int pull_data(const char name[SIZE], char action[SIZE], char item[SIZE]){
int ret = NOT_FOUND;
FILE *fp = fopen(DATA_FILE, "r");//fileopen --> fopen
if(fp == NULL){
perror("fopen:");
exit(EXIT_FAILURE);
} else {
char nametxt[SIZE];
*action = *item = 0;
while(fscanf(fp, "%" S(LEN) "[^,],%" S(LEN) "[^,],%" S(LEN) "[^\n]%*c", //"%19[^,],%19[^,],%19[^\n]%*c"
nametxt, action, item) == 3){
if(strcmp(name, nametxt) == 0){//Use strcmp for comparison of strings
ret = FIND;
break;
}
}
}
fclose(fp);
return ret;
}
int main(void){
char name[SIZE], action[SIZE], item[SIZE];
printf("Enter name: \n");//prinf --> printf
if(scanf("%" S(LEN) "s", name) == 1){
if(pull_data(name, action, item) == FIND){
printf("%s\n%s\n%s\n", name, action, item);
} else {
printf("%s not found.\n", name);
}
}
}
Hi i am new to C and i am trying to use the Character array type below to captures input from users. How do i prevent or escape numerical characters. I just want only strings to be captured.
char str_input[105];
In have tried
scanf("%[^\n]s",str_input);
scanf("%[^\n]",str_input);
scanf("%[^0-9]",str_input);
scanf("%[A-Zaz-z]",str_input);
str_input = fgetc(stdin);
None of the above worked for me.
Input
2
hacker
Expected Output
Hce akr
int main() {
char *str_input;
size_t bufsize = 108;
size_t characters;
str_input = (char *)malloc(bufsize * sizeof(char));
if (str_input == NULL)
{
perror("Unable to allocate buffer");
exit(1);
}
characters = getline(&str_input,&bufsize,stdin);
printf("%zu characters were read.\n",characters);
int i;
int len = 0;
for (i = 0, len = strlen(str_input); i<=len; i++) {
i%2==0? printf("%c",str_input[i]): 'b';
}
printf(" ");
for (i = 0, len = strlen(str_input); i<=len; i++) {
i%2!=0? printf("%c",str_input[i]): 'b';
}
return 0;
}
Error
solution.c: In function ‘main’:
solution.c:21:5: warning: implicit declaration of function ‘getline’ [-Wimplicit-function-declaration]
characters = getline(&str_input,&bufsize,stdin);
Since your buffer has limited size, then using fgets(3) is fine. fgets() returns NULL on failure to read a line, and appends a newline character at the end of the buffer.
In terms of preventing numerical characters from being in your buffer, you can simply create another buffer, and only add non-numerical characters to it. You could just delete the numerical characters from your original buffer, but this can be a tedious procedure if you are still grasping the basics of C. Another method would be just to read single character input with getchar(3), which would allow you assess each character and simply ignore numbers. THis method is by far the easiest to implement.
Since you asked for an example of using fgets(), here is some example code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define INPUTSIZE 108
int main(void) {
char str_input[INPUTSIZE], characters[INPUTSIZE];
size_t slen, char_count = 0;
printf("Enter input:\n");
if (fgets(str_input, INPUTSIZE, stdin) != NULL) {
/* removing newline from fgets() */
slen = strlen(str_input);
if (slen > 0 && str_input[slen-1] == '\n') {
str_input[slen-1] = '\0';
} else {
fprintf(stderr, "Number of characters entered exceeds buffer size\n");
exit(EXIT_FAILURE);
}
/* checking if string is valid */
if (*str_input == '\0') {
fprintf(stderr, "No input found\n");
exit(EXIT_FAILURE);
}
printf("Buffer: %s\n", str_input);
/* only adding non-numbers */
for (size_t i = 0; str_input[i] != '\0'; i++) {
if (!isdigit(str_input[i])) {
characters[char_count++] = str_input[i];
}
}
/* terminating buffer */
characters[char_count] = '\0';
printf("New buffer without numbers: %s\n", characters);
}
return 0;
}
Example input:
Enter input:
2ttt4y24t4t3t2g
Output:
Buffer: 2ttt4y24t4t3t2g
New buffer without numbers: tttytttg
Update:
You could just use this even simpler approach of ignoring non-number characters:
char str_input[INPUTSIZE];
int ch;
size_t char_count = 0;
while ((ch = getchar()) != EOF && ch != '\n') {
if (!isdigit(ch)) {
if (char_count < sizeof(str_input)) {
str_input[char_count++] = ch;
}
}
}
str_input[char_count] = '\0';
If you're using Linux, I would use the getline() function to get a whole line of text, then verify it. If it is not valid input, I would in a loop ask the user to enter a line of text again and again until you the input is acceptable.
If not using Linux, well, your best bet is probably to reimplement getline(). You can also use fgets() if you find a limited-size buffer acceptable. I don't find limited-size buffers acceptable, so that's why I prefer getline().
getline() is used according to the way explained in its man page: http://man7.org/linux/man-pages/man3/getdelim.3.html
Basically, your loop should be something similar to:
char *buf = NULL;
size_t bufsiz = 0;
while (1)
{
if (getline(&buf, &bufsiz, stdin) < 0)
{
handle_error();
}
if (is_valid(buf))
{
break;
}
printf("Error, please re-enter input\n");
}
use_buffer(buf);
free(buf);
Well that's not possible. Numbers are string too. But you can set loop to look for numbers and print error. like this :
char *str = "ab234cid20kd", *p = str;
while (*p) { // While there are more characters to process...
if (isdigit(*p)) { // Upon finding a digit, ...
printf("Numbers are forbidden");
return 0;
} else {
p++;
}
}
I am a beginner coder and writing a code that
asks for the user's name
check if the length is >15, if it is, it will ask the user to input a shorter name when they restart the program
if the length is valid, upper case the first letter of the entered name
display something like "Hi name"
However, The program keeps exiting no matter what I enter. Here is what I did :
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <conio.h>
int main(void)
{
char str_name[15];
printf("Please enter your first name to begin: ");
scanf_s("%14s", str_name, _countof(str_name));
getchar();
if (strlen(str_name) > 15)
{
printf("The entered name is too long, please restart the program and try again.");
getchar();
exit(0);
}
else
{
str_name[0] = toupper(str_name[0]);
printf("Hi %s.\n", str_name);
getchar();
}
return 0;
}
You can simply use fgets() to read an input buffer.
char *fgets(char *str, int n, FILE *stream) reads a line from the specified stream and stores it in a buffer pointed to by str. It stops when either n-1 characters are read, the newline character is read, or the EOF is reached.
Some things to note about fgets():
Returns NULL on error.
Appends \n character at the end of buffer. Can replaced with \0 instead.
Buffer must be pointer to an array of characters. Either allocated on the stack or the heap.
Reads from stdin or FILE objects.
Here is some example code which shows this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define NAMESTRLEN 16
int main(void) {
char str_name[NAMESTRLEN] = {'\0'};
size_t slen;
printf("Please enter your first name to begin: ");
if (fgets(str_name, NAMESTRLEN, stdin) == NULL) {
fprintf( stderr, "Error from fgets()\n");
return 1;
}
slen = strlen(str_name);
if (slen > 0 && str_name[slen-1] == '\n') {
str_name[slen-1] = '\0';
} else {
fprintf( stderr, "Too many characters\n");
return 1;
}
if (str_name[0] == '\0') {
fprintf( stderr, "No name entered\n");
return 1;
}
str_name[0] = toupper((unsigned char)str_name[0]);
printf("Hi %s.\n", str_name);
return 0;
}
There are several issues in your code:
The buffer size is too short: scanf() will not read more than 14 bytes into str_name, so it is not possible to test if the user entered a name longer than 15 characters.
toupper() should not be given a char argument because it is only defined for values of type unsigned char and the special value EOF. Cast the char as unsigned char.
your attempt at pausing before the terminal window closes fails on windows for long names because the extra characters entered by the user are still pending after the scanf_s(). getchar() reads one and returns immediately, and the program exits and the terminal window closes. Open the terminal window and run the program manually so it does not close automatically. With this approach, you can remove the getchar() and make the program more portable.
Here is a corrected version:
#include <ctype.h>
#include <stdio.h>
int main(void) {
char str_name[17];
printf("Please enter your first name to begin: ");
if (scanf_s("%16s", str_name, sizeof(str_name))) {
printf("Premature end of file.\n");
return 1;
}
if (strlen(str_name) > 15) {
printf("The entered name is too long, please restart the program and try again.");
return 1;
}
str_name[0] = toupper((unsigned char)str_name[0]);
printf("Hi %s\n", str_name);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
char str_name[16] = {0};
size_t len = 0;
int ch;
printf("Please enter your first name to begin: ");
while ((EOF != (ch = fgetc(stdin))) && (ch != '\n') && (len<sizeof(str_name)))
{
if (isalpha(ch))
{
str_name[len++] = ch;
}
}
if (len==sizeof(str_name))
{
fprintf(stderr, "Name too long\n");
}
else
{
str_name[len] = '\0';
printf ("Hi %c%s.\n", toupper(str_name[0]), &str_name[1]);
}
return 0;
}
As you can see I changed the input grabbing function. To check the input str len you should read byte per byte, not a whole string: fgetc do it. Using scanf with a format specifier like %14s it will return you always a trimmed string and you are not able to warn user about a too long Name.
Another point is to check that inserted chars are letters and not other kind of chars: isalpha do the job.
Moreover a c-string is composed by chars plus a null terminator ('\0', 0x00 ), so: a 15 chars string wants a 16 bytes array.
Lastly the code you wrote to mahe the first letter uppercase is completely wrong: you are passing to print a 1 char array and not a c string. My solution is one of many.
The problem is:
char Name[1]; // Declare a single element array.
Name[0] = toupper(str_name[0]); // Set it to the upper-case first letter.
// Try and print the nul-terminated string in Name - but there is no
// trailing zero (and the rest of the name is missing).
printf("Hi %s.\n", Name);
What you need is:
str_name[0] = toupper(str_name[0]);
printf("Hi %s.\n", str_name);
There is another problem that str_name[0] is a char value, and char may be signed. If you are using Windows-1252 for example, then Ä is 196, or as a signed char, -60. toupper takes an int, which must be positive¹. When -60 as a signed char is converted to int, you will get -60, and an out of range error. You need to write this as:
str_name[0] = toupper((unsigned char)str_name[0]);
printf("Hi %s.\n", str_name);
(Sorry.)
¹ Chrqlie points out the requirement is actually that the argument must be one of the values of unsigned char (which are - by definition - non-negative) or EOF (which is negative)"
I wanted to only count the number of strings in a text file, containing numbers as well. But the code below, counts even the numbers in the file as strings. How do I rectify the problem?
int count;
char *temp;
FILE *fp;
fp = fopen("multiplexyz.txt" ,"r" );
while(fscanf(fp,"%s",temp) != EOF )
{
count++;
}
printf("%d ",count);
return 0;
}
Well, first up, using the temp pointer without having backing storage for it is going to cause you a world of pain.
I'd suggest, as a start, using something like char temp[1000] instead, keeping in mind that's still a bit risky if you have words more than a thousand or so characters long (that's a different issue to the one you're asking about so I'll mention it but not spend too much time on fixing it).
Secondly, it appears you want to count words with numbers (like alpha7 or pi/2). If that's the case, you simply need to check temp after reading the "word" and increment count only if it matches a "non-numeric" pattern.
That could be as simple as just not incrementing if the word consists only of digits, or it could be complicated if you want to handle decimals, exponential formats and so on.
But the bottom line remains the same:
while(fscanf(fp,"%s",temp) != EOF )
{
if (! isANumber(temp))
count++;
}
with a suitable definition of isANumber. For example, for unsigned integers only, something like this would be a good start:
int isANumber (char *str) {
// Empty string is not a number.
if (*str == '\0')
return 0;
// Check every character.
while (*str != '\0') {
// If non-digit, it's not a number.
if (! isdigit (*str))
return 0;
str++;
}
// If all characters were digits, it was a number.
return 1;
}
For more complex checking, you can use the strto* calls in C, giving them the temp buffer and ensuring you use the endptr method to ensure the entire string is scanned. Off the top of my head, so not well tested, that would go something like:
int isANumber (char *str) {
// Empty string is not a number.
if (*str == '\0')
return 0;
// Use strtod to get a double.
char *endPtr;
long double d = strtold (str, &endPtr);
// Characters unconsumed, not number (things like 42b).
if (*endPtr != '\0')
return 0;
// Was a long double, so number.
return 1;
}
The only thing you need to watch out for there is that certain strings like NaN or +Inf are considered a number by strtold so you may need extra checks for that.
inside your while loop, loop through the string to check if any of its characters are digits. Something like:
while(*temp != '\0'){
if(isnumber(*temp))
break;
}
[dont copy exact same code]
I find strpbrk to be one of the most helpful function to search for several needles in a haystack. Your set of needles being the numeric characters "0123456789" which if present in a line read from your file will count as a line. I also prefer POSIX getline for a line count do to its proper handling of files with non-POSIX line endings for the last line (both fgets and wc -l omit text (and a count) of the last line if it does not contain a POSIX line end ('\n'). That said, a small function that searches a line for characters contained in a trm passed as a parameter could be written as:
/** open and read each line in 'fn' returning the number of lines
* continaing any of the characters in 'trm'.
*/
size_t nlines (char *fn, char *trm)
{
if (!fn) return 0;
size_t lines = 0, n = 0;
char *buf = NULL;
FILE *fp = fopen (fn, "r");
if (!fp) return 0;
while (getline (&buf, &n, fp) != -1)
if (strpbrk (buf, trm))
lines++;
fclose (fp);
free (buf);
return lines;
}
Simply pass the filename of interest and the terms to search for in each line. A short test code with a default term of "0123456789" that takes the filename as the first parameter and the term as the second could be written as follows:
#include <stdio.h> /* printf */
#include <stdlib.h> /* free */
#include <string.h> /* strlen, strrchr */
size_t nlines (char *fn, char *trm);
int main (int argc, char **argv) {
char *fn = argc > 1 ? argv[1] : NULL;
char *srch = argc > 2 ? argv[2] : "0123456789";
if (!fn) return 1;
printf ("%zu %s\n", nlines (fn, srch), fn);
return 0;
}
/** open and read each line in 'fn' returning the number of lines
* continaing any of the characters in 'trm'.
*/
size_t nlines (char *fn, char *trm)
{
if (!fn) return 0;
size_t lines = 0, n = 0;
char *buf = NULL;
FILE *fp = fopen (fn, "r");
if (!fp) return 0;
while (getline (&buf, &n, fp) != -1)
if (strpbrk (buf, trm))
lines++;
fclose (fp);
free (buf);
return lines;
}
Give it a try and see if this is what you are expecting, if not, just let me know and I am glad to help further.
Example Input File
$ cat dat/linewno.txt
The quick brown fox
jumps over 3 lazy dogs
who sleep in the sun
with a temp of 101
Example Use/Output
$ ./bin/getline_nlines_nums dat/linewno.txt
2 dat/linewno.txt
$ wc -l dat/linewno.txt
4 dat/linewno.txt