reading from different files and using strtok on strings - c

so this is a code that reads 3 strings (orig // test1 // orig_copy) from 2 different files (firstline // secondline)**and calls divide_string to use strtok and take tokens and store them in **(token_orig // token_test // token_orig_copy),
--> this is the problem :
- when i put the three lines in main it does compile and take token from all 3 strings and "Done ." in the end.
-but when i try the next three lines (notice how i changed "HAHAHAH" to "HAHAHAHA", that little changing changes everything and make the program stops at printf("for the string number two :"); .
i hope i cleared the problem
PS : you can past copy the program so you can compile yourself easily
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char s[4] = " ,.";
int divide_string(char* thestring,char** destination)
{
int i=0;
char* token=strtok(thestring,s);
destination[i]=malloc(sizeof(token)+1);
strcpy(destination[i],token);
i++;
printf("the word %d is 'tokened' \n",i);
while(token!=NULL)
{
token =strtok(NULL,s);
if (token != NULL)
{
destination[i]=malloc(sizeof(token)+1);
strcpy(destination[i],token);
printf("the word %d is 'tokened' \n",i);
++i;
}
}
return i;
}
void main ()
{ //TRY THESE THREE LINES THAT WORKS<-----------------------------
char orig[]= "does work HAHAHAH";
char orig_copy[] = "does work HAHAHAH";
char test1[]="does work HAHAHAH";
// char orig[]= "doesnt work HAHAHAHA";
// char orig_copy[] = "doesnt work HAHAHAHA";
// char test1[]="doesnt work HAHAHAHA";
char *token_orig[81];
char *token_test[81];
char *token_orig_copy[81];
strcpy(orig_copy,orig);
printf("for string number one : \n");
int max_orig = divide_string(orig,token_orig);
printf("for string number two : \n");
int a = divide_string(orig_copy,token_orig_copy);
printf("for string number three : \n");
int max_test = divide_string(test1,token_test);
printf("%s-",token_orig[0]);
printf("%s-",token_orig[1]);
printf("%s-\n",token_orig[2]);
printf("%s-",token_orig_copy[0]);
printf("%s-",token_orig_copy[1]);
printf("%s-\n",token_orig_copy[2]);
printf("%s-",token_test[0]);
printf("%s-",token_test[1]);
printf("%s-\n",token_test[2]);
printf("done .");
return 0;
}

Since token is a pointer, sizeof(token) gives you the size of the pointer variable (4 or 8 bytes probably), NOT the number of chars in the string it points to! You want:
strlen(token) + 1
instead (+1 for the \0).
About the only time sizeof is useful for character strings is literals like:
sizeof("Hello World")

Related

C program segfaulting with strtok

#include <stdio.h>
#include <unistd.h>
int main(void)
{
int n_of_words = 0;
#define MAX_STR_SZ 256
// asking for user input
char string[50];
printf("\nPlease input a string of text.\n\n");
fgets(string, MAX_STR_SZ, stdin);
char * words[n_of_words];
// extracting the first word
words[n_of_words] = strtok(string, " ");
printf("\n%i %s\n", n_of_words, words[n_of_words]);
// looping through the string to extract all other words
while( words[n_of_words] != NULL )
{
n_of_words ++;
words[n_of_words] = strtok(NULL, " ");
printf("\n%i %s\n", n_of_words, words[n_of_words]);
}
sleep(10);
return 0;
}
I'm very new to programming, but I was trying to write a function to extract words from a user inputted string and save them in an array for later use in the program. I added the 2 printf lines of code to see if it was working properly.
I always get a segmentation fault error after the second iteration of the while loop.
Also, somehow this problem didn't present itself when I compiled the same code on the CS50 ide (Cloud9), but it happens in any other case.
Few issues which can be resolved to prevent segmenatation fault:
No string.h header in the source code for strtokfunction
#include <stdio.h>
#include <unistd.h>
Macros are generally declared in the top of the source code and not inside any function
#define MAX_STR_SZ 256
The char string array is of length 50 but the fgets is allowing 256 and can lead to bufferoverflow.
char string[50];
printf("\nPlease input a string of text.\n\n");
fgets(string, MAX_STR_SZ, stdin);
The value of the variable n_of_words is 0. So, the declaration
char * words[n_of_words];
Will not create an array of the desired length.
The root cause of your question lies here:
while( words[n_of_words] != NULL )
{
n_of_words ++;
words[n_of_words] = strtok(NULL, " ");
printf("\n%i %s\n", n_of_words, words[n_of_words]);
}
You are accessing a memory location which was never declared,
n_of_words ++;
words[n_of_words] = strtok(NULL, " "); //words[1] or any index was never declared.
Every C program gets for free a list of the command line parameters, in general declared as int main(int argc, char* argv[]); or int main(int argc, char** argv);
This is precisely what you are trying to replicate with int n_of_words and char* words[n_of_words];
But you are doing it the wrong way.
A first note on this 3 lines from your code:
#define MAX_STR_SZ 256
char string[50];
fgets(string, MAX_STR_SZ, stdin);
You are setting 256 as the limit for fgets() to read, but you have only 50 chars in string. Many times it will work in this case, since you are reading from the keyboard and many of us would not key more than a few words in, but you have a problem. Change the limits.
strtok() is probably not the best one to choose here. A single loop using scanf() could read many lines and break all of then in words skipping over the newlines and such, and you may find it easier to code.
Anyway, back to your code: since you do not know in advance the number of words, you can estimate a limit or allocate memory for the strings one by one, or even in blocks. But
you need to allocate memory for the strings you will have a SegFault
at the moment you try to write in the words[] array.
I changed a minimum of your code so you can see an example, and I fixed the number of strings in a #define similar of what you have written so far.
A simple way to go is declare --- as C does in main() --- words[] as char** and allocate memory for them as soon as you know you have at least one string to record.
But then you need to note that you will have just the pointers. They are still pointing to nothing.
As soon as you have a string to load you need to allocate memory for it, plus 1 byte for the terminating '\0', and then copying the string and saving the address in the corresponding pointer in the words[] array.
See the code.
#define MAX_STR_SZ 256
#define MAX_N_OF_STRINGS 30
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// https://stackoverflow.com/questions/63343800/
// c-program-segfaulting-with-strtok
int main(int argc, char** argv)
{
int n_of_words = 0;
int max_n_of_words = MAX_N_OF_STRINGS;
char** words;
// asking for user input
char string[MAX_STR_SZ];
printf("\nPlease input a string of text: ");
fgets(string, MAX_STR_SZ, stdin);
string[strlen(string) - 1] = 0; // drops the final '\n'
printf("full string was '%s'\n", string);
if (strlen(string) == 0) return -1; // no input
// we have at least one byte
// before anything build words[]
words = (char**)malloc(max_n_of_words * sizeof(char*));
// now words[] points to an array of pointers to char
// extracting the first word
char* a_word = strtok(string, " ");
// looping through the string to extract all other words
do
{
printf("\n%i %s\n", 1+n_of_words, a_word);
words[n_of_words] = malloc(1 + sizeof(a_word));
strcpy(words[n_of_words], a_word);
n_of_words++;
if (n_of_words >= MAX_N_OF_STRINGS) break;
a_word = strtok(NULL, " ");
} while (a_word != NULL);
printf("\n%d words at the end of the loop:\n\n", n_of_words);
for (int i = 0; i < n_of_words; i += 1)
{
printf("%i %s\n", 1 + n_of_words, words[i]);
free(words[i]); // deletes words[i]
}; // for()
free(words); // deletes the array
return 0;
};
As a result:
Please input a string of text: we have at least one byte
full string was 'we have at least one byte'
1 we
2 have
3 at
4 least
5 one
6 byte
6 words at the end of the loop:
1 we
2 have
3 at
4 least
5 one
6 byte
There are a few problems that could lead to a seg fault. First, I get warnings compiling your code:
../main.c: In function 'main':
../main.c:17:25: warning: implicit declaration of function 'strtok' [-Wimplicit-function-declaration]
words[n_of_words] = strtok(string, " ");
^~~~~~
../main.c:17:23: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
words[n_of_words] = strtok(string, " ");
^
../main.c:24:27: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
words[n_of_words] = strtok(NULL, " ");
All of this is because you didn't include the proper header for strtok, namely string.h. This could potentially cause problems because the default return type is assumed to be int, which may not be large enough to hold a pointer.
Second, you are passing an incorrect size to fgets(). The size should be the size of the buffer for holding the result. If the buffer is overflowed, undefined behavior results.
Finally, the words array is declared with a size n_of_words, which is zero at that point. This results in a zero size array. Arrays in C do not automatically grow.
Here is your code with these issues fixed:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(void)
{
int n_of_words = 0;
#define MAX_STR_SZ 256
// asking for user input
char string[MAX_STR_SZ]; // <--- Use macro to define buffer size
printf("\nPlease input a string of text.\n\n");
fgets(string, sizeof string, stdin);
char * words[MAX_STR_SZ]; // <--- Should never be more words than characters in the buffer
// extracting the first word
words[n_of_words] = strtok(string, " ");
printf("\n%i %s\n", n_of_words, words[n_of_words]);
// looping through the string to extract all other words
while( words[n_of_words] != NULL )
{
n_of_words ++;
words[n_of_words] = strtok(NULL, " ");
printf("\n%i %s\n", n_of_words, words[n_of_words]);
}
sleep(10);
return 0;
}

C read file content into an array of strings

I need to load the contents of a file into two string arrays. I tried the following and it is not working.
file.txt contains 10 records and each record has two string values separated by whitespace.
CODE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char line[12][20];
FILE *fptr = NULL;
int i = 0;
int tot = 0;
fptr = fopen("file.txt", "r");
char arr[20][20];
while (fgets(line, sizeof(line), fptr)) {
strcpy(arr[i],line);
i++;
}
tot=i;
for (int i=0; i<tot; i++) {
printf("first value %s",arr[i][0]);
printf("second value is %s",arr[i][1]);
printf("\n");
}
return 0;
}
If I understand correctly, you're trying to store data in a structure like:
{{"line1A", "line1B"}, {"line2A", "line2B"}, {"line3A", "line3B"}}
It looks like you need an array where each element consists of two arrays (strings), one for the first value and one for the second value on each line. If this is the case, you need a three dimensional array of chars.
In the example below I've declared arrayOfLines as array with 12 elements each of which has 2 arrays of chars (for your two values per line), with space for 20 chars in each string (NULL terminated char array)
There are some other problems with your code:
The first parameter for fgets() should be a char * - a pointer to a string buffer. Your code passes in a multi-dimensional array of chars.
Your while loop should continue until fgets returns NULL
You need to split each line into multiple strings
Check for buffer overruns when copying strings with strcpy()
In the example code I used strtok() delimited by a " " space character - you may need to play around with this - strtok can accept an array of chars to be used as a delimiter. In the example, I split the first string using the first space char, and the second string is delimited by the end of line.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
// Array for 12 lines, each with 2 strings, each string max 20 chars
// Adjust values as required.
char arrayOfLines[12][2][20];
FILE *fptr = NULL;
int i = 0;
int tot = 0;
fptr = fopen("file.txt", "r");
// char arr[20][20]; not needed
char line[20];
while(fgets(line, sizeof(line) / sizeof(line[0]), fptr) != NULL)
{
// Rudimentary error checking - if the string has no newline
// there wasn't enough space in line
if (strchr(line, '\n') == NULL) {
printf("Line too long...");
return EXIT_FAILURE;
}
// Split string into tokens
// NB: Check for buffer overruns when copying strings
char *ptr1 = strtok(line, " ");
strcpy(arrayOfLines[i][0], ptr1);
char *ptr2 = strtok(NULL, "\n");
strcpy(arrayOfLines[i][1], ptr2);
i++;
}
tot=i; // Unecessary - just use a different variable in your loop and use i as the upper bound
for (int i=0;i<tot;i++)
{
printf("first value %s\n", arrayOfLines[i][0]);
printf("second value is %s\n", arrayOfLines[i][1]);
printf("\n");
}
return 0;
}
printf("first value %s",arr[i][0]);
printf("second value is %s",arr[i][1]);
Basicly all you are doing is printing 2 chars from i word when you want to print full string you should do it like this: printf("%s",arr[i]); You said that value is separated by whitespace so when you are getting line from file you will save it to arr[i] (if first line in file contains "Hello World", your arr[0] will contain "Hello World") when you want to split it into 2 printf you need to print them char by char until space.
Edit: I reminded myself about function sscanf you can use it to get data from file array like you whould do it with keyboard input
You can use this to do that
Code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void){
char line[12][20];
char arr[20][20];
FILE *fptr=NULL;
int i=0;
fptr = fopen("file.txt", "r");
if(!fptr){
printf("cant open file\n");
exit(1);
}
while(fgets(*line, sizeof(line), fptr)){
strncpy(arr[i],*line, sizeof(*line));
i++;
}
for (int j=0;j<i;j++){
printf("%s\n", arr[j]);
}
return 0;
}
Notes and changes I made on your code:
Check fptr as return value of open() if it's NULL decide what to do.
Remove unnecessary tot variable and use another index j in last for loop.
Use strncpy() as a better version of strcpy()
Correct way of print arr, printf("%s\n", arr[j]);
\n can be embed on first printf()

Reading words into an array of strings?

Currently I'm reading each character from the user and storing it into a char array called str. From there I'm trying to use a pointer to loop through the string until it sees a space, once a space is seen I want to take the characters already and create an array of strings. Is that possible? Reasons why I'm doing this is because I later want to use an execlp function to execute a process after my initial program was executed.
If you want to split the string into tokens separated by delimiters you could use the strtok function.
An example would be:
#include <stdio.h>
#include <string.h>
int main(void)
{
int i, n;
char str[] = "Hello World";
char *token[4], *act_token;
token[0] = strtok(str, " ");
n=1;
while(n<4 && (act_token=strtok(NULL, " ")))
{
token[n] = act_token;
n++;
}
for(i=0;i<n;i++)
{
printf("%d: %s\n", i, token[i]);
}
return 0;
}

c, delete words which contain digits from a string

I need to delete all words that contain digits from the string.
E.g. if input is abdgh 67fgh 32ghj hj dfg43 11 fg, output should be abdgh hj fg.
I thought of using while( text[i] != ' '), but I don't know how to continue it for the rest of the string (after the first whitespace).
I don't have any other idea, and couldn't find anything by googling. Please, help me!
Here, i gave it a try. Works just fine for me. I tried to explain the logic throughout the code via comments. Hope it helps.
#include <stdio.h>
#include <string.h>
int containsNum(char * str);
int main()
{
char str[] = "abdgh 67fgh 32ghj hj dfg43 11 fg"; // input string
char newstr[100] = ""; //new string to create with filtered data
char * pch; //temp string to use in strtok
printf("given string : %s\n",str );
pch = strtok (str," ");
while (pch != NULL)
{
if(!containsNum(pch))// creation of new string with strcat
{ // if the current word not contains any number
strcat(newstr,pch);
strcat(newstr," "); //adding a space between words for readability
}
pch = strtok (NULL, " ");
}
printf("modified string : %s\n", newstr );
return 0;
}
//function containsNum
//gets a string and checks if it has any numbers in it
//returns 1 if so , 0 otherwise
int containsNum(char * str)
{
int i,
size =strlen(str),
flag=0;
for(i=0; i<size ; ++i)
{
if((int)str[i] >=48 && (int)str[i] <=57 ){
flag =1;
break;
}
}
return flag;
}
Regards
Algorithm:
1-You will have to break your input string into smaller components which are also called as tokens. For example: for the string abdgh 67fgh 32ghj hj dfg43 11 fg the tokens could be abdgh, 67fgh, 32ghj, hj, dfg43, 11 and fg.
2- These smaller strings or tokens can be formed using the strtok function which is defined as
char * strtok ( char * str, const char * delimiters );. Thestr in the first argument is the input sting which in the code presented below is string1. The second argument called the delimiters is what actually defines when to divide the input string into smaller pieces(tokens).
For instance, a whitespace as a delimiter will divide the input string whenever a whitespace is encountered, which is how the string is being divided in the code.
3-Since, your program needs to delete those words in the input string which contain digits we can use the isdigit() function to check exactly that.
WORKING CODE:
#include <cstring>
#include <ctype.h>
#include<stdio.h>
int main ()
{
char output[100]="";
int counter;
int check=0; /* An integer variable which takes the value of "1" whenever a digit
is encountered in one of the smaller strings or tokens.
So, whenever check is 1 for any of the tokens that token is to be ignored, that is,
not shown in the output string.*/
char string1[] = "abdgh 67fgh 32ghj hj dfg43 11 fg";
char delimiters[] = " ";//A whitespace character functions as a delimiter in the program
char * token;//Tokens are the sub-strings or the smaller strings which are part of the input string.
token=strtok(string1,delimiters);/*The first strktok call forms the first token/substring which for the input
given would be abdgh*/
while(token!=NULL)/*For the last substring(token) the strtok function call will return a NULL pointer, which
also indicates the last of the tokens(substrings) that can be formed for a given input string.
The while loop finishes when the NULL pointer is encountered.*/
{
for(counter=0;counter<=strlen(token)-1;counter++)/*This for loop iterates through each token element.
Example: In case of abdgh, it will first check for 'a',
then 'b', then 'd' and so on..*/
{
if(isdigit((int)token[counter])>0)/*This is to check if a digit has been encountered inside a token(substring).
If a digit is encountered we make check equal to 1 and break our loop, as
then that token is to be ignored and there is no real need to iterate
through the rest of the elements of the token*/
{
check=1;
break;
}
}
if(check==1) /* Outside the for loop, if check is equal to one that means we have to ignore that token and
it is not to be made a part of the output string. So we just concatenate(join) an
empty string ( represented by " " )with the output string*/
{
strcat(output,"");
check=0;
}
else /*If a token does not contain any digit we simply make it a part of the output string
by concatenating(joining) it with the output string. We also add a space for clarity.*/
{
strcat(output,token);
strcat(output," ");
}
token = strtok( NULL, delimiters ); /*This line of code forms a new token(substring) every time it is executed
inside the while loop*/
}
printf( "Output string is:: %s\n", output ); //Prints the final result
return 0;
}
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
char *filter(char *str){
char *p, *r;
p = r = str;
while(*r){
char *prefetch = r;
bool contain_digit = false;
while(!isspace(*prefetch) && *prefetch){
if(contain_digit)
++prefetch;
else if(isdigit(*prefetch++))
contain_digit = true;
}
if(contain_digit){
r = prefetch;
}else {
while(r < prefetch){
*p++ = *r++;
}
}
if(!*r)
break;
if(p[-1] == *r)
++r;
else
*p++ =*r++;
}
*p = '\0';
return str;
}
int main(void) {
char text[] = "abdgh 67fgh 32ghj hj dfg43 11 fg";
printf("%s\n", filter(text));//abdgh hj fg
return 0;
}

Strings in C Language

How can you code this in C language if the output is like this? I need strings format of the code because our topic is strings.
#include <stdio.h>
#include <stdlib.h>
void main()
{
char my_string[50];
printf("Enter a word:");
scanf("%s", my_string);
printf("Enter a word:");
scanf("%s", my_string);
// Some unknown code here...
// this part is my only problem to solve this.
getch();
}
Output:
Hello -> (user input)
World -> (user input)
HWeolrllod -> (result)
Okay, you need to do some investigating. We don't, as a general rule, do people's homework for them since:
it's cheating.
you'll probably get caught out if you copy verbatim.
it won't help you in the long run at all.
The C library call for user input that you should use is fgets, along the line of:
char buffer[100];
fgets (buffer, sizeof(buffer), stdin);
This will input a string into the character array called buffer.
If you do that with two different buffers, you'll have the strings in memory.
Then you need to create pointers to them and walk through the two strings outputting alternating characters. Pointers are not an easy subject but the following pseudo-code may help:
set p1 to address of first character in string s1
set p1 to address of first character in string s1
while contents of p1 are not end of string marker:
output contents of p1
add 1 to p1 (move to next character)
if contents of p2 are not end of string marker:
output contents of p2
add 1 to p2 (move to next character)
while contents of p2 are not end of string marker:
output contents of p2
add 1 to p2 (move to next character)
Translating that into C will take some work but the algorithm is solid. You just need to be aware that a character pointer can be defined with char *p1;, getting the contents of it is done with *p1 and advancing it is p = p + 1; or p1++;.
Short of writing the code for you (which I'm not going to do), there's probably not much else you need.
void main()
{
char my_string1[50],my_string2[50]; int ptr;
ptr=0;
printf("Enter a word : ");
scanf("%s",my_string1);
printf("enter a word");
scanf("%s",my_string2);
while(my_string1[ptr]!='\0' && my_string2[ptr]!='\0')
{
printf("%c%c",my_string1[ptr],my_string2[ptr]);
ptr++;
}
if(my_string1[ptr]!='\0')
{
while(my_string1[ptr]!='\0')
{ printf("%c",my_string1[ptr]);
ptr++;
}
}
else
{
while(my_string2[ptr]!='\0')
{printf("%c",my_string2[ptr]);
ptr++;
}
}
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main()
{
char my_string1[50],my_string2[50];
int i,l1=1,l2=0;
printf("Enter a word:");
scanf("%s", my_string1);
printf("Enter a word:");
scanf("%s", my_string2);
l1=strlen(my_string1); /* Length of 1st string */
l2=strlen(my_string2); /* Length of 2nd string */
if(l1==l2)
{
for(i=0;i<l1;i++)
{
printf("%c%c",my_string1[i],my_string2[i]);
}
}
else
{
printf("Length of the entered strings do not match");
}
}
This is your required code.
You can see that output needs to be a String containing all chars of User String1 and User String2 one by one...
You can do this like...
//add #include<String.h>
int l1=strlen(s1);
int l2=strlen(s2);
if(l1!=l2)
{
printf("length do not match");
return 0;
}
char ansstr[l1+l2];
int i,j=0,k=0;
for(i=0;i<l1+l2;i=i+2)
{
ansstr[i]=s1[j];
ansstr[i+1]=s2[k];
j++;
k++;``
}
//ansstr is your answer
Ok, here's your code. Come on guys, if he asked here it means he can't solve this.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char str1[] = "abcdefghijklmopq";
char str2[] = "jklm";
int len1 = strlen(str1);
int len2 = strlen(str2);
int c1 = 0, c2 = 0;
int max = (len1 > len2) ? len1 : len2 ;
char *result = malloc(len1 + len2);
for(c1 = 0; c1 <= max; c1++) {
if(c1 < len1)
result[c2++] = str1[c1];
if(c1 < len2)
result[c2++] = str2[c1];
}
result[c2] = 0;
printf("\n%s\n", result);
return 0;
}
Basically the loop picks up a character from str1 and appends it to result. Then it picks a character, which stands in the same position as the first from str2 and appends it to result, just as before. I increment c2 by 2 every time because I'm adding 2 chars to result. I check if c1 is bigger that the length of the strings because I want to copy only the characters in the string without the terminating \0. If you know that your strings have the same length you can omit these ifs.

Resources