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;
}
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 have this C function which basically takes the input from the user and saves it in a static char[]. Then it checks whether it is empty. If it is empty then it prints an error, else appends a file extension to it. Here's the piece of code I'm concerned about:
const char* text_entry(){
char c;
while((c=getchar())!='\n' && c!=EOF);
static char input[20];
fgets(input, sizeof(input),stdin);
input[strcspn(input,"\n")]=0;
if(strlen(input)>0){
strncat(input, ".txt",4);
return input;
}
printf("Error! no text entered!");
return NULL;
}
My concern is that I want to remove the IF statement from it, making it more DRY. How can I do that?
The "DRY" is in the usage of strcspn(), strlen() and strncat(). You can avoid them by
size_t l = strcspn(input, "\n");
bool ok = false;
if (l == 0) {
fprintf(stderr, "error: too short\n");
} else if (l > sizeof input - sizeof(".txt")) {
fprintf(stderr, "error: too long\n");
} else {
strcpy(input + l, ".txt");
ok = true;
}
return ok ? input : NULL;
This is a minimal loop version. It doescheck* if the result fits into the input buffer.
Note:I'm not saying this is the best way todo it. But it avoids multiple scans over the input. (the gain in performance is mostly futile...)
#include <stdio.h>
#include <string.h>
char* text_entry(){
int ch;
size_t pos;
static char input[20];
//this is dubious: it consumes characters upto and including the first '\n'
while((ch=getchar())!='\n' && ch!=EOF) {;}
for (pos=0; pos < sizeof input; pos++) {
ch=getchar();
if (ch =='\n' || ch==EOF) break;
input[pos] = ch;
}
// noinput
if(!pos) return NULL;
// input too large: cannot append suffix
if(pos + sizeof ".txt" > sizeof input) return NULL;
memcpy(input+pos, ".txt", sizeof ".txt" );
// fprintf(stderr, "[%zu]\n",strlen(input));
return input;
}
int main(void)
{
char *result;
while(1) {
result = text_entry();
if (!result) continue;
printf("%s\n", result);
}
return 0;
}
I did not shorten your code, but I think you might find this solution more resilient, using the libreadline -lreadline
Before your returned a buffer which was declared on the stack, which means that it is unallocated on return, but yet you return its address. This is a bug.
I fixed it and gave you the opportunity to take a buffer and buffer size in parameters, as well as the extension, so the caller manages the memory for you as well as his maximum string length needs.
The loop now handles maximum input size well. It might not be shorter, but it should prove resilient.
/*
** Args:
** input_buffer: a buffer that will be whiped then filled with the user input
** buffer_size: the total size of the input buffer (maximum result length)
** extension: a dotted file type extension
**
** Returns: 0 on error or the input_buffer
*/
const char* text_entry(char *buffer, size_t buffer_size, char *extension) {
int maxsize = buffer_size - strlen(extension) - 1;
char *user_input;
int user_input_len;
do {
user_input = readline("Enter a file name: ");
user_input_len = strlen(user_input);
if (user_input_len > maxsize) {
printf("The name is too long! %d characters maximum. Try again.\n", maxsize);
free(user_input);
}
} while (!user_input_len || user_input_len > maxsize);
strcpy(buffer, user_input);
free(user_input);
strcat(buffer, extension);
printf("%s\n", buffer);
return buffer;
}
I need to find the Nth word in a string which is given through standard input through redirection operators in Unix.
Input is something along these lines:
But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born
5
The European languages are members of the same family.
3
Can anyone give me any idea as to how to read in the string into a char array and then get the int and use it to find the given word? I've been at it for a while and can't get it to work properly.
#define INPUT_LENGTH 400
int main(void)
{
char input[INPUT_LENGTH];
char integer[INPUT_LENGTH];
int spaces = 0;
int value;
char n;
while(fgets(input, INPUT_LENGTH, stdin)) //read in string line
{
while(fgets(integer, INPUT_LENGTH,stdin)) //read in int
{
int num = sscanf(integer, "%d", &value); //assign int val to num
while(1 == sscanf(input, "%c", &n)) //go through string one char at a time
if(spaces == num && !isspace(n))
printf("%c", n); //print chars if we've reached the word
else if(isspace(n))
spaces++;
}
}
}
I've redone most of it with the comments in mind but still can't seem to have it actually reading in the input through the operator unfortunately.
I'm not certain but I don't think my fgets are correct. I'm rather new to C and am not entirely certain how they process the data even after research
Use strtok like this
#include <stdio.h>
#include <string.h>
#define INPUT_LENGTH 400
int main(void){
char input[INPUT_LENGTH];
char integer[INPUT_LENGTH];
int value;
while(fgets(input, sizeof input, stdin)) //read in string line
{
if(fgets(integer, sizeof integer, stdin)) //read in int
{
if(1==sscanf(integer, "%d", &value)) //assign int value to value
{
char *word = strtok(input, " \t\n");
int n;
for(n = 1; word != NULL && n < value; ++n){// 1 origin
word = strtok(NULL, " \t\n");
}
if(word != NULL && n == value)
puts(word);//Nth word
else
puts("No word");
}
else {
printf("Numerical value is not specified.\n");
}
}
else {
printf("There is no numeric specification line.\n");
}
}
}
It would be better If I show you guys an example of what my program is supposed to do.
Input:
3
Double Double End
Triple Double End
Quadruple Double Triple End
Output:
4
6
24
So, the first sentence Double Double means 2*2 and Triple Double means 3*2 and so on.
The word End signifies the end of the string.
It looks very simple, but I have no idea how to work with strings and give them a value and continue on from there.
Here is all I have done so far:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num_of_orders,i,j;
char orders[25];
char str1[25] = "Double";
char str2[25] = "Triple";
char str3[25] = "Quadruple";
scanf("%d", &num_of_orders);
for (i=0; i<num_of_orders+1; i++){
scanf("%s", orders);
}
return 0;
}
There are a number of ways to approach this problem, as indicated by the variety of answers. There is often no one right answer for how to approach a problem in C. The standard library provides a variety of tools that allow you to craft a number of solutions to just about any problem. As long as the code is correct and protects against error, then the choice of which approach to take largely boils down to a question of efficiency. For small bits of example code, that is rarely a consideration.
One approach to take is to recognize that you do not need the first line in your data file (except to read it/discard it to move the file-position-indicator to the start of the first line containing data.)
This allows you to simply use a line-oriented input function (fgets or getline) to read the remaining lines in the file. strtok then provides a simple way to split each line into words (remembering to strip the '\n' or discard the last word in each line). Then it is a small matter of using strcmp to compare each word and multiply by the correct amount. Finally, output the product of the multiplication.
Here is one slightly different approach to the problem. The program will read from the filename given as the first argument (or from stdin by default):
#include <stdio.h>
#include <string.h>
enum { MAXC = 64 };
int main (int argc, char **argv) {
char buf[MAXC] = ""; /* line buffer */
char *delims = " \n"; /* delimiters */
int idx = 0; /* line index */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file pointer */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
while (fgets (buf, MAXC, fp)) { /* read each line */
if (!idx++) continue; /* discard line 1 */
char *p = buf;
size_t len = strlen (p); /* get length */
int prod = 1;
if (len && buf[len-1] == '\n') /* check for '\n' */
buf[--len] = 0; /* remove newline */
printf (" %s", buf); /* output buf before strtok */
/* tokenize line/separate on delims */
for (p = strtok (p, delims); p; p = strtok (NULL, delims))
{ /* make comparson and multiply product */
if (strcmp (p, "Double") == 0) prod *= 2;
if (strcmp (p, "Triple") == 0) prod *= 3;
if (strcmp (p, "Quadruple") == 0) prod *= 4;
}
printf (" = %d\n", prod); /* output product */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
Use/Output
$ ./bin/dbltrpl <../dat/dbltrpl.txt
Double Double End = 4
Triple Double End = 6
Quadruple Double Triple End = 24
Look it over and let me know if you have questions.
When it comes to reading the input, you can use strtok with a " " as a parameter to delimite the words you're reading from the input. This is a function filling all of the words read on the input into an array of strings:
PARAMETERS:
char **words: array of strings where you will store all of the words read in the input
char *input: the input you read (i.e. "Double Double end")
char *s: the delimiter you'll use to read words in the input (i.e. " ", "\n")
void getWords(char **words, char *input, char *s){
*words = strtok(str, s);
while(*words){
words++;
*words = strtok(NULL, s);
}
words++;
*words=NULL; //last element will point to NULL
}
Once you have read the words from the input, and filled them inside an array of strings, you could do something like this to calculate the output:
int calculate(char **words){
int result = 1;
while(*words){
if (strcmp(*words, "Quadruple") == 0){
result *= 4;
}else if (strcmp(*words, "Triple") == 0){
result *= 3;
}else if (strcmp(*words, "Double") == 0){
result *= 2;
}else if (strcmp(*words, "End") == 0){
return result;
}
words++;
}
}
Note that you need to correctly initialize the parameters you're passing before calling those functions. Otherwise, it may cause a Segmentation Fault.
You will have to use the methods from the string.h library, such as: strcmp(to compare two strings), strcpy(to copy one string to another) etc. which are generally used when dealing with strings manipulation in c.
Since, we do not know the size of the results array at compile time, we will have to allocate memory to it dynamically. For this purpose I have used malloc and free.
Here is the code to do that:
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
int main()
{
int num_of_orders, i, j;
char orders[25];
char str1[25];
strcpy(str1,"Double");
char str2[25];
strcpy(str2,"Triple");
char str3[25];
strcpy(str3,"Quadruple");
scanf("%d", &num_of_orders);
getchar();
int *results = malloc(num_of_orders*sizeof(int));
for (i=0; i < num_of_orders; i++)
{
results[i] = 1;
strcpy(orders,"");
while(strcmp(orders,"End") != 0)
{
scanf("%s", orders);
getchar();
if(strcmp(orders,str1)==0)
results[i] *= 2;
else if(strcmp(orders,str2) == 0)
results[i] *= 3;
else if(strcmp(orders,str3)==0)
results[i] *= 4;
}
}
for(i = 0; i < num_of_orders; i++)
printf("%d\n", results[i]);
free(results);
return 0;
}
Note: This program uses strcmp, which does case-sensitive comparison. If you want case-insensitive comparison, then use strcasecmp instead.
Don't forget the fact that the multiplication of integers is commutative:
#include <stdio.h>
#include <string.h>
int main(void)
{
int num_of_orders, i;
char orders[25];
int result;
char *ptr;
scanf("%d", &num_of_orders);
getchar(); // To comsume '\n'
for (i = 0; i < num_of_orders; i++)
{
fgets(orders, sizeof orders, stdin);
result = 1;
ptr = orders;
while(ptr = strstr(ptr, "Double"))
{
result *= 2;
ptr++;
}
ptr = orders;
while(ptr = strstr(ptr, "Triple"))
{
result *= 3;
ptr++;
}
ptr = orders;
while(ptr = strstr(ptr, "Quadruple"))
{
result *= 4;
ptr++;
}
printf("%d\n", result);
}
return 0;
}
What a trivial approach!
Note that strtok() is destructive, namely it will modify order, which can cause some problems if you want to use it later. Also, I think programs using strtok() are less readable. So it might be better to avoid it when possible.
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;
}