parsing contents of string into substrings - c

I am trying to read in a string from a file, then parse the contents of the string to determine how many children to create with fork(), and send each child a section of the string.
int main() {
FILE * fp = fopen("Makefiletest", "r");
char * s;
int i;
char * e;
int c;
for (c = 0; c < 7; c++) {
fgets(s, 128, fp);
}
//e = strchr(s, ":");
//i = (int)(e - s);
//printf("index of : is %d\n", i);
printf("%s", s);
for (i = 0; s[i]; s[i]=='.' ? i++ : *s++);
printf("%d\n", i);
return 0;
}
which retrieves the line "maketools.a: parse.o find.o"
maketools.a is a 2nd generation child (that will have received the string "maketools.a" from its parent), and needs to create 2 new 3rd generation children one with the string "parse.o" the other with "find.o".
I ran into a dead end when I was unable to get the index of : due to segmentation faults (it is commented out and replaced with an attempt I was trying to do with counting instead of strings (it failed)), which prevented me from dividing up the string.
UPDATE
int main() {
FILE * fp = fopen("Makefiletest", "r");
char * s[256];
int i, index, ind;
char * e;
int c;
for (c = 0; c < 7; c++) {
fgets(s, 128, fp);
}
e = strchr(s, ":");
index = (int)(e - s);
printf("index of : is %d\n", index);
printf("%s", s);
return 0;
}
UPDATE 2
int main () {
char fgets_string[256];
char * fgets_string_ptr = fgets_string;
strcpy(fgets_string_ptr, " maketools.a: parse.o find.o ");
char depen[6][128]; //[0][] is root, 1+ are dependencies
char * depen_ptr;
int c;
while (isspace(* fgets_string_ptr)) {//removes leading whitepace
fgets_string_ptr++;
}
for (c = 0; strlen(fgets_string_ptr) > 0; c++) {
if (c == 0)
strtok_r(fgets_string_ptr, ":", &depen_ptr);
else {
strtok_r(fgets_string_ptr, " ", &depen_ptr);
}
while (isspace(* depen_ptr)) {//removes leading whitespace
depen_ptr++;
}
strcpy(depen[c], fgets_string_ptr);
strcpy(fgets_string_ptr, depen_ptr);
//printf("%s\n", depen[c]);
}
printf("%s\n", depen[0]);
printf("%s\n", depen[1]);
printf("%s\n", depen[2]);
return 0;
}

Below is a different approach to achieve what you want... Output of the code is
~/code/str % clang a.c -I../zstring -Wno-unused-value
~/code/str % ./a.out
maketools.a
parse.o
find.o
~/code/str %
Instead of locating the : character first and dealing with spaces, you can split your string into tokens by using (space) as the separator first, and then for the first string, you can remove : character.
The code below uses a string library I maintain, and can be downloaded from https://github.com/fnoyanisi/zString (available with BSD license)
#include <stdio.h>
#include <zstring.h>
int main(){
char s[]="maketools.a: parse.o find.o";
printf("%s\n",zStrrmv(zStrtok(s," "),":"));
printf("%s\n",zStrtok(NULL," "));
printf("%s\n",zStrtok(NULL," "));
return 0;
}

Related

Replace provided string with user input string?

I will preface this with the fact that this was once working. I added a print statement (now gone) that simply asked the user to input strings.
The input is done through the following method:
./Project aa b
aa was the code to be replaced, and b was going to be the letter replacing it for any occurrences in the user's input.
so for
./project Timmy Johhny
Timmy strolled through the park
the output would be
Johhny strolled through the park.
And as I said, it did work, and after it just printed spaces.
My code looks as follows:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * isMatch(char* os, char* ns, char* us){
int i;
int oslen, nslen, uslen;
int it = 0;
uslen = strlen(us);
oslen = strlen(os);
nslen = strlen(ns);
for(i=0; i < uslen; i++){
if(strstr(&us[i], os) == &us[i]){
it = it + 1;
i = i + oslen - 1;
}
}
char *ans = malloc(uslen + nslen * it);
int anslen = uslen + nslen * it;
i = 0;
while(*us){
if(strstr(us, os) == us){
strcpy(&ans[i], ns);
i = i + nslen;
us = us + oslen;
}
else
ans[i++] = *us++;
}
return ans;
}
int main(int arg1, char * argp[]){
char input[100];
int i;
char c;
while(1){
if(scanf("%c",&c)==EOF){
break;
}
if( (input[0]=c) != '\n'){
for(i=1;i<100;i++){
scanf("%c", &input[i]);
if(input[i] == '\n'){
break;
}
// char *match = isMatch(argp[1],argp[2],&input[i]);
// printf("%s", match);
// free(match);
}
char *match = isMatch(argp[1],argp[2],&input[i]);
printf("%s", match);
free(match);
}
}
}
Is there just a small error I made, or is it something larger.
I tried to move the printf in and out of a for loop amongst everything else, and simply got increasingly strange outputs.
Thank you!

Count words from a string with multiple empty spaces

I need code that can count the words from a string without counting multiple spaces between them.
I could code a program that counts the words with only 1 empty space between them, but I don't know how I should code it when it would be more than 1 empty space. I thought something like a for loop that checks if the char before it is a space, but I don't know how to do that. And I want to mention that I'm a beginner in C.
#include <stdio.h>
#include <string.h>
int main()
{
char s[200];
int count = 0, i;
printf("enter the string: ");
fgets(s,200,stdin);
for (i = 0;s[i] != '\0';i++)
{
if (s[i] == ' ')
count++;
}
printf("number of words in given string are: %d\n", count+ 1);
return(0);
}
You can introduce a flag to tell whether the previous character was a space. Something like:
#include <stdio.h>
#include <string.h>
int main()
{
char s[200];
int count = 0, i;
int last_was_space = 1;
printf("enter the string: ");
fgets(s,200,stdin);
for (i = 0;s[i] != '\0';i++)
{
if (s[i] == ' ')
{
if (!last_was_space)
{
count++; // Only count when last char wasn't a space
last_was_space = 1;
}
}
else
{
// Update flag (unless this char is a newline)
if (s[i] != '\n') last_was_space = 0;
}
}
if (!last_was_space) ++count; // Count the last word if there wasn't a space before
printf("number of words in given string are: %d\n", count);
return(0);
}
Framing the problem in general terms helps here. Don't think of it as "counting words", or "counting spaces". Think of it as counting "transitions from separator to non-separator". Defining our terms:
Separator: start of string, or a single ASCII space
Non-separator: everything else
Examples (^ is start of string, _ is a literal space, $ is end of string):
^a_quick_brown_fox_jumps$
^ ^ ^ ^ ^ 5 transitions
^_a__quick___brownfox_jumps___$
^ ^ ^ ^ 4 transitions
^$
0 transitions
^___$
0 transitions
^__x$
^ 1 transition
Now in psuedo code:
def is_separator(char x):
return (x == NULL or x == ' ')
def is_non_separator(char x):
return (! is_separator(x))
let count = 0, last_char = NULL
while current_char = read_char():
if (is_non_separator(current_char) and is_separator(last_char)):
count++
From here, you can translate into specific languages or change the meaning of separators without affecting the logic of counting.
A bit more universal
size_t wcount(const char *s, const char *del, int countempty)
{
char *token;
size_t count = 0;
char *str = strdup(s);
if(str)
{
token = strtok(str, del);
while( token != NULL )
{
if(!strlen(token))
{
if(countempty)
{
count++;
}
}
else
{
count++;
}
token = strtok(NULL, del);
}
}
free(str);
return count;
}
int main ()
{
char str[] = "something to count ,., , . !! Stack overflow ";
printf("With empty %zu, Without empty%zu\n", wcount(str," ", 1), wcount(str," .,", 0));
}
count the words from a string without counting multiple spaces between them
Set a flag to determine if the beginning of a word is possible. Fewer special cases than looking for the end of the word.
Typically the requirement for "spaces" implies any white-space, then the task is easily coded:
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
int main(void) {
char s[200];
printf("enter the string: ");
fgets(s, sizeof s, stdin);
int count = 0;
bool beginning_of_word_possible = true;
for (const char *p = s; *p; p++) {
if (isspace((unsigned char ) *p)) {
beginning_of_word_possible = true;
} else {
if (beginning_of_word_possible) {
count++;
}
beginning_of_word_possible = false;
}
}
printf("number of words in given string are: %d\n", count);
return (0);
}
#P__J__ offered a good idea that passes in a list of delimiters. Below is a similar and short solution that does not allocate memory nor change the supplied string.
#include <string.h>
size_t word_count(const char *s, const char *delimiters) {
size_t count = 0;
while (*(s += strspn(s, delimiters))) { // Advance s by the matching delimiters.
count++;
s += strcspn(s, delimiters); // Advance s by the non-matching delimiters.
}
return count;
}
Test
int main(void) {
const char *de = " \n";
printf("%zu\n", word_count("", de));
printf("%zu\n", word_count("\n", de));
printf("%zu\n", word_count(" ", de));
printf("%zu\n", word_count("abc", de));
printf("%zu\n", word_count(" abc", de));
printf("%zu\n", word_count(" abc \n", de));
printf("%zu\n", word_count("abc xyz", de));
printf("%zu\n", word_count(" abc xyz", de));
printf("%zu\n", word_count(" abc xyz \n", de));
}
Output
0
0
0
1
1
1
2
2
2
Short and Simple Version:
#include <stdio.h>
int main(void) {
char str[] = " Hello, This is a test of a word counter";
int i = 0;
for(char* s=str; strtok(s," "); i++) s = NULL;
printf("number of words in given string are: %d\n", i);
return 0;
}
Output
Success #stdin #stdout 0s 9424KB
number of words in given string are: 9

How to split a string into int[3]

I have a string, like "101 1 13" and I need to split it to a int aux[3] --> resulting in aux[0] = 101, aux[1] = 1 and aux[2] = 13 (in this case). How can
I do that?
In the example of the code below I get op as a String and want to get the value of the INTs in there. Each int is divided in the string by a white space(" ").
Another detail: I need the code to compile with flag -std=c99, so the answer that was accepted would not work.
#include <stdio.h>
#include <stdlib.h>
//example of str = "101 1 14" (char *)
// example of output = {101, 1, 14}(int *)
int* stoi(char *str) {
// function to split str into 3 ints
}
int main() {
char op[10];
int num[3];
scanf("%s\n", op);
num = stoi(op);
printf("%d %d %d", num[0], num[1], num[2]);
return 0;
}
First you need to tokenize your input (break apart the input into distinct elements). Then you need to parse/integerize the individual tokens by converting them from strings to the desired format.
Sample Code
#include <stdio.h>
#include <string.h>
#define BUF_LEN (64)
int main(void)
{
char buf[BUF_LEN] = { 0 };
char* rest = buf;
char* token;
int i = 0;
int iArr[100] = { 0 };
if ( fgets(buf, BUF_LEN, stdin) != NULL )
{
strtok(buf, "\n"); // Remove newline from input buffer in case we want to call fgets() again.
while ( (token = strtok_r(rest, " ", &rest)) != NULL )
{
iArr[i] = strtol(token, NULL, 10);
printf("Token %d:[%d].\n", i, iArr[i]);
i++;
}
}
return 0;
}
Sample Run
1231 12312 312 1232 1312
Token 0:[1231].
Token 1:[12312].
Token 2:[312].
Token 3:[1232].
Token 4:[1312].
Try to replace your code by following code.
The new code works only if input contains only single space between integers.
Your code:
while(op[cont] != '\0') {
for(i = 0; op[cont] != ' '; i++, cont++) {
num[i] += op[cont];
}
printf("num[i] = %d\n", num[i]);
}
New code:
while(op[cont] != '\0')
{
if(op[cont] != ' ')
num[i] = num[i]*10 + (op[cont]- '0');
else
i++;
cont++;
}
See this example of how to do that:
char string [10] = "101 1 666"
int v [3], n=0, j=0;
int tam = strlen(string);
int current_Len = 0;
for(i=0; i<tam; i++){
//32 = ascii for White space
if(string[i] != 32){
n = n*10 + string[i] - '0';
current_len++;
} else if (current_len > 0){
v[j++] = n;
current_len = 0;
n=0;
}
}
if (current_len > 0){
v[j++] = n;
}
This answer is assuming you know how much integers your string contain at the time of writing your code. It also uses specific clang/gcc extension (typeof) and may not be portable. But it may be helpful to someone (I mainly wrote it because I had nothing good to do).
#include <stdio.h>
#include <string.h>
struct {int _[3];} strToInt3(const char (*pStr)[])
{
int result[3] = {0}, *pr = result;
for(register const char *p = *pStr; *p; ++p)
{
if(*p == ' ') ++pr;
else
*pr *= 10,
*pr += *p - '0';
}
return *(__typeof__(strToInt3(0)) *)result;
}
int main()
{
char op[10];
int num[3];
scanf("%10[^\n]", op),
//memcpy(num, strToInt3(op)._, sizeof(num));
//or
*(__typeof__(strToInt3(0)) *)num = strToInt3(op);
printf("%d %d %d", num[0], num[1], num[2]);
}
I've commented the copying of returned array using memcpy and added a structure assignment. Although both must be valid (not standard I guess but working in most cases) I prefer the second option (and maybe some compiler optimizers will).
Also I assume ASCII character set for chars.
I found an easier approach to the problem. I insert a scanf, that don't catch the space blanket and convert it using atoi. As it is just 3 ints it doesn't become so bad to use this simple, repetitive way of catching the values. And it work with the -std=c99 flag, that I needed to use.
scanf("%s[^ ]\n", op);
num[0] = atoi(op);
scanf("%s[^ ]\n", op);
num[1] = atoi(op);
scanf("%s[^ ]\n", op);
num[2] = atoi(op);
printf("%d\n", num[0]);
printf("%d\n", num[1]);
printf("%d\n", num[2]);

Replacing a substring in a string - c

I'm trying to do a program which finds a substring in a string and replaces it with another substring entered by user. My code doesn't give a compile or run-time error, but it just doesn't work. I put printfs in the while loop which I wrote a comment line near it, and the program doesn't go into first if -I put another comment line near it. It prints a, h and i. The other parts in loop aren't working. Here's my code:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
char *findAndReplace(char *sentence, char *word1, char *word2);
void main()
{
char sentence[1000];
char word1[200];
char word2[200];
int length;
printf("Please enter a sentence: ");
gets(sentence);
printf("Please write the word to be replaced: ");
gets(word1);
printf("Please write the word to be put instead: ");
gets(word2);
findAndReplace(sentence, word1, word2);
system("pause");
}
char* findAndReplace(char *sentence, char *word1, char *word2)
{
char *search, *tempString[1000];
int a, b, c, d, i = 0, j, sentenceLength, word1Length, searchLength;
sentenceLength = strlen(sentence);
printf("Length of %s is %d\n", sentence, sentenceLength);
printf("Finding ");
puts(word1);
search = strstr(sentence, word1);
searchLength = strlen(search);
word1Length = strlen(word1);
strcpy(tempString, sentence);
if(search != NULL)
{
printf("Starting point: %d\n", sentenceLength - searchLength);
}
else
{
printf("Eşleşme bulunamadı.\n");
}
j = 0;
while(j < sentenceLength + 1) //This loop
{
printf("a");
if(word1[i] == tempString[j])
{
printf("b");
if(i == word1Length)
{
c = j;
printf("c");
for(d = 0; d < word1Length; d++)
{
tempString[c - word1Length + d + 1] = word2[d];
printf("d");
}
i = 0;
j++;
printf("e");
}
else
{ printf("f");
i++;
j++;
}
printf("g");
}
else{
printf("h");
i = 0;
j++;
}
printf("i");
}
puts(tempString);
}
You've made a decent start, but you're making this a lot harder than it needs to be. One way to minimize errors is to rely on standard library functions when there are any that do the work you need done. For example:
char tempString[1000];
char *search;
search = strstr(sentence, word1);
if (search) {
ptrdiff_t head_length = search - sentence;
int sentence_length = strlen(sentence);
int word1_length = strlen(word1);
int word2_length = strlen(word2);
if (sentence_length + word2_length - word1_length < 1000) {
/* construct the modified string */
strncpy(tempString, sentence, head_length);
strcpy(tempString + head_length, word2);
strcpy(tempString + head_length + word2_length, search + word1_length);
/* copy it over the original (hope it doesn't overflow!) */
strcpy(sentence, tempString);
} else {
/* oops! insufficient temp space */
}
} /* else the target word was not found */
That covers only the search / replacement bit, fixing the error in tempString's type first pointed out by iharob. Also, it replaces only the first occurrence of the target word, as the original code appeared to be trying to do.
Among other things you have declared tempString as char* tempString[1000] which is an array of uninitialized character pointers so when you do
strcpy(tempString, sentence);
you are basically getting undefined behavior.
Use also fgets instead of gets when you input strings - even though you have rather large buffers it can happen one day that you pipe in a text file and get a stack overflow.
If I were you I would use strtok and split your sentence in words, then check each word. If word is same replace otherwise add sentence word to a new string.
e.g.
char newString[1000] = {0};
for (char* word = strtok(sentence, " "); word != NULL; word = strok(NULL, " "))
{
if (!strcmp(word, word1)) // here you may wanna use strncmp or some other variant
{
strcat(newString, word2);
}
else
{
strcat(newString, word);
}
strcat(newString, " ");
}
newString[strlen(newString)-1] = '\0';

My comparison of two strings for a hangman game doesn't work properly

I've been working on a hangman game for a class course and I'm almost done. However, I've stumbled upon a problem that I can't seem to fix.
First, the computer choose a random word from a text file, takes the lenght of that word and with that length creates a masked copy of the original word. Then the game start. The player types in letters and if the word is completed before he/she fails six times, he wins. Otherwise, he/she loose. I think the problem with my code is when I create my mask of the word chosen by the computer, but I'm not sure.
If I run the program it looks something like this:
Chosen word: strand (first control of word chosen by computer)
Chosen word: strand (second control to see if the same word is copied from the function to the string in the main)
Chosen word: monster (this is printed by the free() function. for some reason it's one word higher)
Chosen word: strand (third control is done before the lenght of the word is copied, in order to see if it's the right word being copied, which it is)
Wordlenght: 6 (control to see if the lenght matches the word, which it does)
Mask: _ _ _ _ _ _ N (ignore the spaces between the underscores, they are only there to make it easier to see. this is where i think the problem is, because of the extra character added in the end, the "N" in this case. the number of underscores match the number of letters which is good)
Mask: _ _ _ _ _ _ N (printed by the second free() function)
Then the actual game starts. Everything else works fine (if the player aborts or looses and if the player wants or doesn't want to play again). I checked if the actual strcmp() in the int resultat (char* word, char* mask, int count) function worked, and it did. So the fault has be with the strings being compared. I think it's when I get the lenght of the chosen word with strlen(). When I get the length, I subtract with one because otherwise I would get a lenght which is too long(for example, paper would give a lenght of 6, but when I subtract with one I get 5).
If someone could help me or maybe give me some hints I would be very grateful!
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
#include<time.h>
#define MAX_WORD_LEN 20
char* datorns_val();
int ordlengd(char* word);
char* datorns_val_mask(char* word, int len);
int spel(char* word, char* mask, int len, int count, int result);
int resultat (char* word, char* mask, int count);
char get_user_choice();
void hangman(int count, int result);
const int MAX_GUESS = 6;
const char ABORT_CH = '0';
const int LOOSE = 0;
const int WIN = 1;
const int ABORTED = 2;
/************************************************************
*
* MAIN
*
*
************************************************************/
int main ()
{
char word[MAX_WORD_LEN];
char mask[MAX_WORD_LEN];
int ch;
int len;
int result;
int count;
/* -------------------- Programstart -----------------*/
srand(time(NULL));
while (true)
{
result = 5;
count = 0;
strcpy(word,datorns_val());
printf("Valt ord 2: %s", word);
free(datorns_val());
len = ordlengd(word);
strcpy(mask,datorns_val_mask(word,len));
printf("\nMask 2: %s <-----", mask);
free(datorns_val_mask(word,len));
printf( "\nV\x84lkommen till HANGMAN 2014!\n");
printf( "Du har %d gissningar p\x86 dig (avbryt med 0)\n", MAX_GUESS );
printf( "Datorn har nu valt ett ord p\x86 %d bokst\x84ver\n", len );
/* GAME MAIN LOOP */
while (count < 6)
{
count=spel(word,mask,len,count,result);
result=resultat(word,mask,count);
hangman(count,result);
}
/* END MAIN GAME LOOP */
if( result == WIN )
{
printf("\nGrattis du vann!\n");
}
else if( result == LOOSE )
{
printf("\nTyv\x84rr du f\x94rlorade! Ordet var: %s\n", word);
}
else
{
printf("Avbrutet\n");
}
printf("Vill du spela igen? (j/n)");
ch = get_user_choice();
if (ch == 'n' || ch == 'N')
{
break;
}
}
}
/***********************************************************
*
* --------- Funktionsdefinitioner ----------------
*
***********************************************************/
char get_user_choice()
{
char tkn;
scanf(" %c", &tkn);
return tkn;
}
char* datorns_val()
{
char ordlista[20];
char* valt_ord = malloc(20);
int random;
int raknare = 0;
random = rand()%4+1;
FILE *ptr_file;
ptr_file =fopen("hangman.dat","r");
if (!ptr_file)
{
printf("Filen kunde inte öppnas!");
}
while (fgets(ordlista,20, ptr_file)!= NULL)
{
if (raknare == random)
{
strcpy(valt_ord, ordlista);
break;
}
raknare=raknare+1;
}
printf("Valt ord 1: %s",valt_ord);
fclose(ptr_file);
return valt_ord;
}
int ordlengd(char* word)
{
printf("Valt ord 3: %s", word);
int ordlengd;
ordlengd=strlen(word)-1;
printf("Ordlengd 1: %i", ordlengd);
return ordlengd;
}
char* datorns_val_mask(char* word, int len)
{
int j;
char* gissning = malloc(20);
for (j=0; j<len; j++)
{
gissning[j]='_';
}
printf("\nMask 1: %s <----", gissning);
return gissning;
}
int spel(char* word, char* mask, int len, int count, int result)
{
int j;
char bokstav;
int ratt = 0;
printf("\nSkriv en bokstav: ");
scanf(" %c", &bokstav);
for(j=0; j<len; j++)
{
if(bokstav==word[j])
{
mask[j]=bokstav;
ratt = 1;
}
else if(bokstav=='0')
{
count = 7;
return count;
}
}
if (ratt == 0)
{
printf("\nBokstaven finns inte i ordet!\n");
count=count+1;
}
printf("Antal fel: %i\n\n", count);
ratt = 0;
for (j=0; j<len; j++)
{
printf("%c", mask[j]);
printf(" ");
}
return count;
}
void hangman(int count, int result)
{
const char* str[20];
int j;
str[0]="\n_______ \n";
str[1]=" | \n";
str[2]=" O \n";
str[3]="//|\\\\\n";
str[4]=" | \n";
str[5]="// \\\\\n";
if(result != ABORTED)
{
for (j=0; j<count; j++)
{
printf("%s", str[j]);
}
}
}
int resultat (char* word, char* mask, int count)
{
char* a = "Hej";
char* b = "Hej";
if (count == 6)
{
return LOOSE;
}
else if (count < 6 && strcmp(mask,word) == 0)
{
return WIN;
}
else if (count == 7)
{
return ABORTED;
}
}
There are some things around the code:
1) The first free() call in pointless:
free(datorns_val());
This reserves memory for a string and deletes it without making any use of it. So get rid of it.
2) Using fgets() to read strings from a file stores also the '\n' character at the end of the line into your string, so you must get rid of it. As a hint, I have used this sentence:
while(fscanf(ptr_file,"%s", ordlista) >0)
that does not store '\n' characters.
3) In ordlengd(char* word) function, you had problem with an extra character (the above mentioned '\n') so the length is the same as the one returned by strlen(), not the
strlen(word) - 1
you had written.
4) You have think about another condition to end the while loop of the main function. I would suggest to add
else return 5;
at the end of resultat() function and the check this value en the while loop of the main function
while (count < 6 && result == 5)
Hope it helps

Resources