I attempt to copy the contents of closure in res using strcpy, however i get what i think are soome garbage values before what actually is in closure, any ideas on how to solve this issue, all help is appreciated :) . Please ignore the rest of the scuffed code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int fdcount;
int i, j;
char closure[100];
char temp[20];
printf("nb fd: \n");
scanf("%d", &fdcount);
char left[fdcount][100];
char right[fdcount][100];
char res[fdcount][100];
for (i = 0; i < fdcount; i++) {
printf("left of fd %d: ", i + 1);
scanf(" %c", temp);
strcpy(left[i], temp);
printf("right of fd %d: ", i + 1);
scanf(" %c", temp);
strcpy(right[i], temp);
}
printf("closure ");
scanf(" %c", closure);
//system("cls");
printf("your fds \n");
for (i = 0; i < fdcount; i++) {
printf("%s -> %s \n", left[i], right[i]);
}
strcpy(closure, res[0]);
for (i = 0; i < fdcount; i++) {
printf(" %s", res[i]);
}
return 0;
}
The line
strcpy(closure, res[0]);
will copy the string in res[0] to closure.
You probably want to do the opposite. You want to copy the string in closure to res[0]. In that case, you should swap the two arguments, by changing the line to the following:
strcpy( res[0], closure );
Another problem is that using the function strcpy requires the second argument to actually be a string (i.e. a sequence of characters terminated by a null character). If it is not, then your program will be invoking undefined behavior (i.e. your program may crash).
The content of closure is not a string, because the line
scanf(" %c", closure);
will only write a single character to closure. It won't write a terminating null character afterwards.
If you want to make closure a valid string, then all you have to do is add a terminating null character after the character, like this:
closure[1] = '\0';
On the other hand, if you want to read a whole line of input as a string, then you could use the function fgets instead:
fgets( closure, sizeof closure, stdin );
Note that the function fgets will also read the newline character at the end of the line, and store it as part of the string. If you do not want this, see the following question for different possibilities on how to remove this newline character:
Removing trailing newline character from fgets() input
Another problem in your code is that the following loop is wrong:
for (i = 0; i < fdcount; i++) {
printf(" %s", res[i]);
}
When using printf with the %s conversion format specifier, the argument must be a valid null-terminated string. Since you are calling printf in a loop, the contents of res[0] up to res[fdcount-1] must contain valid strings. However, even after making the fixes mentioned above, only res[0] will be a valid string with a null terminating character. The content of res[1] to res[fdcount-1] will still contain garbage data. Therefore, you should not attempt to treat this garbage data as strings, because doing so will invoke undefined behavior.
Here is a short demonstration program which reads a line of input into closure, copies it, and then prints the copy:
#include <stdio.h>
#include <string.h>
int main( void )
{
int fdcount = 20;
char closure[100];
char res[fdcount][100];
//prompt user for input
printf( "Please enter a line of input: " );
//read one line of user input
fgets( closure, sizeof closure, stdin );
//remove newline character from input
closure[strcspn(closure,"\n")] = '\0';
//copy input to res[0]
strcpy( res[0], closure );
//print copy
printf( "Contents of res[0]: %s\n", res[0] );
}
This program has the following behavior:
Please enter a line of input: This is a test.
Contents of res[0]: This is a test.
Of course, it does not make much sense to create an array of strings, if you are only using one string.
Here is the same program with full error checking:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main( void )
{
int fdcount = 20;
char closure[100];
char res[fdcount][100];
char *p;
//prompt user for input
printf( "Please enter a line of input: " );
//attempt to read one line of user input
if ( fgets( closure, sizeof closure, stdin ) == NULL )
{
fprintf( stderr, "Input error!\n" );
exit( EXIT_FAILURE );
}
//verify that input buffer was large enough to store entire line
p = strchr( closure, '\n' );
if ( p == NULL )
{
if ( !feof( stdin ) )
{
fprintf( stderr, "Line too long to fit into buffer!\n" );
exit( EXIT_FAILURE );
}
}
else
{
//remove newline character from input
*p = '\0';
}
//copy input to res[0]
strcpy( res[0], closure );
//print copy
printf( "Contents of res[0]: %s\n", res[0] );
}
Please ignore the rest of the scuffed code.
The rest of your code is hard to ignore, because it is also invoking undefined behavior, so that the behavior of your entire program is undefined (i.e. your program may crash).
The lines
strcpy(left[i], temp);
and
strcpy(right[i], temp);
require temp to be a string, which it is not, because it is not terminated by a null character.
Related
Here's the basic skeleton of my code:
int getSentence(SearchResults* input){
printf("Enter sentence:");
fgets(input->sentence, 100, stdin);
printf("Enter message ID:");
fgets(input->messageID, 20, stdin);
return 1;
}
As is, this has a couple of problems. One is that when I print the string later, they have a newline character at the end, which I don't want. The other is that if I enter more than the 100 or 20 characters, it will overflow those characters into the next fgets call.
I've found "solutions" online, but they all either introduce new problems, or are recommended against using. Most of what I found is summarized in this SO post: How to properly flush stdin in fgets loop.
fflush works for the second problem, but is apparently "problematic".
I came up with *(strstr(input->sentence, "\n")) = '\0'; for the first issue, but it doesn't help with the second
while ((getchar()) != '\n')(and variations) is a commonly recommended solution for both problems, but it introduces a new issue: my next input requires two enters before the program will continue running. I tried adding fputc('\n', stdin); after the while loop and it solves all three problems, but only when the input exceeds the character limit. If I write a sentence less than 100 chars, I have to hit enter twice for the program to continue.
setbuf(stdin, NULL) is one of the solutions given, but one of the comments says "mucking around with setbuf is even worse [than fflush]"
I recommend that you create your own function that calls fgets, verifies that the entire line was read in and removes the newline character. If the function fails due to the input being too long, you can print an error message, discard the remainder of the line and reprompt the user. Here is a function that I have written myself for this purpose some time ago:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//This function will read exactly one line of input from the
//user. It will remove the newline character, if it exists. If
//the line is too long to fit in the buffer, then the function
//will automatically reprompt the user for input. On failure,
//the function will never return, but will print an error
//message and call "exit" instead.
void get_line_from_user( const char prompt[], char buffer[], int buffer_size )
{
for (;;) //infinite loop, equivalent to while(1)
{
char *p;
//prompt user for input
fputs( prompt, stdout );
//attempt to read one line of input
if ( fgets( buffer, buffer_size, stdin ) == NULL )
{
printf( "Error reading from input!\n" );
exit( EXIT_FAILURE );
}
//attempt to find newline character
p = strchr( buffer, '\n' );
//make sure that entire line was read in (i.e. that
//the buffer was not too small to store the entire line)
if ( p == NULL )
{
int c;
//a missing newline character is ok if the next
//character is a newline character or if we have
//reached end-of-file (for example if the input is
//being piped from a file or if the user enters
//end-of-file in the terminal itself)
if ( !feof(stdin) && (c=getchar()) != '\n' )
{
printf( "Input was too long to fit in buffer!\n" );
//discard remainder of line
do
{
if ( c == EOF )
{
printf( "Error reading from input!\n" );
exit( EXIT_FAILURE );
}
c = getchar();
} while ( c != '\n' );
//reprompt user for input by restarting loop
continue;
}
}
else
{
//remove newline character by overwriting it with
//null character
*p = '\0';
}
//input was ok, so break out of loop
break;
}
}
Here is a demonstration program in which I apply my function to your code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//forward declaration
void get_line_from_user( const char prompt[], char buffer[], int buffer_size );
int main( void )
{
char sentence[100];
char messageID[20];
get_line_from_user( "Enter sentence: ", sentence, sizeof sentence );
get_line_from_user( "Enter message ID: ", messageID, sizeof messageID );
printf(
"\n"
"The following input has been successfully read:\n"
"sentence: %s\n"
"message ID: %s\n",
sentence, messageID
);
}
//This function will read exactly one line of input from the
//user. It will remove the newline character, if it exists. If
//the line is too long to fit in the buffer, then the function
//will automatically reprompt the user for input. On failure,
//the function will never return, but will print an error
//message and call "exit" instead.
void get_line_from_user( const char prompt[], char buffer[], int buffer_size )
{
for (;;) //infinite loop, equivalent to while(1)
{
char *p;
//prompt user for input
fputs( prompt, stdout );
//attempt to read one line of input
if ( fgets( buffer, buffer_size, stdin ) == NULL )
{
printf( "Error reading from input!\n" );
exit( EXIT_FAILURE );
}
//attempt to find newline character
p = strchr( buffer, '\n' );
//make sure that entire line was read in (i.e. that
//the buffer was not too small to store the entire line)
if ( p == NULL )
{
int c;
//a missing newline character is ok if the next
//character is a newline character or if we have
//reached end-of-file (for example if the input is
//being piped from a file or if the user enters
//end-of-file in the terminal itself)
if ( !feof(stdin) && (c=getchar()) != '\n' )
{
printf( "Input was too long to fit in buffer!\n" );
//discard remainder of line
do
{
if ( c == EOF )
{
printf( "Error reading from input!\n" );
exit( EXIT_FAILURE );
}
c = getchar();
} while ( c != '\n' );
//reprompt user for input by restarting loop
continue;
}
}
else
{
//remove newline character by overwriting it with
//null character
*p = '\0';
}
//input was ok, so break out of loop
break;
}
}
This program has the following behavior:
Enter sentence: This is a test sentence.
Enter message ID: This is another test sentence that is longer than 20 characters and therefore too long.
Input was too long to fit in buffer!
Enter message ID: This is shorter.
The following input has been successfully read:
sentence: This is a test sentence.
message ID: This is shorter.
Here's what I'm using to solve my issue, thanks to Steve Summit and Andreas Wenzel for their comments.
int getSentence(SearchResults* input){
printf("Enter sentence:");
fgets(input->sentence, 100, stdin);
int temp = strcspn(input->sentence, "\n");
if(temp < 100 - 1) input->sentence[temp] = '\0';
else while ((temp = getchar()) != '\n' && temp != EOF);
printf("Enter message ID:");
fgets(input->messageID, 20, stdin);
temp = strcspn(input->messageID, "\n");
if(temp < 20 - 1) input->messageID[temp] = '\0';
else while ((temp = getchar()) != '\n' && temp != EOF);
return 1;
}
EDIT: For anyone else who has the same issue as me, see comments below for additional problems you may need to account for if you use this solution, such as fgets returning NULL.
Good afternoon, my question is conceptual. How can I make it generate a "fancy" error when the user incorrectly enters some data that does not correspond to the scanf() function? So as to only allow integers to be entered in the example below (not characters or array of characters or an inappropriate data).
For example:
#include <stdio.h>
int a;
printf("Enter a number\n");
scanf("%d", &a); //the user is supposed to enter a number
printf("Your number is %d ", a);
//but if the user enters something inappropriate, like a character, the program leads to
//undetermined behavior (which as I understand it interprets said character according to its
//value in the ASCII code).
From already thank you very much
In order to determine whether scanf was able to successfully convert the input to an integer, you should check the return value of scanf:
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
int num;
printf( "Enter a number: " );
if ( scanf( "%d", &num ) != 1 )
{
printf( "Failed to convert input!\n" );
exit( EXIT_FAILURE );
}
printf( "Conversion successful! The number is %d.\n", num );
}
However, using scanf for line-based user input is generally not recommended, because scanf does not behave in an intuitive manner when dealing with that kind of input. For example, scanf will generally not consume an entire line of input at once. Instead, it will generally only consume the input that matches the argument, but will leave the rest of the line on the input stream, including the newline character.
Leaving the newline character on the input stream can already cause a lot of trouble. For example, see this question.
Also, if the user enters for example 6abc, then scanf will successfully match the 6 and report success, but leave abc on the input stream, so that the next call to scanf will probably immediately fail.
For this reason, it is generally better to always read one line of input at a time, using the function fgets. After successfully reading one line of input as a string, you can use the function strtol to attempt to convert the string to an integer:
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
char line[200], *p;
int num;
//prompt user for input
printf( "Enter a number: " );
//attempt to read one line of input
if ( fgets( line, sizeof line, stdin ) == NULL )
{
printf( "Input failure!\n" );
exit( EXIT_FAILURE );
}
//attempt to convert string to integer
num = strtol( line, &p, 10 );
if ( p == line )
{
printf( "Unable to convert to integer!\n" );
exit( EXIT_FAILURE );
}
//print result
printf( "Conversion successful! The number is %d.\n", num );
}
However, this code has the following issues:
It does not check whether the input line was too long to fit into the buffer.
It does not check whether the converted number is representable as an int, for example whether the number is too large to be stored in an int.
It will accept 6abc as valid input for the number 6. This is not as bad as scanf, because scanf will leave abc on the input stream, whereas fgets will not. However, it would probably still be better to reject the input instead of accepting it.
All of these issues can be solved by doing the following:
Issue #1 can be solved by checking
whether the input buffer contains a newline character, or
whether end-of-file has been reached, which can be treated as equivalent to a newline character, because it also indicates the end of the line.
Issue #2 can be solved by checking whether the function strtol set errno to the value of the macro constant ERANGE, to determine whether the converted value is representable as a long. In order to determine whether this value is also representable as an int, the value returned by strtol should be compared against INT_MIN and INT_MAX.
Issue #3 can be solved by checking all remaining characters on the line. Since strtol accepts leading whitespace characters, it would probably also be appropriate to accept trailing whitespace characters. However, if the input contains any other trailing characters, the input should probably be rejected.
Here is an improved version of the code, which solves all of the issues mentioned above and also puts everything into a function named get_int_from_user. This function will automatically reprompt the user for input, until the input is valid.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
int get_int_from_user( const char *prompt )
{
//loop forever until user enters a valid number
for (;;)
{
char buffer[1024], *p;
long l;
//prompt user for input
fputs( prompt, stdout );
//get one line of input from input stream
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "Unrecoverable input error!\n" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
{
int c;
printf( "Line input was too long!\n" );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "Unrecoverable error reading from input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
continue;
}
//attempt to convert string to number
errno = 0;
l = strtol( buffer, &p, 10 );
if ( p == buffer )
{
printf( "Error converting string to number!\n" );
continue;
}
//make sure that number is representable as an "int"
if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
{
printf( "Number out of range error!\n" );
continue;
}
//make sure that remainder of line contains only whitespace,
//so that input such as "6abc" gets rejected
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Unexpected input encountered!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
return l;
continue_outer_loop:
continue;
}
}
int main( void )
{
int number;
number = get_int_from_user( "Enter a number: " );
printf( "Input was valid.\n" );
printf( "The number is: %d\n", number );
return 0;
}
This program has the following behavior:
Enter a number: abc
Error converting string to number!
Enter a number: 6000000000
Number out of range error!
Enter a number: 6 7 8
Unexpected input encountered!
Enter a number: 6abc
Unexpected input encountered!
Enter a number: 6
Input was valid.
The number is: 6
How to get verified user input of a specific type
#1 Get user input as a string
char s[100];
if (!fgets( s, sizeof(s), stdin )) *s = '\0';
char * p = strptok( s, "\r\n" );
if (!p) complain_and_quit();
*p = '\0';
...
Alternately:
#define __STDC_WANT_LIB_EXT2__ 1
#include <stdio.h>
char * s = NULL;
size_t n = 0;
if (getline( &s, &n, stdin ) < 0)
{
free( s );
complain_and_quit();
}
...
free( s );
#2 Get rid of any trailing whitespace
This could easily be put in a trim() function, but here we’ll spell it out:
Can’t believe I forgot this step. Sorry. 😳
p = strchr( s, '\0' );
while (p-- != s) if (!isspace( *p )) break;
p[1] = '\0';
#3 Try to convert that string to the type of thing you want.
char * p;
int user_input = strtol( s, &p, 10 );
if (*p)
{
// Input was not JUST an integer.
// It could be something like "123 xyz", or "not-an-integer".
// Look at the value of p to figure out where the conversion went wrong.
complain();
}
do_something_with_an_integer( user_input );
That’s it!
keep in mind i'm a complete beginner and i'm still getting acclimated to the programming vocabulary.
When I run the debug from visual studio, the command prompt comes up with "Enter any string: " but when I enter something, i get "Exception thrown blah blah blah". What is going wrong? Any help and criticism is greatly appreciated. I've been losing my mind over this for 4 hours now.
Heres my code:
int main(){
char str[100];
int i=0;
printf("Enter any string: ");
scanf_s("%s",str);
printf("ASCII values of each characters of given string: ");
while(str[i])
printf("%d ",str[i++]);
return 0;
}
The scanf_s() function must be used with a third argument to indicate the max length of the string i.e. scanf_s("%s", str, 100);
BTW scanf_s() is specific to Microsoft Visual Studio so it's less portable so I don't recommend it and str isn't a really good variable name
The posted code is:
not portable
contains 'magic' (not basis for value) numbers
spreads the variable i declaration far from its' usage
will not input past a 'white space' character
The following code corrects those problems, checks for errors, and compiles cleanly
#include <stdio.h> // scanf(), printf(), perror()
#include <stdlib.h> // exit(), EXIT_FAILURE
#define MAX_STR_LEN (100)
int main( void )
{
char str[ MAX_STR_LEN ];
printf("Enter any string: ");
if( NULL == fgets( str, sizeof(str), stdin ))
{
perror( "fgets failed" );
exit( EXIT_FAILURE );
}
// implied else, scanf successful
printf("ASCII values of each characters of given string: ");
for( size_t i=0; str[i]; i++ )
printf("%d ",str[i]);
return 0;
}
Note: the above code will input the newline and print it (10 on linux) You might want to use something to eliminate the newline, so insert the following, right after the call to fgets():
char *newline = NULL;
if( NULL != ( newline = strstr( str, "\n" ) ) )
{ // carriage return found
*newline = '\0';
}
This method of eliminating the newline char means the code also needs:
#include <string.h> // strstr()
I'd like to iterate through a string (entered by the user), returning the inputted string with an added space after each character (i.e. "Hello" --> "H e l l o ".
If I preset the value for str (i.e. char str[] = "Hello";) then the desired result is printed ("H e l l o "), but not so with user input (i.e. If the user inputs "Hello" the output is "H"). How does one successfully extract and manipulate a C string based on user input?
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "";
printf("\nEnter a string: ");
scanf("%s", &str);
printf("\nYou typed: %s \n", str);
int i = 0;
char newstr[150] = "";
for (i = 0; i < strlen(str); i++)
{
newstr[2*i] = str[i];
newstr[2*i+1] = ' ';
}
newstr[2 * strlen(str)] = '\0';
printf("\nExpanded String: ");
printf("%s", newstr);
return 0;
}
Here:
char str[] = "";
the size of str is inferred from the initializer, which is in this case one byte large. Thus str cannot hold a string larger than one byte, and since the zero-terminator is one byte large, there is no more space for a payload. A fix is to specify a size:
char str[1024] = "";
Now str has enough space for a kilobyte of data, or 1023 characters in addition to the terminator. The size is deliberately chosen to be much larger than the input you expect.
In addition to this, it would be a good idea to prevent scanf from writing past the end of the buffer by including the size in the format string. That is
scanf("%1023s", str); // now scanf will not read more than 1023 bytes plus sentinel.
...and in turn, it would be a good idea to increase the size of newstr accordingly (to twice that of str), i.e.
char newstr[2047]; // 2 * 1023 + terminator
...or, you know, make str smaller, depending on how long a string you want to support.
Thanks to Cool Guy for catching the superfluous & and newstr size implications.
"How does one successfully extract and manipulate a C string based on user input?"
You can use getchar() instead.
For example, you can store the user input in an array first. Then the problem becomes the same as if you did your 'char str[] = "Hello":
int index = 0
while((temp1 = getchar())!= '\n'){
str[index++] = temp1;
}
the following code
-complies cleanly
-checks and handles errors
-does the job
-doesn't use unneeded memory
(well actually) the logic could be a loop
that reads one char, outputs char, outputs space
or something similar if a trailing space is a problem
then the input buffer could be a single character
#include <stdio.h>
#include <stdlib.h> // exit, EXIT_FAILURE
#include <string.h>
int main()
{
// char str[] = "";
// there actually has to be room for the string
char str[100] = {'\0'};
printf("\nEnter a string: ");
if( 1 != scanf("%s", str) ) // arrays degenerate to pointer so no extra '&' needed
{ // then scanf failed
perror( "scanf failed" );
exit( EXIT_FAILURE );
}
// implied else, scanf successful
printf("\nYou typed: %s \n", str);
// there is no need to keep the modified string in memory
// when all that will be done is print it
int i = 0; // loop counter
printf("\nExpanded String: ");
for (i = 0; i < strlen(str); i++)
{
printf("%c", str[i]);
if( i < (strlen(str)-1) )
{ // then another char will follow
printf( " " );
}
else
{
printf( "\n" );
} // end if
} // end for
return 0;
} // end function: main
this is my source code. When I input a string "I am in CSE 2nd year." and replace CSE 2nd(ie loc 9 to 15) by ECE 3rd, I get some garbage vales at the end of string. Also there is a newline at the beggining of rslt2 string. There is something wrong with rslt2. Can anyone please rectify the error?
//splitting a string and replace latter part of string by another string
#include<stdio.h>
#include<string.h>
int main()
{
int i,count=0,loc2,scount=0,rcount=0,loc=0; //scount represents counter for subset and rcount for replacement and loc from where we will split the string
char str[100],sub[100],newss[100],rslt[100],rslt2[100]; //newss=new substr, rslt and rslt2=former and latter part of original string
printf("Enter a String:\n");
fgets(str,100,stdin);
printf("\nString Entered by User:\n");
fflush(stdin);
puts(str);
printf("\nLoc Char\n"); //Creates Colums 'Char' and 'Loc'
for(i=0;str[i]!='\0';i++)
{
count++; //Counts length of String
printf("%d. %c\n",count,str[i]); //Prints Characters with it its Corresponding Location
}
printf("\n\nLength of String: %d\n\n",count);
printf("Enter the locations of Characters from where subset will start and end: \n");
scanf("%d%d",&loc,&loc2); //stores indices of begining and end of substring
printf("\n\nSubset formed from Existing String:\n");
for(i=loc-1;i<loc2;i++)
{
scount++;
sub[i]=str[i]; //stores substring in "sub"
printf("%c",sub[i]);
}
printf("\n\nLength of Subset: %d\n",scount);
for(i=0;i<(loc-1);i++)
{
rslt[i]=str[i]; //Stores former part of string in resultant string
}
for(i=loc2;i<strlen(str);i++)
{
rslt2[i]=str[i]; //Stores latter part of string in resultant string2
}
printf("\n\nEnter a Replacement for Subset(Of Equal Length as that of Subset):\n");
fflush(stdin);
fgets(newss,100,stdin);
for(i=0;newss[i]!='\0';i++)
rcount++;
printf("\n\nLength of New Subset: %d\n",rcount-1); //-1 to subtract length of null char
if(rcount-1!=scount) //to check whether replacement string and substring are of same len
printf("\nSince length of both subsets is not same. \nHence Replacement is Not Possible\n");
else //Concatination of 3 substrings
{
printf("\nResultant String:\n");
for(i=0;i<(loc-1);i++)
printf("%c",rslt[i]);
printf("\n");
for(i=0;newss[i]!='\0';i++)
printf("%c",newss[i]);
for(i=loc2;rslt2[i]!='\0';i++)
printf("%c",rslt2[i]);
}
return 0;
}
Here's an example of how to implement that program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXL 100
int main( void )
{
int count, lengthI, lengthR, start, end;
char initial[MAXL], replacment[MAXL], range[MAXL], result[MAXL];
// get user input
printf( "Initial string: " );
fflush( stdout );
fgets( initial, MAXL, stdin );
printf( "Replacement string: " );
fflush( stdout );
fgets( replacment, MAXL, stdin );
printf( "Start and end: ");
fflush( stdout );
fgets( range, MAXL, stdin );
count = sscanf( range, "%d%d", &start, &end ); // indices of beginning and end of range in initial string
// remove newline character from the input strings, if necessary
lengthI = strlen( initial );
if ( lengthI > 0 && initial[lengthI - 1] == '\n' )
initial[--lengthI] = '\0';
lengthR = strlen( replacment );
if ( lengthR > 0 && replacment[lengthR - 1] == '\n' )
replacment[--lengthR ] = '\0';
// range checking to verify that user inputs are valid and the resulting string will fit into the buffer
if ( count != 2 || start < 0 || start > lengthI || end < start || end > lengthI )
{
fprintf( stderr, "Invalid start and end values\n" );
exit( 1 );
}
if ( lengthI + lengthR - (end - start) + 1 > MAXL )
{
fprintf( stderr, "Resulting string would be too long\n" );
exit( 2 );
}
// create a new string with the substring replaced
if ( start > 0 ) // copy characters from the initial string up to the start index
strncpy( result, initial, start ); // note: this step may leave the result string unterminated
strcpy( &result[start], replacment ); // append the repacement string
// guarantees the result string is terminated
if ( end < lengthI ) // append characters from the initial that are after the end index
strcat( result, &initial[end] ); // terminates the result string (provided that strcat is called)
// print the result
printf( "%s\n", result );
}
Comments:
Don't mix fgets and scanf. Even if you're aware of the issues involved with doing so, it's still easy to get it wrong. Best to just read lines with fgets, and then parse with sscanf as necessary.
fflush(stdin) is non-standard. fflush is only guaranteed to work on stdout. On some systems, fpurge can be used to erase unread input.
When dealing with strings in C (aka arrays of characters), range checking is essential. Buffer overruns are the #1 cause of crashes, unexpected behavior, and security holes in C programs. Always range check user inputs, and always verify that a newly created string will fit into the buffer provided.
Always make sure that a newly created string ends with a null character (aka '\0'), and be sure to include that null character when calculating buffer sizes.
Note that in the sample code, strncpy may leave the string unterminated. The subsequent call to strcpy will terminate the string. The strcat function will also terminate the string. However, the call to strcat is conditional based on user input. Hence, without the call to 'strcpy', we'd have extra work to do to guarantee the the string gets its mandatory null terminator.
use negated scanf ie scanf(" %[^\n]",str_name); instead of gets();