Replacing a substring in a string - c - 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';

Related

I am writing a code about replacing a word in a string with another word and removing repeats. Cannot finish it but got half to work [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
//This function converts a string to a sentence.
void
StrtoSent(char *string)
{
int length = 0,n = 0;
length = strlen(string);
for(n = 0; n < length; n++){
if((n ==0) && (string[n] >= 'b' && string[n] <= 'y')){
string[n] = string[n] - 32;
}
else if(string[n] == '.'){
if(string[n + 1] == ' '){
if(string[n+2]>= 'b' && string[n+2]<= 'y'){
string[n+2]= string[n+1] - 32;
}
}
}
}
}
int
main(void)
{
char string[50] = {0};
int length = 0,n = 0,a = 0,d = 0;
printf("\n\nEnter a wordstring Neo: ");
gets(string);
StrtoSent(string);//Here,we send the string off to the function
char str[] = "The xitraM is acutally the Matrix!";
char j[] = "xitraM";
char e[] = "Matrix";
char *result = NULL;
printf("Original string: %s\n",str);
printf("The converted sentence: %s",string);
char input[200];
getchar();
fflush(stdin);
fgets(input,200,stdin);
char c;
if (isdigit(c)) {
int n = c - '0'; //'0'-'9' -> 0 - 9
printf("%c is coverted to %d\n",c,n);
}
while((c=getchar()) != EOF) {
if(islower(c))
printf("%c will be converted to %c\n",c,toupper(c));
if(isupper(c))
printf("%c in lowercase is %c\n",c,tolower(c));
getchar();
}
}
How do I replace the word xitraM and get it to be like this output:
The xirtaM is actually the MATRIX!
Converted sentence:
The Matrix is actually the MATRIX!
Original:
a blACk cAT is in the xirtaM.
Converted sentence:
A Black Cat is in the Matrix.
My code allows you
so far to enter a wordstring and it will return a string, and it will
fix the //code if there are capitals in the wrong place and if the
punctuation is wrong, but I cannot seem to get the code to replace
xitraM with Matrix and I am stuck on that.
Some help would be great -- thanks!
This is prefaced by my top comments.
There are many issues with the code.
Never use gets--the man page for it says to not use it [and why].
Your main is reading a line but not doing much with it.
The loop at the bottom doing getchar makes no sense because you've already read the line with the fgets above. It looks like you're trying to preview the capitalization.
For the word substitution, use two buffers. An input and a separate output buffer. Although xirtaM and Matrix are the same length, using separate buffers allows the length of the strings to differ (i.e. it's more general).
You can loop through the input using strstr to find the "bad" string. Then, copy over the partial string that precedes it. Skip the bad string in the input. Then, copy over the "good" string to the output.
Your capitalization function makes no sense [and appears to do nothing].
Also, converting the "black cat" string, from your example isn't general because it would need to special case "cat" to produce "Cat". For English, "cat" is not a proper name, so it should be all lowercase.
Unfortunately, your code needed some heavy refactoring in order to work.
I had to change the capitalization function to just capitalize the first char of the first word of each sentence as that was the only thing that made sense to me [adjust to suit your needs].
I wired in your two test cases. And, I've added some debug printf statements.
Anyway, here's the code. I've annotated it, so that the part you had an issue with [the word substitution] should give you some ideas.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
//This function converts a string to a sentence.
void
StrtoSent(char *string)
{
int length = 0,n = 0;
length = strlen(string);
for(n = 0; n < length; n++){
if((n ==0) && (string[n] >= 'b' && string[n] <= 'y')){
string[n] = string[n] - 32;
}
else if(string[n] == '.'){
if(string[n + 1] == ' '){
if(string[n+2]>= 'b' && string[n+2]<= 'y'){
string[n+2]= string[n+1] - 32;
}
}
}
}
}
// fixcap -- capitalize sentences in the string
void
fixcap(char *string)
{
int capflg = 1;
while (1) {
int chr = *string;
// end of string
if (chr == 0)
break;
switch (chr) {
case ' ':
break;
case '.': // end of sentence -- restart capitalization
case '!':
capflg = 1;
break;
default:
// capitalize the [first letter of the] first word of a sentence
if (capflg) {
chr = toupper((unsigned char) chr);
capflg = 0;
}
else
chr = tolower((unsigned char) chr);
break;
}
*string++ = chr;
}
}
// fixword -- substitute word in string
void
fixword(char *out,const char *inp,const char *bad,const char *good)
{
int lenbad = strlen(bad);
int lengood = strlen(good);
char *cp;
int lencpy;
while (1) {
// find the "bad" string in the input
cp = strcasestr(inp,bad);
// the remaining input string is good -- copy it
if (cp == NULL) {
strcpy(out,inp);
break;
}
// get the length of the string leading up to the "bad" string
// copy it over and advance the pointers
lencpy = cp - inp;
memcpy(out,inp,lencpy);
inp += lencpy;
out += lencpy;
// skip over the bad string in the input
inp += lenbad;
// copy over the "good" string and advance the output pointer
strcpy(out,good);
out += lengood;
}
}
// fixall -- perform all actions
void
fixall(const char *string)
{
char inp[1000];
char out[1000];
strcpy(inp,string);
printf("DEBUG: BEFORE '%s'\n",inp);
//Here,we send the string off to the function
#if 0
StrtoSent(inp);
printf("DEBUG: AFTCAP '%s'\n",inp);
#endif
#if 1
fixcap(inp);
printf("DEBUG: AFTCAP '%s'\n",inp);
#endif
fixword(out,inp,"xirtaM","Matrix");
printf("DEBUG: AFTFIX '%s'\n",out);
}
// doline -- read and process an input line
int
doline(void)
{
char *cp;
char string[1000];
int more;
do {
printf("\n\nEnter a wordstring Neo: ");
cp = fgets(string,sizeof(string),stdin);
more = (cp != NULL);
if (! more)
break;
// strip newline
cp = strchr(string,'\n');
if (cp != NULL)
*cp = 0;
fixall(string);
} while (0);
return more;
}
int
main(void)
{
#if 0
char string[50] = {0};
int length = 0,n = 0,a = 0,d = 0;
#endif
// default test cases
fixall("The xirtaM is acutally the Matrix!");
fixall("a blACk cAT is in the xirtaM.");
// read input lines and do conversions
while (1) {
if (! doline())
break;
}
#if 0
char str[] = "The xirtaM is acutally the Matrix!";
char j[] = "xirtaM";
char e[] = "Matrix";
char *result = NULL;
printf("Original string: %s\n",str);
printf("The converted sentence: %s",string);
char input[200];
getchar();
fflush(stdin);
fgets(input,200,stdin);
char c;
if (isdigit(c)) {
int n = c - '0'; //'0'-'9' -> 0 - 9
printf("%c is coverted to %d\n",c,n);
}
while((c=getchar()) != EOF) {
if(islower(c))
printf("%c will be converted to %c\n",c,toupper(c));
if(isupper(c))
printf("%c in lowercase is %c\n",c,tolower(c));
getchar();
}
#endif
return 0;
}
Here is the program output for the default test cases:
DEBUG: BEFORE 'The xirtaM is acutally the Matrix!'
DEBUG: AFTCAP 'The xirtam is acutally the matrix!'
DEBUG: AFTFIX 'The Matrix is acutally the matrix!'
DEBUG: BEFORE 'a blACk cAT is in the xirtaM.'
DEBUG: AFTCAP 'A black cat is in the xirtam.'
DEBUG: AFTFIX 'A black cat is in the Matrix.'

C Programming: alternative way of creating a test string and letting the user search for the character within the string vs source code

This lab is trying to show the use of coder-defined functions to execute the code, but I'm trying to do it alternatively so when we actually are tested on it I won't be freaking out that I just copied the source code.
#define NotFound -1
#define WordSize 20
int stringSearch(char * string, char array, int * letter);
int main(void)
{
char * string = (char *) malloc(WordSize * sizeof(char));
char tester = '\0';
int index_tester = 0, i;
// do
// {
// printf("Enter a test string and character, enter q for the test string to exit.\n");
// printf("Test string: ");
// scanf("%s", string);
// while (getchar() != '\n') {}
// if (strcmp(string, "q") == 0) {
// break;
// }
// } // ----> Is it possible to do a while or for look instead? loop here?
printf("What is the test string you wish to enter: ?");
for (i = 0; i < sizeof(string); i++)
{
{
scanf("%c", &string[i]);
}
}
string[i] = '\0';
puts(string);
printf("Tester for the inputed string: ");
scanf("%c", &tester);
while (getchar() != '\n') {}
int ResultofSearch = stringSearch(string, tester, &index_tester);
if (ResultofSearch == NotFound)
{
printf("That letter is not foudn in the string, try again: ");
}
else {
printf("Character found at index %d.\n\n", index_tester);
}
return 0;
}
int stringSearch(char * string, char array, int * letter)
{
for (int i = 0; i < strlen(string); i++)
{
if (string[i] == array)
{
*letter = i;
return (Found);
}
}
return(NotFound);
}
When executing the code, I can put in the string, which I think is working fine, but it will automatically put in the search for some random letters immediately without prompting for the user input. I'm still a greenhorn to all this coding stuff so sorry in advance, any advice would be appreciated though
Apart from the issues pointed out in the comments there is some things you should improve:
char * string = (char *) malloc(WordSize * sizeof(char)); is the same as char * string = malloc(WordSize), but for a 20 word string we will need char * string = malloc(WordSize + 1)
This part of the code:
for (i = 0; i < Wordsize; i++) // already corrected
{
{
scanf("%c", &string[i]);
}
}
string[i] = '\0';
This will obligate you to always have a 19 character string. The cycle will not end until you do (you replace the 20th character with the null-terminator).
You can replace the whole thing with:
fgets(string, WordSize + 1, stdin);
And for good measure, discard the extra characters when the input is too big to fit the string.
int c;
while((c = fgetc(stdin)) !='\n' && c =! EOF); //discard until newline, for completion check for EOF return
This will allow a 20 character max size string but also for smaller ones.
Working sample
You should add required headers, use fgets() rather than scanf() and set tester_index to -1 rather than 0 which means found at index 0.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Found 1
#define NotFound 0
#define WordSize 20
int stringSearch(char * string, char array, int * letter);
int main(void)
{
char * string = (char *) malloc(WordSize * sizeof(char));
//char tester = '\0';
char tester[2] = {'\0', '\0'};
int index_tester = -1; // 0 means found # index 0
/* (...) */
printf("What is the test string you wish to enter: ?\n");
fgets(string, WordSize, stdin);
if (string[WordSize-1]=='\n')
string[WordSize-1]='\0';
puts(string);
printf("Tester for the inputed string: \n");
while (getchar() != '\n') {}
///scanf("%c", &tester[0]);
fgets(tester, 2, stdin);
int ResultofSearch = stringSearch(string, tester[0], &index_tester);
if (ResultofSearch == NotFound)
{
printf("That letter is not found in the string.\n");
}
else {
printf("Character found at index %d.\n\n", index_tester);
}
return 0;
}
int stringSearch(char * string, char c, int * index)
{ ... }
It's definitely not perfect but works more less expected way.

Issue with Strings in C

Here is a program with Strings where I am trying
Pig Latin translation is simply taking the first letter of a “word” and appending that letter to the end of the word with “ay” added to the end as well
I have issue with m1=m2+3 ( resetting the Initial Marker ).
Input that I am giving : "Alex, how are you right"
The output I am expecting is : lexay, owhay reay ouyay ightray
But
I am getting this : lex,Aay way ay ayo gayi
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
void initialize(char english[], char piglatin[]);
void readinput (char english[]);
int countwords(char english[]);
void convert ( int words, char english[], char piglatin[]);
void writeoutput( char piglatin[]);
int main()
{
char english[80], piglatin[80];
int words;
initialize(english, piglatin);
printf("enter the string\t");
fflush(stdin);
gets(english);
printf ("\nInput buffer contents: %s\n", english);
words = countwords(english);
convert(words,english,piglatin);
writeoutput(piglatin);
printf ("Have a nice day\n");
}
void initialize(char english[], char piglatin[])
{
int count;
for(count =0; count<80;++count)
{
english[count]=piglatin[count]=' ';
}
return;
}
/* Scan the english test and determine the number of words */
int countwords(char english[])
{
int count, words =1;
for ( count =0;count <79;++count)
{
if(english[count]==' ' && english[count+1]!=' ')
++words;
}
printf("%d\n",words);
return (words);
}
/* convert each words in to piglatin*/
void convert ( int words, char english[], char piglatin[])
{
int n, count;
int m1=0;
int m2;
/* convert each word */
for ( n=1;n<=words;++n)
{
/* locate the end of the current word*/
count = m1;
printf ("\ before conversion word contents: %d\n", count);
while ( english[count]!=' ')
{
m2=count++;
}
printf ("\ before conversion word contents: %d\n", m2);
/* transpose the first letter and add 'a', 'y'*/
for (count =m1;count<m2;++count)
{
piglatin[count+(n-1)]=english[count+1];
}
piglatin[m2+(n-1)] = english[m1];
piglatin[m2+1] = 'a';
piglatin[m2+2] = 'y';
m1=m2+3;
printf ("\ Converted word contents: %s\n", piglatin);
}
return;
}
void writeoutput( char piglatin[])
{
int count =0;
for (count =0; count <80; ++count)
{
putchar(piglatin[count]);
}
printf ("\n");
return;
}
I see various problems here:
Alex -> lex,Aay: You should check for punctuation marks when determining the end of the words, thus inserting the Aay part before the comma character
Alex -> lex,Aay: Every character from the start of a word should be converted to lowercase and the resulting first character should be converted to upper case respectively
Now the conversion function: I have changed it a bit to get you started; it should work now ( at least it does with your test string ) without taking 1 and 2 into account though
void convert(int words, char english[], char piglatin[])
{
int estart = 0;
int ppos = 0;
int m2;
for (int n = 0; n < words; n++)
{
//locate the start of the current word, to make
//sure something like this is converted:
//"Alex, how are you"
while (english[estart] == ' ')
{
//make sure we do not exceed the strings boundaries!
if (english[estart] == '\0')
{
return;
}
estart++;
}
//locate the end of the word
int eend = estart;
while (english[eend] != ' ')
{
//never forget to check for the end of the string
if (english[eend] == '\0')
{
break;
}
eend++;
}
/* transpose the first letter and add 'a', 'y'*/
for (int i = estart+1; i < eend; i++, ppos++)
{
piglatin[ppos] = english[i];
}
piglatin[ppos++] = english[estart];
piglatin[ppos++] = 'a';
piglatin[ppos++] = 'y';
//dont forget to add a whitespace or your string might behave
//very stangely!
piglatin[ppos++] = ' ';
estart = eend;
printf("\ Converted word contents: %s\n", piglatin);
}
}
I hope this gets you started in the right direction.
Please also check your array sizes for english and piglatin. The string for piglatin is alway longer than the english one but your array sizes are the same! Also i would advise you add some boundary checks to make sure you do not leave the array boundaries.

Concatenating strings using a variable arguments function

I made a program which receives from 2 till 5 strings and concatenate all together using a variable arguments function.
So far the program works OK, but it always show at the end 3 random characters before showing the complete string.
For example:
Please insert number of strings: 3
string 1: car
string 2: bike
string 3: plane
Full string:
=$>carbikeplane
I have made several tweaks to the program trying to find the reason and fix it, however I always get the same result.
The full program is showed below.
Few comments about the program:
I am printing the strings in different parts of the programs because I was trying to locate where the problem was coming. So some of the printf() functions may not have sense.
The main function seems to be fine, the problem is in the function defined later.
NOTE: I'm still learning C, so there may be some code that can/might be creating undefined behavior, if there is, I would appreciate if you can point those out.
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
char *function(int num, ...);
int main(void)
{
char line1[80] = " ", line2[80] = " ", line3[80] = " ", line4[80] = " ", line5[80] = " ";
int count = 0, count2;
char *newStr;
int i;
int status;
do {
fflush(stdin);
printf("\nPlease select the number of strings (max. 5): ");
scanf("%d", &count);
}while(count < 2 && count > 5);
count2 = count;
fflush(stdin);
status = 1;
for( i = 1 ; count > 0; count--, i++)
{
switch(status)
{
case 1:
{
printf("\nInput string[%d]: ", i);
gets(line1);
status = 2;
break;
}
case 2:
{
printf("\nInput string[%d]: ", i);
gets(line2);
status = 3;
break;
}
case 3:
{
printf("\nInput string[%d]: ", i);
gets(line3);
status = 4;
break;
}
case 4:
{
printf("\nInput string[%d]: ", i);
gets(line4);
status = 5;
break;
}
case 5:
{
printf("\nInput string[%d]: ", i);
gets(line5);
status = 6;
break;
}
}
}
printf("\n%s\n%s\n%s\n%s\n%s\n", line1, line2, line3, line4, line5);
/*call the function of variable arguments*/
/*memory allocation of newstr*/
newStr = (char *)malloc(420*sizeof(char) +1);
switch(count2)
{
case 2:
{
newStr = function(2, line1, line2);
break;
}
case 3:
{
newStr = function(3, line1, line2, line3);
break;
}
case 4:
{
newStr = function(4, line1, line2, line3, line4);
break;
}
case 5:
{
newStr = function(5, line1, line2, line3, line4, line5);
}
}
printf("\nThe final string is: \n");
printf("%s", newStr);
return 0;
}
char *function(int num, ...)
{
va_list arg_ptr;
int b;
char *string;
char *curstr;
va_start(arg_ptr, num); /*initialize the arg_ptr*/
string = (char *)malloc(420*sizeof(char) + 1);
*string = " ";
for(b=0; b < num; b++)
{
curstr = va_arg(arg_ptr, char * );
string = strcat(string,curstr);
}
printf("\n%s", string);
va_end(arg_ptr);
return string;
}
The real problem is that you can compile the line: *string = " "; This is not valid anymore and should not compile. Assumingly you put that line there to initialize your string to have an initial value. But this can easily be solved by allocating the string like this:
string = calloc(420, sizeof(char));
ie: use calloc which sets the memory to zero. This way you have a valid string which can be used by strcat.
I'm not telling you to do not use gets or fflush because it is obvious that this is a home assignment and the suggested fgets has its own problems when dealing with the input string. Certainly if you will use gets in production code someone will kick you at that time.
And about casting the return value of malloc again, it's a two sided sword. If you know for sure that you will compile your project as a C project (ie: filename ends in .c and you use gcc to compile) then yes. Do not cast. However in other circumstances, such as naming the files .cpp or compiling with g++ .... well. You will get the error: error: invalid conversion from ‘void*’ to ‘char*’ without the cast. And I have the feeling that at a beginner level, while doing home assignments for school you more or less concentrate on making your code to compile and run, rather than stick to be pedantic. However for the future, it is recommended that you will be pedantic.
Here is a quick and dirty way to concatenate as many strings as the user wants to enter. Simply press ctrl+d when done to end input:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *concat (const char *str1, const char *str2) {
size_t len1 = strlen (str1); /* get lenghts */
size_t len2 = strlen (str2);
char * s = malloc (len1 + len2 + 2); /* allocate s and concat with ' ' */
memcpy (s, str1, len1);
s [len1] = ' ';
memcpy(s + len1 + 1, str2, len2); /* does not include terminating null */
s [len1 + len2 + 1] = '\0'; /* force null termination */
return s;
}
int main (void) {
char *line = NULL; /* pointer to use with getline () */
ssize_t read = 0;
size_t n = 0;
int cnt = 0;
char *str;
printf ("\nEnter a line of text to concatenate (or ctrl+d to quit)\n\n");
while (printf (" input: ") && (read = getline (&line, &n, stdin)) != -1) {
if (line[read-1] == '\n') { /* strip newline */
line[read-1] = 0;
read--;
}
if (cnt == 0) /* if more than 1 word, concat */
str = strdup (line);
else
str = concat (str, line);
cnt++;
}
printf ("\n\n Concatenated string: %s\n\n", str);
return 0;
}
output:
$ ./bin/concat
Enter a line of text to concatenate (or ctrl+d to quit)
input: my dog
input: has lots of fleas
input: my cat
input: has some too.
input:
Concatenated string: my dog has lots of fleas my cat has some too.
This is the modified code working fine
#include <stdio.h>
#include <string.h>
#include<stdlib.h>
#include <stdarg.h>
char *function(int num, ...);
int main(void)
{
char line1[80] = " ", line2[80] = " ", line3[80] = " ", line4[80] = " ", line5[80] = " ";
int count = 0, count2;
char *newStr;
int i;
int status;
do {
fflush(stdin);
printf("\nPlease select the number of strings (max. 5): ");
scanf("%d", &count);
}while(count < 2 && count > 5);
count2 = count;
fflush(stdin);
status = 1;
for( i = 1 ; count > 0; count--, i++)
{
switch(status)
{
case 1:
{
printf("\nInput string[%d]: ", i);
gets(line1);
status = 2;
break;
}
case 2:
{
printf("\nInput string[%d]: ", i);
gets(line2);
status = 3;
break;
}
case 3:
{
printf("\nInput string[%d]: ", i);
gets(line3);
status = 4;
break;
}
case 4:
{
printf("\nInput string[%d]: ", i);
gets(line4);
status = 5;
break;
}
case 5:
{
printf("\nInput string[%d]: ", i);
gets(line5);
status = 6;
break;
}
}
}
printf("\n%s\n%s\n%s\n%s\n%s\n", line1, line2, line3, line4, line5);
/*call the function of variable arguments*/
/*memory allocation of newstr*/
newStr = (char *)malloc(420*sizeof(char) +1);
switch(count2)
{
case 2:
{
newStr = function(2, line1, line2);
break;
}
case 3:
{
newStr = function(3, line1, line2, line3);
break;
}
case 4:
{
newStr = function(4, line1, line2, line3, line4);
break;
}
case 5:
{
newStr = function(5, line1, line2, line3, line4, line5);
}
}
printf("\nThe final string is: \n");
printf("%s", newStr);
return 0;
}
char *function(int num, ...)
{
va_list arg_ptr;
int b;
char *string;
char *curstr;
va_start(arg_ptr, num); /*initialize the arg_ptr*/
string = (char *)malloc(420*sizeof(char) + 1);
//*string = " ";
for(b=0; b < num; b++)
{
curstr = va_arg(arg_ptr, char * );
string = strcat(string,curstr);
}
printf("\n%s", string);
va_end(arg_ptr);
return string;
}
Just included stdlib and commented *string
Have a nice day
Length of your code is proportional to max strings user can enter. That doesn't sound good, right? (what if someone in the future will ask you to change it to allow user to enter 10 strings? 20? 100???).
In such cases usually in help come arrays - instead of having 5 different variables just use an array of them:
So change:
char line1[80], line2[80], line3[80], line4[80], line5[80];
to:
char lines[5][80];
So when in need of setting for e.g. second string, you can get it through:
char* line2 = lines[1]; \\ remember about indexes starting from 0,
\\ so second element has index 1
So now instead of 5 switch cases you can go with:
for( i = 1 ; count > 0; count--, i++)
{
printf("\nInput string[%d]: ", i);
fgets(lines[i], 80, stdin);
}
Moreover you don't need variable arguments function, as you can just pass array and it's size:
char *function(int array_elements, char ** array);
//Usage:
concatenated_string = function(5, lines);
Also it's good practice to put all const values into variables (so when changing max amount of string user can enter, you need to change only one place).
const int MAX_STRINGS = 5;
const int MAX_STRING_LENGTH = 80;
Now comes the real problem:
string = (char *)malloc(420*sizeof(char) + 1);
*string = " ";
Why would you allocate 420 bytes? What if user enters only one string - what do you need the rest 340 bytes for?
To get the length of concatenate strings, iterate through lines (from 0 to array_size), get lengths of lines (with strlen), sum them together and add 1 for trailing '\0'. Now you won't have any unnecessary memory allocated.
Next - *string = " "; should not compile as *string is a char and " " i a string (char *). Do *string = '\0' instead or call calloc instead of malloc.

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