Nested strtok_r : command line argument parsing - c

CODE HERE: http://ideone.com/AZnXFm
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
int main()
{
char *buffer;
size_t bufsize = 32;
size_t characters;
buffer = (char *)malloc(bufsize * sizeof(char));
if( buffer == NULL)
{
perror("Unable to allocate buffer");
exit(1);
}
printf("Type something: ");
characters = getline(&buffer,&bufsize,stdin);
printf("%zu characters were read.\n",characters);
printf("You typed: %s",buffer);
char *end_str,*token2;
char *token = strtok_r(buffer,";",&end_str);
printf("token : %s \n", token);
int count =0,wordcnt=0;
while(token !=NULL)
{
char *end_token;
count++;
printf("outside count ------------------------%d\n", count);
strtok_r(token," ",&end_token);
while(token2!=NULL)
{
wordcnt++;
printf("insdie count %d\n",wordcnt);
printf("%s------------------- \n", token2);
token2 = strtok_r(NULL," ",&end_token);
}
token = strtok_r(NULL, ";",&end_str);
}
return(0);
}
Output is
Type something: rosie is; really good
22 characters were read.
You typed: rosie is; really good
token : rosie is
outside count ------------------------1
insdie count 1
AWAVA��AUATL�% -------------------
insdie count 2
is-------------------
outside count ------------------------2

A number of basic fixes are needed or have been applied in the code below:
Let getline() do the memory allocation.
Check that getline() read a line.
Free the memory allocated.
Set token2 with inner strtok_r() call.
Make variable names a bit more systematic.
Make characters into ssize_t to match the return from getline().
Print characters using %zd. This is marginally controversial; it prints the signed variant of size_t with the z-qualified signed decimal format string. It makes sense (to me at least and my compiler — GCC 6.2.0 on macOS Sierra), but I'm not sure where to find the confirmation that it is officially sanctioned by (the POSIX) standards.
Renaming variables for consistency.
Other minor cosmetic fixups (the print formatting could still be improved — quite a lot).
Leading to:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *buffer = 0;
size_t bufsize = 0;
ssize_t characters;
printf("Type something: ");
characters = getline(&buffer, &bufsize, stdin);
printf("%zd characters were read.\n", characters);
if (characters > 0)
{
printf("You typed: %s", buffer);
char *end_str1;
char *token1 = strtok_r(buffer, ";", &end_str1);
printf("token: %s \n", token1);
int count = 0, wordcnt = 0;
while (token1 != NULL)
{
char *end_str2;
count++;
printf("outside count ------------------------%d\n", count);
char *token2 = strtok_r(token1, " ", &end_str2);
while (token2 != NULL)
{
wordcnt++;
printf("inside count %d\n", wordcnt);
printf("%s------------------- \n", token2);
token2 = strtok_r(NULL, " ", &end_str2);
}
token1 = strtok_r(NULL, ";", &end_str1);
}
}
free(buffer);
return(0);
}
Example run:
Type something: rosie is; really good
22 characters were read.
You typed: rosie is; really good
token: rosie is
outside count ------------------------1
inside count 1
rosie-------------------
inside count 2
is-------------------
outside count ------------------------2
inside count 3
really-------------------
inside count 4
good
-------------------

Related

Operations with text and delimiters

The task is: to read the text from file and to read an array of delimiters from keyboard. Than the program should search the sequence of delimiters in the text and, if it would be found 3 times or more, swap all the odd strings in a circle. Also it should detete all the words, which exceed the length limit, entered by user, but only in odd strings.
This is what i've got now:
#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
int main(void)
{
setlocale(LC_ALL, "Russian"); //entering the text
const int numberOfCharactersToRead = 128;
char* inputText = (char*)(malloc(sizeof(char) * numberOfCharactersToRead));
FILE *fp;
fopen_s(&fp, "D:\texxxt.txt", "r");
if (fp == NULL)
{
printf("nFile not foundn");
system("pause");
return 0;
}
fgets(inputText, numberOfCharactersToRead, fp);
printf("Enter the sequence of delimiters: "); //entering delimiters
const int numberOfDelimitersToRead = 6;
char* delimiters = (char*)(malloc(sizeof(char) * numberOfDelimitersToRead));
int indexer = 0;
for (indexer = 0; indexer < numberOfDelimitersToRead; indexer++)
{
delimiters[indexer] = getchar();
}
//Trying to use strtok in order to devide text into rows (unsuccesful)
char delims[] = "/n";
char *pch = strtok_s(NULL, inputText, &delims);
printf("nLexems:");
while (pch != NULL)
{
printf("n%s", pch);
pch = strtok_s(NULL, inputText, &delims);
}
return 0;
}
int symcount(void)
{ //function searching the quantity of delimiters
char str[20], ch;
int count = 0, i;
printf("nEnter a string : ");
scanf_s("%s", &str);
printf("nEnter the character to be searched : ");
scanf_s("%c", &ch);
for (i = 0; str[i] != ''; i++)
{
if (str[i] == ch)
count++;
}
if (count == 0)
printf("nCharacter '%c'is not present", ch);
else
printf("nOccurence of character '%c' : %d", ch, count);
return (0);
}
I dont really know how to devide the text into rows and how to make my program differentiate even and odd strings. I'm really confused
The definition of strtok_s is the following:
char *strtok_s(char *strToken, const char *strDelimit, char **context);
You are mixing up the parameters. The 1st parameter should be a pointer to the input string and the 2nd parameter should be the delimiter string. Finally after the function is executed the 3rd parameter will be passed a pointer to the string after the position where the delimiter was found, or NULL if no delimiter was found. This pointer can then be passed onto the next strtok_s call to continue the search.
char *pchNext;
char *pch = strtok_s(inputText, delimiters, &pchNext);
while (pch != NULL)
{
printf("\n%s", pch);
pch = strtok_s(NULL, delimiters, &pchNext); // The first parameter can be NULL here
}
Also, the textual representation of the newline character is \n, not /n or n.

Scan a sentence with space into *char array in C

I'm not good at using C language. Here is my dumb question. Now I am trying to get input from users, which may have spaces. And what I need to do is to split this sentence using space as delimiter and then put each fragment into char* array. Ex:
Assuming I have char* result[10];, and the input is: Good morning John. The output should be result[0]="Good"; result[1]="morning"; result[2]="John";I have already tried scanf("%[^\n]",input); and gets(input); Yet it is still hard to deal with String in C. And also I have tried strtok, but it seems that it only replaced the space by NULL. Hence the result will be GoodNULLmorningNULLJohn. Obviously it's not what I want. Please help my dumb question. Thanks.
Edit:
This is what I don't understand when using strtok. Here is a test code.
The substr still displayed Hello there. It seems subtok only replace a null at the space position. Thus, I can't use the substr in an if statement.
int main()
{
int i=0;
char* substr;
char str[] = "Hello there";
substr = strtok(str," ");
if(substr=="Hello"){
printf("YES!!!!!!!!!!");
}
printf("%s\n",substr);
for(i=0;i<11;i++){
printf("%c", substr[i]);
}
printf("\n");
system("pause");
return 0;
}
Never use gets, is deprecated in C99 and removed from C11.
IMO, scanf is not a good function to use when you don't know the number of elements before-hand, I suggest fgets:
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[128];
char *ptr;
fgets(str, sizeof str, stdin);
/* Remove trailing newline */
ptr = strchr(str, '\n');
if (ptr != NULL) {
*ptr = '\0';
}
/* Tokens */
ptr = strtok(str, " ");
while (ptr != NULL) {
printf("%s\n", ptr);
ptr = strtok(NULL, " ");
}
return 0;
}
gets is not recommended to use, as there is no way to tell the size of the buffer. fgets is ok here because it will stop reading when the 1st new line is encountered. You could use strtok to store all the splited words in to an array of strings, for example:
#include <stdio.h>
#include <string.h>
int main(void) {
char s[256];
char *result[10];
fgets(s, sizeof(s), stdin);
char *p = strtok(s, " \n");
int cnt = 0;
while (cnt < (sizeof result / sizeof result[0]) && p) {
result[cnt++] = p;
p = strtok(NULL, " \n");
}
for (int i = 0; i < cnt; i++)
printf("%s\n", result[i]);
return 0;
}
As most of the other answers haven't covered another thing you were asking:
strtok will not allocate temporary memory and will use your given string to replace every separator with a zero termination. This is why Good morning John becomes GoodNULLmorningNULLJohn. If it wouldn't do this, each token would print the whole rest of the string on its tail like:
result[0] = Good morning John
result[1] = morning John
result[2] = John
So if you want to keep your original input and an array of char* per word, you need 2 buffers. There is no other way around that. You also need the token buffer to stay in scope as long as you use the result array of char* pointers, else that one points to invalid memory and will cause undefined behavior.
So this would be a possible solution:
int main()
{
const unsigned int resultLength = 10;
char* result[resultLength];
memset(result, 0, sizeof result); // we should also zero the result array to avoid access violations later on
// Read the input from the console
char input[256];
fgets(input, sizeof input, stdin);
// Get rid of the newline char
input[strlen(input) - 1] = 0;
// Copy the input string to another buffer for your tokens to work as expected
char tokenBuffer[256];
strcpy(tokenBuffer, input);
// Setting of the pointers per word
char* token = strtok(tokenBuffer, " ");
for (unsigned int i = 0; token != NULL && i < resultLength; i++)
{
result[i] = token;
token = strtok(NULL, " ");
}
// Print the result
for (unsigned int i = 0; i < resultLength; i++)
{
printf("result[%d] = %s\n", i, result[i] != NULL ? result[i] : "NULL");
}
printf("The input is: %s\n", input);
return 0;
}
It prints:
result[0] = Good
result[1] = morning
result[2] = John
result[3] = NULL
result[4] = NULL
result[5] = NULL
result[6] = NULL
result[7] = NULL
result[8] = NULL
result[9] = NULL
The input is: Good morning John

How do I split elements in an array of unsigned char

I have the following:
unsigned char input[];
unsigned char *text = &input[];
I'm taking in user input as follows:
do {
printf ("Please enter an numeric message terminated by -1:\n");
fgets(input, sizeof(input), stdin);
}
while (input[0] == '\n')
Since my output will give me an array of individual characters, how
can I go about concatenating them. If I enter input such as:
14 156 23 72 122
when I try to work with it, it's breaking it into:
1 4 1 5 6 ...
In other words, when I want to pass it to a function as an unsigned char,
I want to pass '14', so the function can read the binary of 14, rather than
1, then 4, etc. Any help would be greatly appreciated!
As it stands now, your code does not compile.
You cannot declare these variables like this:
unsigned char input[];
unsigned char *text = &input[];
You need to say how big input is supposed to be. I'm not sure what you're doing with your second definition.
You also need to put a semicolon after this line
while (input[0] == '\n')
All of that aside, if the input is separated by a know delimiter, you could use strtok() instead of reading the string byte by byte.
I scrapped your program because it didn't compile. This is what I assume you're trying to do with your code, adjust accordingly:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/*
* Converts "input" separated by "delims" to an array of "numbers"
*/
size_t str_to_nums(const char* input, const char* delims, int* numbers, size_t numsize)
{
char* parsed = malloc(strlen(input) + 1); /* allocate memory for a string to tokenize */
char* tok; /* the current token */
size_t curr; /* the current index in the numbers array */
strcpy(parsed, input); /* copy the string so we don't modify the original */
curr = 0;
tok = strtok(parsed, delims);
while(tok != NULL && curr < numsize) { /* tokenize until NULL or we exceed the buffer size */
numbers[curr++] = atoi(tok); /* convert token to integer */
tok = strtok(NULL, delims); /* get the next token */
}
free(parsed);
return curr; /* return the number of tokens parsed */
}
int main(void)
{
char input[256];
int numbers[64];
size_t count, i;
puts("Please enter an numeric message terminated by -1:");
fgets(input, sizeof(input), stdin);
count = str_to_nums(input, " ", numbers, sizeof(numbers)/sizeof(*numbers)); /* string is separated by space */
for(i = 0; i < count; ++i) {
printf("%d\n", numbers[i]); /* show the results */
}
}
P.s. This is not concatenation. The phrase your looking for is "string splitting" or "tokenizing".
Try this!
#include <string.h>
#include <stdio.h>
int main()
{
char *line;
char *token;
scanf(" %[^\n]s",line);
/* get the first token */
token = strtok(line, " ");
/* walk through other tokens */
while( token != NULL )
{
printf( " %s\n", token );
token = strtok(NULL, " ");
}
return(0);
}

c how to cut of the first x words of a string?

I have a char array:
char tmp[2048];
I want to cut of the first x words of tmp. I define a word as a sequence of characters that does not include whitespaces. I tried something like this (should cut of the first 3 words):
sscanf(tmp, "%*s %*s %*s %s", tmp);
My problem is, that '%s' stops at the first whitespace it finds. I want the new string to end at the end of the old string, not at the first whitespace.
I'm also open for other suggestions how to cut of the first x words of a string. I define a word as a sequence of characters that doesn't contain whitespaces.
Here's a rough implementation:
const char* TrimWords(const char* input, int nWords)
{
while (nWords)
{
if (!isspace(*input) && isspace(*(input + 1)))
{
nWords--;
}
input++;
}
return input;
}
TrimWords("One Two Three Four Five", 3);
// returns " Four Five" after the first 3 words are trimmed.
Detailed input validation and error checking is left to the OP.
This is just a good starting point.
use strncpy(tmp, n, tmp+m); where m and n are ints
char tmp[20] = "abcdef";
strncpy(tmp, tmp + 3, 2);
for exmaple: code above will result in decdef
You can use strtok to tokenize strings by whitespace. Something similar to this could do what you're trying to achieve:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
// Number of words to trim
const int numWords = 2;
char tmp[1024];
char buffer[1024];
sprintf(tmp, "this is a\tsentence.");
strcpy(buffer, tmp);
char* token = strtok(buffer, " \t");
for (int i = 0; i < numWords && token; i++) {
token = strtok(NULL, " \t");
}
if (token) {
size_t len = 1024 - (token - buffer);
memmove(tmp, tmp + (token - buffer), len);
}
else {
memset(tmp, '\0', 1024);
}
// Prints "a sentence."
printf("%s", tmp);
return 0;
}
However, the use of strtok is tricky at best. I would suggest using an approach similar to that of abelenky's answer.

read 1/2/5 string inputs in c

i need to read input from the standart input line by line
but each line will contain 1 or 2 or 5 strings like :
bofob fbo
blabla bibi bobo fbo fbooo
bobobo bobo
bobof
how can i do this?
my idea is really not looking profassional and not working
char a[50],b[50],c[50],d[50],f[50];
int numOfStrings=0;
scanf(" %s",a); char a[50],b[50],c[50],d[50],f[50];
int numOfStrings=0;
scanf(" %s",a);
if (scanf (" %s",b)){
numOfStrings=2;
if (scanf (" %s %d %d",c,d,f)
numOfStrings=5;
}
if (scanf (" %s",b)){
numOfStrings=2;
if (scanf (" %s %d %d",c,d,f)
numOfStrings=5;
}
but its not working because it goes and read inputs from the next line
is there a way to read a whole line (i know its max 250 chars) and then know how many words are in there?
edit:
i will add a count words function
but what is the nicest wat ro read a line untilll the end line or eof??
int words(const char *sentence)
{
int count,i,len;
char lastC;
len=strlen(sentence);
if(len > 0)
{
lastC = sentence[0];
}
for(i=0; i<=len; i++)
{
if(sentence[i]==' ' && lastC != ' ')
{
count++;
}
lastC = int words(const char *sentence)
}
return count;
}
You need to use fgets() to take the input line-by-line. check the man page here. It will also liberate you from handling the limitation of [1/2/5/.....] numbers of space-seperated strings. Provided sufficient storage, you can read 1 to any number of "string"s.
Note: You might need to take care of the trailing newline \n [caused by ENTER] yourself. Causes trouble most of the times.
You could scan one line until the '\n' with %[^\n], then split the line into words with strtok():
#include <string.h>
#include <stdio.h>
const char s[2] = " ";
const int MAX_LINE_SIZE = 128;
FILE *fp;
char *word, *str;
int word_counter;
/* Open the file here */
while (fgets(str, MAX_LINE_SIZE, fp) != NULL)
{
word_counter = 0
/* get the first word */
word = strtok(str, s);
/* walk through other words */
while (word != NULL)
{
printf(" %s\n", word);
word_counter++;
word = strtok(NULL, s);
}
printf("This string contains %d words\n",word_counter);
}
/* END of FILE */
You can use fgets to read a file and strchr to count the number of spaces:
#include <stdio.h>
#include <string.h>
int main(void)
{
char s[250];
char *p;
FILE *f;
int i;
f = fopen("demo.txt", "r");
while ((p = fgets(s, sizeof s, f))) {
i = 0;
while ((p = strchr(p, ' '))) {
p++;
i++;
}
printf("%d spaces\n", i);
}
fclose(f);
return 0;
}

Resources