I need a simple function that can read multiple words into a string in C, kind of like Scanner.nextLine() in Java or Console.ReadLine() in C#, but I can't seem to find a simple method anywhere, I tried all sorts of things, but none of them seem to work 100% of the time.
You can use fgets
char *fgets(char *str, int n, FILE *stream)
Be aware that fgets reads until reach the size n, or a newline or an EOF.
This is made to avoid buffer overflow, so you need to make sure that your buffer is big enough to store the string.
scanf is what you want:
#include <stdio.h>
int main(void)
{
char string[50];
scanf(" %49[^\n]s",string);
printf("you entered: %s\n",string);
}
you can follow this:
char str[100];// as length of the total words neded
fgets(str,100,stdin)
printf("output: %s",str);
return 0;
Use fgets to parse an input string into a char buffer.
char * fgets ( char * str, int num, FILE * stream );
Here is the link for a better description
Then use sscanf to dissect this string to however you need it.
int sscanf ( const char * s, const char * format, ...);
Here is the link for a better description
This removes the '\n' character that is included in the string returned by fgets, thus making the function practically equivalent to the functions present in popular managed languages:
//gets a line from the specified stream
int getline(char* charArray, int maxLength, FILE* stream) {
int i;
if (fgets(charArray, maxLength, stream) == NULL)
return 1; //some error occurred
for (i = 0; i < maxLength; i++) {
if (charArray[i] == '\n') {
if (i != 0 && charArray[i - 1] == '\r') //cater for windows line endings
i--;
charArray[i] = '\0';
return 0; //all's well that ends well
} else if (charArray[i] == '\0')
return 0; //smooth sailing fam
}
return 2; //there was no string terminator
}
Here you go:
#include "stdio.h"
//gets a line from the specified stream
int getline(char* charArray, int maxLength, FILE* stream) {
int i;
if (fgets(charArray, maxLength, stream) == NULL)
return 1; //some error occurred
for (i = 0; i < maxLength; i++) {
if (charArray[i] == '\n') {
if (i != 0 && charArray[i - 1] == '\r') //cater for windows line endings
i--;
charArray[i] = '\0';
return 0; //all's well that ends well
} else if (charArray[i] == '\0')
return 0; //smooth sailing fam
}
return 2; //there was no string terminator
}
int main() {
char money[4];
printf("How much money do you have on you? ");
getline(money, 4, stdin);
printf("Oh really? $%d? Good. :)\n", atoi(money));
char string[4];
printf("Where is our next lesson?\n");
getline(string, 4, stdin);
printf("%s", string);
return 0;
}
Related
I want to create a program in C that takes an arbitrary number of lines of arbitrary length as input and then prints to console the last line that was inputted. For example:
input:
hi
my name is
david
output: david
I figured the best way to do this would be to have a loop that takes each line as input and stores it in a char array, so at the end of the loop the last line ends up being what is stored in the char array and we can just print that.
I have only had one lecture in C so far so I think I just keep setting things up wrong with my Java/C++ mindset since I have more experience in those languages.
Here is what I have so far but I know that it's nowhere near correct:
#include <stdio.h>
int main()
{
printf("Enter some lines of strings: \n");
char line[50];
for(int i = 0; i < 10; i++){
line = getline(); //I know this is inproper syntax but I want to do something like this
}
printf("%s",line);
}
I also have i < 10 in the loop because I don't know how to find the total number of lines in the input which, would be the proper amount of times to loop this. Also, the input is being put in all at once from the
./program < test.txt
command in Unix shell, where test.txt has the input.
Use fgets():
while (fgets(line, sizeof line, stdin)) {
// don't need to do anything here
}
printf("%s", line);
You don't need a limit on the number of iterations. At the end of the file, fgets() returns NULL and doesn't modify the buffer, so line will still hold the last line that was read.
I'm assuming you know the maximum length of the input line.
This one here will surely do the job for you
static char *getLine( char * const b , size_t bsz ) {
return fgets(b, bsz, stdin) );
}
But remember fgets also puts a '\n' character at the end of buffer so perhaps something like this
static char *getLine( char * const b , size_t bsz ) {
if( fgets(b, bsz, stdin) ){
/* Optional code to strip NextLine */
size_t size = strlen(b);
if( size > 0 && b[size-1] == '\n' ) {
b[--size] = '\0';
}
/* End of Optional Code */
return b;
}
return NULL;
}
and your code needs to be altered a bit while calling the getline
#define BUF_SIZE 256
char line[BUF_SIZE];
for(int i = 0; i < 10; i++){
if( getLine(line, BUF_SIZE ) ) {
fprintf(stdout, "line : '%s'\n", line);
}
}
Now it is how ever quite possible to create function like
char *getLine();
but then one needs to define the behavior of that function for instance if the function getLine() allocates memory dynamically then you probably need use a free to de-allocate the pointer returned by getLine()
in which case the function may look like
char *getLine( size_t bsz ) {
char *b = malloc( bsz );
if( b && fgets(b, bsz, stdin) ){
return b;
}
return NULL;
}
depending on how small your function is you can entertain thoughts about making it inline perhaps that's a little off topic for now.
In order to have dynamic number of input of dynamic length, you have to keep on reallocating your buffer when the input is of greater length. In order to store the last line, you have to take another pointer to keep track of it and to stop the input from the terminal you have to press EOF key(ctrl+k). This should do your job.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *get_last_line(FILE* fp, size_t size){
//The size is extended by the input with the value of the provisional
char *str, *last_str = NULL;
int ch;
size_t len = 0, last_len = 0;
str = realloc(NULL, sizeof(char)*size);//size is start size
if(!str)return str;
while(ch=fgetc(fp)){
if(ch == EOF){
break;
}
if(ch == '\n'){
str[len]='\0';
last_len = len;
last_str = realloc(last_str,sizeof(char)*last_len);
last_str[last_len]='\0';
//storing the last line
memcpy(last_str,str,sizeof(char)*last_len);
str = realloc(NULL, sizeof(char)*size);//size is start size
len = 0;
}
else {
str[len++]=ch;
if(len==size){
str = realloc(str, sizeof(char)*(size+=16));
if(!str)return str;
}
}
}
free(str);
return last_str;
}
int main(void){
char *m;
printf("input strings : ");
m = get_last_line(stdin, 10);
printf("last string :");
printf("%s\n", m);
free(m);
return 0;
}
I had to rewrite two functions as per two exercises in a book I'm working from. One that simply reads a line of characters, readLine and another that compared two character strings and returned either 1 or 0 based on whether they match, 'equalStrings`.
The point of the exercise was to rewrite the functions so they used pointers, as opposed to arrays.
I've been struggling with prior exercises and was surprised how quickly I was able to do this so I'm concerned I'm missing something important.
Both programs compile and run as hoped though.
This is the original readLine function:
#include <stdio.h>
void readLine(char buffer[]);
int main(void)
{
int i;
char line[81];
for(i = 0; i < 3; i++)
{
readLine(line);
printf("%s\n\n", line);
}
return 0;
}
void readLine(char buffer[])
{
char character;
int i = 0;
do
{
character = getchar();
buffer[i] = character;
i++;
}
while(character != '\n');
buffer[i - 1] = '\0';
}
My edited with pointers:
#include <stdio.h>
void readLine(char *buffer);
int main(void)
{
int i;
char line[81];
char *pointer;
pointer = line;
for(i = 0; i < 3; i++)
{
readLine(pointer);
printf("%s\n\n", line);
}
return 0;
}
void readLine(char *buffer)
{
char character;
int i;
i = 0;
do
{
character = getchar();
buffer[i] = character;
i++;
}
while(character != '\n');
buffer[i - 1] = '\0';
}
Here is the original equalString function:
#include <stdio.h>
#include <stdbool.h>
bool equalStrings(const char s1[], const char s2[]);
int main(void)
{
const char stra[] = "string compare test";
const char strb[] = "string";
printf("%i\n", equalStrings(stra, strb));
printf("%i\n", equalStrings(stra, stra));
printf("%i\n", equalStrings(strb, "string"));
return 0;
}
bool equalStrings(const char s1[], const char s2[])
{
int i = 0;
bool areEqual;
while(s1[i] == s2[i] && s1[i] != '\0'){
i++;
if(s1[i] == '\0' && s2[i] == '\0')
areEqual = true;
else
areEqual = false;
}
return areEqual;
}
and the rewritten with pointers:
#include <stdio.h>
#include <stdbool.h>
bool equalStrings(const char *pointera, const char *pointerb);
int main(void)
{
const char stra[] = "string compare test";
const char strb[] = "string";
const char *pointera;
const char *pointerb;
pointera = stra;
pointerb = strb;
printf("%i\n", equalStrings(pointera, pointerb));
printf("%i\n", equalStrings(pointerb, pointerb));
printf("%i\n", equalStrings(strb, "string"));
return 0;
}
bool equalStrings(const char *pointera, const char *pointerb)
{
int i = 0;
bool areEqual;
while(pointera[i] == pointerb[i] && pointera[i] != '\0'){
i++;
if(pointera[i] == '\0' && pointerb[i] == '\0')
areEqual = true;
else
areEqual = false;
}
return areEqual;
}
Is there anything glaring out that needs to be changed?
Thank you.
There are (3) conditions you need to protect against in your readline function. (1) you must protect against writing beyond the end of your array. Utilizing a simple counter to keep track of the number of characters added will suffice. You can express this limit in your read loop. Your array size is 81 (which will hold a string of 80 characters +1 for the nul-terminating character. Assuming you create a #define MAXC 81 for use in your code, your first condition could be written as:
void readline (char *buffer)
{
int i = 0, c;
while (i + 1 < MAXC && ...
(2) the second condition you want to protect against is reaching a '\n' newline character. The second condition for your read loop could be written as:
while (i + 1 < MAXC && (c = getchar()) != '\n' && ...
(3) the third condition you must protect against is encountering EOF with a line before a newline character is reached (many editors produce files with non-POSIX line-endings). With the final condition, your complete set of test conditions could look like the following:
while (i + 1 < MAXC && (c = getchar()) != '\n' && c != EOF)
(and that is why c must be signed (and should be a signed int), because EOF is generally -1)
Putting that together, with what it appears was intended in rewriting the function from using array-index notation to using pointer notation, you could do something like the following:
void readline (char *buffer)
{
int i = 0, c;
while (i + 1 < MAXC && (c = getchar()) != '\n' && c != EOF) {
*buffer++ = c;
i++;
}
*buffer = 0;
if (i + 1 == MAXC && *(buffer - 1) != '\n')
fprintf (stderr, "warning: line truncation occurred.\n");
}
You should also check, as shown above, whether you read all the characters in the line, or whether a short-read occurred (meaning after reading 80 allowable characters, there were still more characters in the line to be read, but to prevent writing beyond the end of your array, and leaving room for the terminating nul, you stopped reading before your reached the newline). You are free to handle it as you like, but be aware -- those characters still exist in the input buffer (stdin here) and will be the very next characters read on your next call to getchar(). So you may want a way to tell if that occurred.
Putting the function together in a short example with a helpful input file will help explain.
#include <stdio.h>
#define MAXC 81
void readline(char *buffer);
int main(void) {
int i;
char line[MAXC] = "", *pointer = line;
for(i = 0; i < 3; i++) {
readline (pointer);
printf ("%s\n\n", line);
}
return 0;
}
void readline (char *buffer)
{
int i = 0, c;
while (i + 1 < MAXC && (c = getchar()) != '\n' && c != EOF) {
*buffer++ = c;
i++;
}
*buffer = 0;
if (i + 1 == MAXC && *(buffer - 1) != '\n')
fprintf (stderr, "warning: line truncation occurred.\n");
}
How will your function behave if given a 90 character line to read?
Input File
Two lines with 90 characters each.
$cat dat/90.txt
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
Example Use/Output
Note what has occurred. On the first read attempt, 80 character were read, and a short read occurred. You were warned of that fact. The second read, read the reamining 10 characters in the first line (chars 81-90). The third, and final, read, again reads the first 80 chars of the second line and the code terminates.
$ ./bin/getchar_ptr <dat/90.txt
warning: line truncation occurred.
12345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890
warning: line truncation occurred.
12345678901234567890123456789012345678901234567890123456789012345678901234567890
I'll let you look this over and incorporate any of the suggestions you find helpul in the rest of your code. Let me know if you have any questions. Make sure you fully undetstand what is being passed as buffer in void readline (char *buffer) (copy as opposed to original) as basic pointer understandin has implications throughout C.
I am working on a program that should remove preceding spaces and tabs from each line of text in a given file (case b). I read the file from stdin, which I got working fine. However I am getting a nasty seg fault that I can't figure out. It happens when I call strcat() in case b. Basically what I was trying to do in case b is iterate through each line (80 characters) in the text file, remove any preceding tabs or spaces from the line, then put these lines back into finalText. Can anyone see where am I going wrong? Or if there might be a simpler approach?
Here's my code:
int main(int argc, char* argv[]) {
int x = 0;
int i = 0;
int j = 0;
int y = 0;
int count = 1;
char *text = malloc(sizeof(char) * 1024);
char *finalText = malloc(sizeof(char) * 1024);
char buff[80];
while(fgets(buff, 80, stdin) != NULL){
strcat(text, buff);
}
while ((x = getopt(argc, argv, "bic:")) != -1){
switch (x){
case 'b':
for(; text[i] != EOF; i += 80){
char buff2[80];
char *buff3;
j = i;
y = 0;
while(j != (80 * count)){
buff2[y] = text[j];
y++;
j++;
}
buff3 = buff2;
while(*buff3 && isspace(*buff3)){
++buff3;
}
count++;
strcat(finalText, buff3);
}
printf(finalText);
break;
default:
break;
}
}
return 0;
}
#include <stdio.h>
int main(){
char buff[80];
int n;
while(fgets(buff, sizeof(buff), stdin)){
sscanf(buff, " %n", &n);
if(n && buff[n-1] == '\n')//only whitespaces line.(nothing first word)
//putchar('\n');//output a newline.
fputs(buff, stdout);//output as itself .
else
fputs(buff + n, stdout);
}
return 0;
}
Firstly before the 'b' case, there is another problem too. You have allocated 1024 byte for text. Each line you read from stdin is concatenated at text string. If the total characters read from stdin exceed 1024 bytes you will receive a segmentation fault.
For your problem at 'b' case:
Why searching for EOF? EOF is not a character and your loop will continue to iterating incrementing i until you receive a segmentation fault. You just want to iterate until the end of the string which can be retrieved with strlen() for example.
I need a program to reverse the order of all strings stored in one or more text files. This is what i've got so far:
#include <stdio.h>
main(int argc, char *argv[])
{
int i;
for (i=1;i < argc;i++)
{
FILE *MyFile=fopen(argv[i], "r");
int i,len;
char str[1000], *ptr;
fgets(str, 1000, MyFile);
ptr = str;
for(i=0;i<1000;i++)
{
if(*ptr == '\0') break;
ptr++;
}
len = i;
ptr--;
for(i=len; i>0; i--)
{
printf("%c",*ptr--);
}
printf("\n");
fclose (MyFile);
}
return 0;
}
What i'm not being able to do is to loop the program correctly so that it reverses all strings. Currently it reverses the first string of all files, but when it encounters a line break the fgets stops. What i've tried to do is to count the lines in the current file, do a for loop, and at the end do another fgets(str, 1000, MyFile); to advance the fgets, but I somehow manage to mess things up.
Another option I thought of is to create a separate function which only reverses a given string, and inside the main function call that function the appropriate number of times, but i'm not sure how to handle the argc and *argv[] in this situation.
Any help? Thanks!
You are clobbering the i variable for the outer loop with another one declared inside. This is most probably why it doesn't work.
You should use strlen() function to get the string length instead of calculating it manually.
Unless you are guaranteed to have strings of at most 1000 bytes, you should consider using a smarter algorithm to cater for longer strings.
Accumulate each char in a buffer until end-of-string (\0) detected. Then print it in reverse.
printf_reverse(const char *buf, size_t len) {
while (len > 0) {
fputc(buf[--len], stdout);
}
}
char buf[1000];
size_t len = 0;
int ch;
while ((ch == fgetc(MyFile)) != EOF) {
if (ch == '\0') {
printf_reverse(buf, len);
len = 0;
}
// You may want not use EOL as part of the reverse
else if (ch == '\n') {
printf_reverse(buf, len);
fputc(ch, stdout);
len = 0;
}
else if (len < sizeof(buf)) {
buf[len++] = ch;
}
else {
; // handle error string too long
}
printf_reverse(buf, len);
OP says "ABCD 1234 Should output: DCBA 4321". In C, a string ends with a \0. It is not clear if the source file has embedded \0 or OP also wants to use a space to indicate the end of the string.
I'm new to C, and I'm trying to scan a line from stdin and extract the nth word from it.
Right now I've hard-coded it where you can store the first, second, or third entry in the sentence, and this is what it looks like:
int set_to_nth_word(char* word, char* input, int n)
{
char word1[20];
char word2[20];
char word3[20];
if(sscanf(input, "%s %s %s", word1, word2, word3) < n)
{
printf("You didn't enter enough values\n");
return 0;
}
else
{
if(n == 1) strcpy(word, word1);
else if(n == 2) strcpy(word, word2);
else if(n == 3) strcpy(word, word3);
return 1;
}
}
The code that calls this method is:
char *input = (char *) malloc (1);
if(getline(&input, (size_t)0, stdin) != -1)
{
char word[20];
if(set_to_nth_word(word, input, 1))
{
printf("Success");
}
}
Besides finding a solution to this problem, I'd be happy if anyone points out any bad style or bad coding practices!
You can make use of %n conversion specifier supported by sscanf(). It requires an int * parameter, and returns the number of characters consumed from the input into that int.
int set_to_nth_word(char *word, const char *input, int n)
{
int chars_used;
word[0] = '\0'; /* In case n < 1 */
while (n > 0 && sscanf(input, "%s%n", word, &chars_used) > 0)
{
input += chars_used;
n--;
}
if (n > 0)
{
printf("You didn't enter enough values\n");
return 0;
}
return 1;
}
As far as style goes, you should make the input parameter const char *, since the characters pointed to are not being modified in the function.
In terms of safety, word should be allocated with a length of strlen(input) + 1, rather than declared as a fixed-size array, since the words may be up to that length.
Here are a few pieces of advice:
instead of scanning a fixed number of words, loop n times scanning a single word
use strtok instead of sscanf for this; it will make your life much easier
try to avoid compiled-in limits on how long a word can be (20), especially when you're not checking to see if those limits are being exceeded
avoid copying string data unnecessarily when scanning it, especially (as stated above) when you're not enforcing length limits on your strcpy calls. Using strtok will locate words within the input with zero copies.
Homework? As homework assignments go, it's a bit interesting, as it tempts one to implement a crude and limited solution yet allows a fairly easy true solution.
Anyway, here is my shot at it...
#include <stdio.h>
#include <stdlib.h>
int set_to_nth_word(char *word, const char *input, int n) {
int i;
size_t used = 0;
char convert[1000];
static const char convertPattern[] = " %*s";
static const char convertReal[] = " %s";
if((unsigned)n > sizeof convert / sizeof convertPattern - 1)
return 0;
for(i = 1; i < n; ++i)
used += sprintf(convert + used, "%s", convertPattern);
sprintf(convert + used, "%s", convertReal);
return sscanf(input, convert, word) == 1;
}
int main(int ac, char **av) {
static char space[1000];
static char wordn[1000];
if (ac > 1) {
fgets(space, sizeof space, stdin);
if(set_to_nth_word(wordn, space, atoi(av[1])))
printf("%s\n", wordn);
}
return 0;
}