I have another problem concerning C :( what I want to do with this function is check for numbers in a token and if there are none I put that token in a string, which I later print to file. My function looks like this:
const char *tarpas = " ";
{
const char *space = " ";
char *token, B[255];
int i, length, found = 0, x = 0;
token = strtok(A, space);
while(token != NULL){
for(i = 0; i < strlen(token); i++){
if((token[i] >= '0') && (token[i] <= '9')) found++; //If found a number
} //increase found
if(found == 0){ //if found = 0 means the word is clean
for(i = 0; i < strlen(token); i++){
B[x] = token[i];
x++;
}
B[x] = ' '; //adds a space after the token is in string
x++;
}
rado = 0;
token = strtok(NULL, tarpas); // get another token
}
print(B);
memset(B, 0, strlen(B)); //clear B string
}
My data file:
ta5iip r345ytas suraitytas o rytoj gimimo rytas
asdasdasd
asdasd
My result file:
asdasd \
rytoj gimimo rytas
(
What it should be:
suraitytas o rytoj gimimo rytas
asdasdasd
asdasd
Thank you for any kind of input!!!
You have to reset found in each iteration of the while loop.
Also you have to exit loop
for(i = 0; i < strlen(token); i++){
if((token[i] >= '0') && (token[i] <= '9')) found++; //If found a number
}
if a digit was found in the string.
This loop could be rewritten the following way
size_t n = strlen(token);
i = 0;
while ( i < n && ( token[i] < '0' || token[i] > '9' ) ++i;
found = i != n;
It seems also that you read strings with function fgets that includes the new line character. You should remove this character from the string.
ANd place statement
memset(B, 0, strlen(B));
before the while loop or initially initialize array B to zeroes
You never reset found to zero inside the loop.
Since you find a digit in the first token, that means that you never execute the if(found == 0) code.
This, in turn, means that when you print B, it's still uninitialised and you're printing some random data.
You should initialise B:
char B[255] = {0};
and add
found = 0;
as the first line of the loop.
Or, since you have no use of found outside the loop, move it inside the loop.
while(token != NULL){
int found = 0;
/* ... */
You forgot to initialize found variable inside the while loop. Also as #BLUEPIXY mentioned, B array needs to be ended with '\0'.
So the code would be as following
{
const char *space = " ";
char *token, B[255];
int i, length, found = 0, x = 0;
token = strtok(A, space);
while(token != NULL){
found = 0;
for(i = 0; i < strlen(token); i++){
if((token[i] >= '0') && (token[i] <= '9')) found++; //If found a number
} //increase found
if(found == 0){ //if found = 0 means the word is clean
for(i = 0; i < strlen(token); i++){
B[x] = token[i];
x++;
}
B[x] = ' '; //adds a space after the token is in string
x++;
}
rado = 0;
token = strtok(NULL, tarpas); // get another token
}
B[x] = '\0';
print(B);
memset(B, 0, strlen(B)); //clear B string
}
Related
I am writing a function that is supposed to get an array with a tweet inside it and an empty array which should be filled with usernames that are in the tweet starting with '#' each in its own line. The usernames in the username array should be without the '#'.
This is what I have so far, but this version only stores one username and doesn't even put a new line behind it, and I don't know why.
It's probably a logic mistake?
void extract_username(char *tweet, char *user){
int j = 0;
int z = 0;
for(int i = 0; i<strlen(tweet); i++){
if(tweet[i] == '#'){
z = i+1;
while(tweet[z] != ' '){
user[j] = tweet[z];
z++;
j++;
}
j++;
user[j] = '\n';
}
}
}
extract_username gets called in the main like this
int main(){
char tweet[281];
char user[281]; //for example #user1 hello #user2
printf("Please enter a tweet (max. 280 symbols): \n");
fgets(tweet, 281, stdin);
extract_usename(tweet, user);
printf("%s", user);
return 0;
}
Making the fewest changes possible, change the condition to while (tweet[z] != ' ' && tweet[z] != 0) and add the newline with user[j++] = '\n'; Probably best to explicitly add the NUL terminator at the end with user[j] = 0; as well.
void extract_username(char* tweet, char* user) {
int j = 0;
int z = 0;
for (int i = 0; i < strlen(tweet); i++) {
if (tweet[i] == '#') {
z = i + 1;
while (tweet[z] != ' ' && tweet[z] != 0) {
user[j] = tweet[z];
z++;
j++;
}
user[j++] = '\n';
}
}
user[j] = 0;
}
In this code, the string is split by the difference of the space. I could do that through strtok but I didn't. I just want to know that how can split the strings by assigning tokens to them, like if I want to print the first token then it should print the first word from the string. Similarly, if I want to print the second word then it should print the second word after the first space occurred and so on.
int main(){
char inputString[100], words[10][10];
int indexCtr = 0, wordIndex = 0, totalWords = 0;
printf("Input a string: ");
fgets(inputString, sizeof(inputString), stdin);
for(indexCtr = 0; indexCtr <= strlen(inputString); indexCtr++){
if(inputString[indexCtr] == ' ' || inputString[indexCtr] == '\0'){
words[totalWords][wordIndex] = '\0';
totalWords++;
wordIndex = 0;
}
else{
words[totalWords][wordIndex] = inputString[indexCtr];
wordIndex++;
}
}
printf("\nWords from the string are:\n");
for(indexCtr = 0; indexCtr < totalWords; indexCtr++){
printf("%s\n", words[indexCtr]);
}
return 0;
}
as an idea with strncpy(...):
char input[100] = " 1 2 3 4 5 "
"one two three four five";
char words[10][10] = { 0 };
size_t w_counter = 0;
for (size_t i = 0; i < strlen (input); i++) {
while (input[i] != '\0' && isspace (input[i])) {
i++;
}
char* start = &input[i];
while (input[i] != '\0' && !isspace (input[i])) {
i++;
}
strncpy (words[w_counter++],
start,
&input[i] - start);
}
//output
for (size_t i = 0; i < w_counter; i++){
puts (words[i]);
}
I received an assignment to write a code that would erase the instances of a string in another string, and although my code does that successfully, the symbol ╠ appears many times at the end of the result string.
Example:
For input string 1 - A string is a string, and an input string 2 - str
The result should be A ing is a ing.
But I receive A ing is a ing╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
Hoped I could get some assistance regarding this issue, cause no matter what I've tried I wasn't able to
fix this.
#include <stdio.h>
#define STRING_SIZE 100
int StrippingFunc(char input_str1[STRING_SIZE], char input_str2[STRING_SIZE], char
result_string[STRING_SIZE])
{
if (input_str2[0] == '\n' || input_str2[0] == '\0')
{
return 0;
}
for (int k1 = 0; k1 < STRING_SIZE; k1++)
{
if (input_str1[k1] == '\n')
{
input_str1[k1] = '\0';
}
}
for (int k2 = 0; k2 < STRING_SIZE; k2++)
{
if (input_str2[k2] == '\n')
{
input_str2[k2] = '\0';
}
}
int Length;
int length2 = 0;
int index2 = 0;
while (input_str2[index2] != '\0') // Loop used to determine input_string2's length.
{
length2++;
index2++;
}
int InString = 0;
int i = 0;
int j;
int resultindex = 0;
while (input_str1[i] != '\0')
{
Length = length2;
int l = i;
j = 0;
int proceed = 1;
if (input_str1[l] == input_str2[j])
{
while ((input_str2[j] != '\0') && (proceed != 0))
{
while (Length >= 0)
{
if (Length == 0)
{
InString = 1;
i += (l-i-1);
proceed = 0;
Length = -1;
}
if (input_str1[l] == input_str2[j])
{
Length--;
j++;
l++;
}
else if ((input_str1[l-1] == input_str2[j-1]) && (input_str2[j] == '\0'))
{
proceed = 0;
Length = -1;
}
else
{
proceed = 0;
Length = -1;
result_string[resultindex] = input_str1[l - 1];
resultindex++;
}
}
}
}
else
{
result_string[resultindex] = input_str1[i];
resultindex++;
}
i++;
}
return InString;
}
int main()
{
char result_string[STRING_SIZE];
char input_string1[STRING_SIZE];
char input_string2[STRING_SIZE];
printf("Please enter the main string..\n");
// Your function call here..
fgets(input_string1, STRING_SIZE + 1, stdin);
printf("Please enter the pattern string to find..\n");
// Your function call here..
fgets(input_string2, STRING_SIZE + 1, stdin);
int is_stripped = StrippingFunc(input_string1, input_string2, result_string);; // Your function call here..
// Store the result in the result_string if it exists
printf("> ");
printf(is_stripped ? result_string : "Cannot find the pattern in the string!");
return 0;
}
But I receive A ing is a ing╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
In the code after you fill result_string but you missed to add the final null character, because of that the printf after reach non initialized characters with an undefined behavior producing your unexpected writting. After
while (input_str1[i] != '\0')
{
Length = length2;
...
}
add
result_string[resultindex] = 0;
note you have the place for because result_string and input_str1 have the same size
Having
char input_string1[STRING_SIZE];
char input_string2[STRING_SIZE];
these two lines can have an undefined behavior :
fgets(input_string1, STRING_SIZE + 1, stdin);
fgets(input_string2, STRING_SIZE + 1, stdin);
because fgets may write after the end of the arrays, you need to remove +1 or to size the arrays one more
In
for (int k1 = 0; k1 < STRING_SIZE; k1++)
{
if (input_str1[k1] == '\n')
{
input_str1[k1] = '\0';
}
}
for (int k2 = 0; k2 < STRING_SIZE; k2++)
{
if (input_str2[k2] == '\n')
{
input_str2[k2] = '\0';
}
}
except if fgets fill all the arrays you have an undefined behavior working on non initialized characters because you do not stop when you reach newline or the null character.
In
int length2 = 0;
int index2 = 0;
while (input_str2[index2] != '\0') // Loop used to determine input_string2's length.
{
length2++;
index2++;
}
length2 and length2 have exactly the same value, is it useless to have two variables, and in fact this lop is useless because the previous loop with the right termination already give you the expected length.
In
printf(is_stripped ? result_string : "Cannot find the pattern in the string!");
I encourage you to replace printf by a puts not only to add a final newline to flush the output and make it more clear in case you start your program in a shell, but also because in case the input string contains for instance %d and it is not removed and is_stripped is true then printf will try to get an argument whose do not exist, with an undefined behavior
If you do all the corrections with your inputs your code will print > A ing is a ing without undefined behavior
I have a problem where I'm trying to turn a value from an array of string pointers to an integer value: token[1]. However, I get a segmentation fault whenever I don't specify an integer at the first index which in some cases I won't need a number. For example what if I just wanted to type the command: list. I would get a segmentation fault after. How do I store the convert the string value at token[1] to an integer, if an integer is present or not?
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
int main(){
int ch, n = 1;
int i = 0;
int val = 0;
char str[512], *token[5], *act_token;
while(1){
printf("Enter text: ");
while((ch = getchar()) != '\n')
str[i++] = ch;
str[i] = '\0';
i = 0;
printf("string: %s\n", str);
int spaces = 0;
for(int counter = 0; counter < strlen(str) + 1; counter++){
if(str[counter] == ' '){
spaces++;
}
}
printf("Spaces: %d\n", spaces);
strtok(str, " ");
while(n <= spaces && (act_token = strtok(NULL, " "))){
token[n] = act_token;
n++;
}
token[n] = NULL;
n = 1;
// printf("token[1]: %s\n", token[1]);
for(int x = 1; x < spaces+1; x++){
printf("token[%d]: %s\n", x, token[x]);
}
if(isdigit(atoi(token[1])) != 0){
val = atoi(token[1]);
}
printf("value:%d\n", val);
}
return 0;
}
I don't know whether I understand you correctly. However, I have simply added some checks to prevent segfault that were occurring at varying points of the code. Tested with 'foo 3 33'. Formatting is poor.
int main(){
int ch, n = 1;
int i = 0;
int val = 0;
#define TOKEN_SZ 5
char str[512], *token[TOKEN_SZ+1], *act_token;
while(1){
printf("Enter text: ");
while((ch = getchar()) != '\n')
str[i++] = ch;
str[i] = '\0';
i = 0;
printf("string: %s\n", str);
int spaces = 0;
for(int counter = 0; counter < strlen(str) + 1; counter++){
if(str[counter] == ' '){
spaces++;
}
}
printf("Spaces: %d\n", spaces);
n=0;
strtok(str, " ");
while(n<TOKEN_SZ && n <= spaces && (act_token = strtok(NULL, " "))){
token[n] = act_token;
n++;
}
token[n] = NULL;
for(int i=0; token[i]; i++){
printf("%d token[%d]: %s\n", n,i, token[i]);
}
if(n>0 && (atoi(token[0])) != 0){
val = atoi(token[0]);
}
printf("value:%d\n", val);
}
return 0;
}
Update
bash> ./a.out
Enter text: list 2 4
string: list 2 4
Spaces: 2
2 token[0]: 2
2 token[1]: 4
value:2
Enter text:
Replace
if(isdigit(atoi(token[1])) != 0){
val = atoi(token[1]);
}
with
if(isdigit(token[1][0])) != 0){
val = atoi(token[1]);
}
The problem is that isdigit takes a character as its argument. Sure, the man page says it takes an integer, but that integer represents a character.
What your code is doing is:
convert token[1] to an integer (or 0 if it's not a valid integer)
determine whether that integer happens to match an ASCII digit
If so, convert it again, and save the value.
I doubt that's your intent.
My version checks whether the first character of token[1] is a digit, and converts the value if it is. Make sure you understand what token[1][0] means.
BTW, note that if you enter more than 5 space-separated words in your string, you'll store to tokens[6] and higher, which will produce undefined results (possibly crash.) Also, your program is wrong if the user enters more than two spaces between words.
Don't guess what strtok is going to do regarding how it detects and handles delimiters. Instead, let it do its job. Store the values as you get them. Either pick a limit value for the array where you're storing your results and exit the loop before exceeding it, or malloc space for more results as necessary. Here's an example:
char * tstr = str;
int tok_count = 0;
char *tok;
do {
tok = strtok(tstr, " ");
if (tok != NULL) {
token[tok_count++] = tok;
}
tstr = NULL;
} while (tok != NULL && tok_count < TOK_COUNT);
TOK_COUNT has to be at least 1, and should be the array size for tokens.
I basically have a sentence in a string and want to break it down word per word. Every word should go into an array of strings. I am not allowed to use strtok. I have this code but it doesn't work. Can someone help?
There is for sure something similar in the internet but I couldn't find anything...
int main(){
char s[10000]; // sentence
char array[100][100]; // array where I put every word
printf("Insert sentence: "); // receive the sentence
gets(s);
int i = 0;
int j = 0;
for(j = 0; s[j] != '\0'; j++){ // loop until I reach the end
for(i = 0; s[i] != ' '; i++){ // loop until the word is over
array[j][i] = s[i]; // put every char in the array
}
}
return 0;
}
Every word should go into an array of strings. I am not allowed to use
strtok.
Interesting problem which could be resolved in a compact algorithm.
It handles multiple spaces and punctuation marks specified in check(char c).
The most difficult part of the problem is to properly handle corner cases. We may have situation when words are longer more than WORD_LEN length or the number of words exceeds the capacity of the array.
Both cases are properly handled. The algorithm truncates the excessive words and parses only to the capacity of the array.
(BTW. Do not use gets: Why is the gets function so dangerous that it should not be used?)
Edit: The fully tested find_tokens function has been presented.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORD_LEN 3 // 100 // MAX WORD LEN
#define NR_OF_WORDS 3 // 100 // MAX NUMBER OF WORDS
#define INPUT_SIZE 10000
int is_delimiter(const char * delimiters, char c) // check for a delimiter
{
char *p = strchr (delimiters, c); // if not NULL c is separator
if (p) return 1; // delimeter
else return 0; // not a delimeter
}
int skip(int *i, char *str, int skip_delimiters, const char *delimiters)
{
while(1){
if(skip_delimiters) {
if( (str[(*i)+1] =='\0') || (!is_delimiter(delimiters, str[(*i)+1])) )
break; // break on nondelimeter or '\0'
else (*i)++; // advance to next character
}
else{ // skip excess characters in the token
if( is_delimiter(delimiters, str[(*i)]) )
{
if( (str[(*i)+1] =='\0') || !is_delimiter(delimiters, str[(*i)+1]) )
break; // break on non delimiter or '\0'
else (*i)++; // skip delimiters
}
else (*i)++; // skip non delimiters
}
}
if ( str[(*i)+1] =='\0') return 0;
else return 1;
}
int find_tokens(int max_tokens, int token_len, char *str, char array[][token_len+1], const char *delimiters, int *nr_of_tokens)
{
int i = 0;
int j = 0;
int l = 0;
*nr_of_tokens = 0;
int status = 0; // all OK!
int skip_leading_delimiters = 1;
int token = 0;
int more;
for(i = 0; str[i] != '\0'; i++){ // loop until I reach the end
// skip leading delimiters
if( skip_leading_delimiters )
{
if( is_delimiter( delimiters, str[i]) ) continue;
skip_leading_delimiters = 0;
}
if( !is_delimiter(delimiters,str[i]) && (j < token_len) )
{
array[l][j] = str[i]; // put char in the array
//printf("%c!\n", array[l][j] );
j++;
array[l][j] = 0;
token = 1;
}
else
{
//printf("%c?\n", str[i] );
array[l][j] = '\0'; // token terminations
if (j < token_len) {
more = skip(&i, str, 1, delimiters); // skip delimiters
}
else{
more = skip(&i, str, 0, delimiters); // skip excess of the characters in token
status = status | 0x01; // token has been truncated
}
j = 0;
//printf("more %d\n",more);
if(token){
if (more) l++;
}
if(l >= max_tokens){
status = status | 0x02; // more tokens than expected
break;
}
}
}
if(l>=max_tokens)
*nr_of_tokens = max_tokens;
else{
if(l<=0 && token)
*nr_of_tokens = 1;
else
{
if(token)
*nr_of_tokens = l+1;
else
*nr_of_tokens = l;
}
}
return status;
}
int main(void){
char input[INPUT_SIZE+1]; // sentence
char array[NR_OF_WORDS][WORD_LEN+1]; // array where I put every word, remeber to include null terminator!!!
int number_of_words;
const char * delimiters = " .,;:\t"; // word delimiters
char *p;
printf("Insert sentence: "); // receive the sentence
fgets(input, INPUT_SIZE, stdin);
if ( (p = strchr(input, '\n')) != NULL) *p = '\0'; // remove '\n'
int ret = find_tokens(NR_OF_WORDS, WORD_LEN, input, array, delimiters, &number_of_words);
printf("tokens= %d ret= %d\n", number_of_words, ret);
for (int i=0; i < number_of_words; i++)
printf("%d: %s\n", i, array[i]);
printf("End\n");
return 0;
}
Test:
Insert sentence: ..........1234567,,,,,,abcdefgh....123::::::::::::
tokens= 3 ret= 1
0: 123
1: abc
2: 123
End
You are not '\0'-terminating the strings and you are scanning the source from
the beginning every time you've found a empty character.
You only need one loop and, the inner loop and the condition must be s[i] != 0:
int j = 0; // index for array
int k = 0; // index for array[j]
for(i = 0; s[i] != '\0'; ++i)
{
if(k == 99)
{
// word longer than array[j] can hold, aborting
array[j][99] = 0; // 0-terminating string
break;
}
if(j == 99)
{
// more words than array can hold, aborting
break;
}
if(s[i] == ' ')
{
array[j][k] = 0; // 0-terminating string
j++; // for the next entry in array
k = 0;
} else
array[j][k++] = s[i];
}
Note that this algorithm doesn't handle multiple spaces and punctuation marks.
This can be solved by using a variable that stores the last state.
int j = 0; // index for array
int k = 0; // index for array[j]
int sep_state = 0; // 0 normal mode, 1 separation mode
for(i = 0; s[i] != '\0'; ++i)
{
if(k == 99)
{
// word longer than array[j] can hold, aborting
array[j][99] = 0; // 0-terminating string
break;
}
if(j == 99)
{
// more words than array can hold, aborting
break;
}
// check for usual word separators
if(s[i] == ' ' || s[i] == '.' || s[i] == ',' || s[i] == ';' || s[i] == ':')
{
if(sep_state == 1)
continue; // skip multiple separators
array[j][k] = 0; // 0-terminating string
j++; // for the next entry in array
k = 0;
sep_state = 1; // enter separation mode
} else {
array[j][k++] = s[i];
sep_state = 0; // leave separation mode
}
}
As you can see, using the sep_state variable I'm able to check if multiple
separators come one after the other and skips subsequent separators. I also
check for common punctuation marks.
#include <stdio.h>
int main()
{
char s[10000]; // sentence
char array[100][100]; // array where i put every word
printf("Insert sentence: "); // receive the sentece
gets(s);
printf("%s",s);
int i = 0;
int j = 0;
int k = 0;
for(j = 0; s[j] != '\0'; j++){ // loop until i reach the end
if ( s[j] != ' ' || s[j] == '\0' )
{
array[i][k] = s[j];
k++;
}
else {
i++;
k = 0;
}
}
return 0;
}
please note that the gets function is very unsafe and shouldn't in any case be used, use scanf or fgets instead