Why I can't print first/last character right? - c

My output string needs to be palindrom of the input string. It works almost perfect but I am having problem with first character of the input string, my new string won't print it (in essence my new string won't print last character). Also strrev() does not work on Ubuntu so i need to do this without using that function.
#include <stdio.h>
#include <string.h>
int main(void){
int i,j=0;
char input_str[10];
char new_str[10];
printf("Enter characters:\n");
gets(input_str);
for(i=strlen(input_str)-1;i>0;i--){
new_str[j]=input_str[i];
j++;
}
printf("Output:\n");
printf("%s", new_str);
return 0;
}

For starters the function gets is unsafe function and is not supported by the C Standard.
You should use the standard C function fgets.
There are two problems with your code. The first one is in this loop
for(i=strlen(input_str)-1;i>0;i--){
new_str[j]=input_str[i];
j++;
}
the index i equal to 0 is skipped from using it to copy the corresponding character of the source string.
The second one is the destination array is not appended with the terminating zero character.
Here is a demonstrative program that shows how a function that makes a reversed copy of a source string can be implemented.
#include <stdio.h>
#include <string.h>
char * reverse_copy( char *dsn, const char *src )
{
size_t n = strlen( src );
size_t i = 0;
for ( ; i < n; i++ )
{
dsn[i] = src[n - i - 1];
}
dsn[i] = '\0';
return dsn;
}
int main(void)
{
enum { N = 10 };
char input_str[N] = "";
char new_str[N];
printf( "Enter a string (less than %zu symbols): ", ( size_t )N );
fgets( input_str, N, stdin );
input_str[ strcspn( input_str, "\n" ) ] = '\0';
printf( "\"%s\"\n", input_str );
printf( "\"%s\"\n", reverse_copy( new_str, input_str ) );
return 0;
}
The program output might look for example the following way
Enter a string (less than 10 symbols): Hello
"Hello"
"olleH"

i is never zero. That is why the first character (input_str[0]) is ignored.

Related

how do I access a character from 2-D char string

#include <stdio.h>
#include <string.h>
#define max 50
#define len 30
char text[max][len];
void main(){
register int i;
printf("Enter an empty line to quit\n");
for(i =0 ;i<max;i++){
gets(text[i]);
if(!*text[i]){break;}
}
puts(text[1][0]);/*I want to display first character of second string but it doesn't print anything. Why??*/
}
how do i access character or part of string from array of string
For starters according to the C Standard the function main without parameters shall be declared like
int main( void )
The function gets is unsafe and is not supported by the C Standard. Instead use standard C function fgets.
The function puts expects an argument of the pointer type char * that points to a string. However you are passing an object of the type char
puts(text[1][0]);
that invokes undefined behavior.
Also declare variables in minimum scope where they are used. There is no great sense to declare the array text in the file scope.
The program can look the following way
#include <stdio.h>
#define MAX 50
#define LEN 30
int main( void )
{
char text[MAX][LEN] = { 0 };
puts( "Enter an empty line to quit" );
size_t i = 0;
while ( i < MAX && fgets( text[i], LEN, stdin ) != NULL && text[i][0] != '\n' )
{
++i;
}
if ( !( i < 2 ) ) printf( "%c\n", text[1][0] );
}
Pay attention to that the function fgets can store the new line character '\n' in the suppled array.
If you want to remove it then you can write for example
#include <string.h>
//...
text[i][ strcspn( text[i], "\n" ) ] = '\0';
In your code, puts(text[1][0]) is trying to print a text[1][0] which is a char, and puts only accepts an char*, leading to a segmentation fault on my computer.
But, printf allows you to print an char.
Fixed code:
#include <stdio.h>
#include <string.h>
#define max 50
#define len 30
char text[max][len];
void main(){
register int i;
printf("Enter an empty line to quit\n");
for(i =0 ;i<max;i++){
gets(text[i]);
if(!*text[i]){break;}
}
printf("%c\n", text[1][0]); /* printf allows you to print char */
}
Note: as said in the comments of the question, you can also use putchar() to print one character.
Input:
s
s
Output:
s

Spilting strings in C with mulitple delimiters [duplicate]

This question already has answers here:
split char string with multi-character delimiter in C
(5 answers)
Closed 1 year ago.
so i need to split the string given with:
const char *inputs[] = {"111adbhsd111gfhds","goal!","zhd!111oosd","111let111"};
to ouput:
char *outputs[]={"adbhsd","gfhds","goal!","zhd!","oosd","let"}
where the delimiter is : "111" .
I tried with strtok , but as the delimiter is of mulitple character , it did't work!
any idea, how it might give the output, will help!
what i have did till now:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
size_t split(
char **outputs, // outputs
const char *separator, // the delimiter
const char **inputs,
size_t num_inputs // no. of input strings, given in input array
){
size_t num_outputs = 0;
int l= 0;
for(size_t i = 0; i < num_inputs ; i++){
if(strstr(*(inputs+i), separator) != NULL){ // to check, if the string of the given input array has the delimiter
char* pos = strstr( *(inputs+i), separator);
//having problem in this part
}
else
{
strcpy( outputs[l] , *(inputs+i));;
l++;
num_outputs++;
}
}
return num_outputs;
}
int main(){
const char *inputs[] = {
"111abdhsd111gfhds",
"goal!",
"zhd!111oosd",
"111let111"
};
char *outputs[] ={malloc(1000),malloc(1000),malloc(1000),malloc(1000),malloc(1000),malloc(1000)};
split(outputs, "111", inputs, 4);
for(int i =0; i < 6; i++)
{
printf("The output[%d] is : %s" ,i, outputs[i]);
free(outputs[i]);
}
return 0;
}
NOTE: The following answer refers to revision 2 of the question, which is before OP added code to the question which already uses the function strstr.
If the string is delimited by a substring instead of a single character, you can use the function strstr to find the delimiter substrings:
#include <stdio.h>
#include <string.h>
int main( void )
{
const char input[] = "111adbhsd111gfhds", *p = input;
const char *const delim = "111";
//remember length of delimiter substring
const size_t delim_length = strlen( delim );
for (;;) //infinite loop, equivalent to "while ( 1 )"
{
//attempt to find next delimiter substring
const char *q = strstr( p, delim );
//break loop if this is last token
if ( q == NULL )
break;
//print token
if ( q == p )
printf( "Found token: <empty>\n" );
else
printf( "Found token: %.*s\n", (int)(q-p), p );
//make p point to start of next token
p = q + delim_length;
}
//print last token
printf( "Found token: %s\n", p );
}
This program has the following output:
Found token: <empty>
Found token: adbhsd
Found token: gfhds
Since the sample input starts with the delimiter "111", the first token is empty. If you don't want empty tokens to be printed, you can simply remove the first printf statement in the code.
This is not a full solution to your problem, as your task seems to consist of multiple input strings instead of only one, and writing to output arrays instead of printing to the screen. In accordance with the community guidelines for homework questions, I will not provide a full solution to your problem at this time. Instead, for now, I have only provided a solution to the problem that you stated that you had trouble with (which was using strtok with substring delimiters). If necessary, I can add additional code later.

Printing out word by word using pointers

I am trying to make a program that prints out a sentence word by word using a pointer. I am having hard time finding the problem.
char str[100];
char *p;
printf("\nSentence: ");
scanf("%s", str);
p=str;
while(*p!='\0'){
if(*p == ' '){
printf("\n");
}else{
printf("%c", *p);
}
p++;
}
Using of the function scanf with the format "%s" skips leading white spaces and reads characters until a white space is encountered.
So you can not enter a sentence using this format,
Instead use the standard function fgets.
Moreover take into account that the user can separate words with several spaces or tabs. In this case your output will be invalid because there will be many empty lines.
It is more efficient to use the standard C functions strspn and strcspn.
Here is a demonstrative program.
#include <stdio.h>
#include <string.h>
int main(void)
{
enum { N = 100 };
char str[N] = "";
printf( "Enter a Sentence: " );
fgets( str, N, stdin );
str[ strcspn( str, "\n" ) ] = '\0';
const char *p = str;
const char *delim = " \t";
while ( *p )
{
p += strspn( p, delim );
const char *q = p;
p += strcspn( p, delim );
if ( p != q )
{
printf( "%*.*s\n", ( int )( p - q ), ( int )( p - q ), q );
}
}
return 0;
}
If for example to enter the following statement
Have a nice day Luka Milicevic
then the program output will be
Enter a Sentence: Have a nice day Luka Milicevic
Have
a
nice
day
Luka
Milicevic
You can use gets_s instead of scanf("%s"):
gets_s(str, sizeof(str));
Then you code will work fine.
scanf("%s") will get only one word from standard input.
On the other hand, gets_s will get a whole line.
But gets_s() can work only on Visual Studio, in order to make it portable, it's better to use fgets().
scanf reads the string until the first whitespace. If you input a sentence like 'first second', only 'first' will be read. To read a full line, you should use fgets.
Try to avoid using gets, as it doesn't limit the number of characters to read, which could cause a security vulnerability.
You could also use scanf like
scanf("%99[^\n]", str);
It will read any non '\n' (line ending) character upto max 99 so your buffer won't overflow.
Although using fgets is a safer bet.
scanf will read until first whitespace ,so only first word will be stored in str.
use fgets instead of scanf:(using fgets is a safe way)
#include <stdio.h>
int main()
{
char str[100];
char* p;
printf("\nSentence: ");
fgets(str, 100, stdin);
p = str;
while (*p != '\0') {
if (*p == ' ') {
printf("\n");
}
else {
printf("%c", *p);
}
p++;
}
return 0;
}

Segmentation Fault caused by realloc?

Hei, I was trying to solve this school exercise..
Write a program that keeps reading in character strings and concatenates them (adds them to a single character string). the concatenation should take place in a function that returns 1 if successful or 0 if it fails. for memory allocation use only realloc!
I don't receive any error while debugging the program, but when I try to run the program, after I insert the string the only thing that appears is "Segmentation Fault", what could it be? This is the code:
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
int cat(char **, char *);
int main(void)
{
char string[51];
char *output=NULL;
char choice;
do
{
printf("Please enter a string [<50 chars]: ");
fgets(string,50,stdin);
if(string[strlen(string)-1]=='\n') /* if newline was read as well */
string[strlen(string)-1]=0; /* discard it */
if(cat(&output,string))
printf("\n\nThe string now contains:\n%s\n",output);
else
{
printf("error: memory (re-)allocation failed!\n\n");
return 1; /* exit with error */
}
printf("Continue? (y/n) - ");
fgets(string,3,stdin); /* read input from keyboard - leave a safety buffer to account for read newline */
choice=string[0]; /* use the first character from the previous read as the choice */
} while(choice=='y' || choice=='Y');
free(output);
return 0;
}
int cat(char **dest, char *src)
{
int i;
int length1=strlen(src);
int length2=strlen(*dest);
int length3=length1+length2;
*dest=(char*)realloc(NULL,sizeof(*src));
printf("%p", *dest);
if(*dest==NULL) return 0; /* if allocation failed */
for(i=0;i<=length3;i++)
{
if(i<=length1)
(*dest)[i]=(*dest)[i];
else
(*dest)[i]=(src)[i];
}
free(src);
return 1;
}
There are at least 5 issues with your code:
1) You should free only what you allocated yourself on the heap. Don't free(src) because what you pass in src points to stack memory (char string[51]; is freed automatically).
2) you probably meant to reallocate dest, and 3) you meant to allocate memory the size of length3 (+1 null-terminator).
*dest=(char*)realloc(*dest, length3 + 1);
4) strlen(*dest) will crash when *dest is NULL initially.
int length2=(*dest)?strlen(*dest):0;
5) I don't think your for-loop is correct. It won't concatenate the strings, your offset calculation is off.
The initial value of the pointer output is NULL. However inside the function there is no check that the pointer is equal to NULL. So applying the function strlen to the pointer results in undefined behavior.
Also you need to reserve one more character for the terminating zero.
The memory is not reallocated correctly in the function. Moreover sizeof( *src ) is equal to one byte.
This statement
if(i<=length1)
(*dest)[i]=(*dest)[i];
does not make great sense. The reallocated memory provided that it was reallocated correctly already contains the original string.
You shall not free the pointer src because it does not point to a dynamically allocated memory.
The function can look the following way as it is shown in the demonstrative program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int cat( char **dest, const char *src )
{
size_t n = strlen( src ) + ( *dest == NULL ? 0 : strlen( *dest ) );
char *tmp = realloc( *dest, n + 1 );
int success = tmp != NULL;
if ( success )
{
if ( *dest == NULL ) *tmp = '\0';
*dest = tmp;
while ( *tmp ) ++tmp;
while ( ( *tmp++ = *src++ ) );
}
return success;
}
#define N 50
int main(void)
{
char *output = NULL;
char choice = 'n';
do
{
char string[N];
printf( "Please enter a string [<%d chars]: ", N );
fgets( string, sizeof( string ),stdin );
string[strcspn( string, "\n" )] = '\0';
if ( cat( &output, string ) )
{
printf( "\nThe string now contains:\n\"%s\"\n\n", output );
}
else
{
printf( "error: memory (re-)allocation failed!\n\n" );
return 1; /* exit with error */
}
printf( "Continue? (y/n) - " );
fgets( string, 3, stdin ); /* read input from keyboard - leave a safety buffer to account for read newline */
choice = string[0]; /* use the first character from the previous read as the choice */
} while ( choice == 'y' || choice == 'Y' );
free( output );
return 0;
}
Its output might look like
Please enter a string [<50 chars]: Hi Stefano Feltre
The string now contains:
"Hi Stefano Feltre"
Continue? (y/n) - y
Please enter a string [<50 chars]:
The string now contains:
"Hi Stefano Feltre "
Continue? (y/n) - y
Please enter a string [<50 chars]: Let's learn C
The string now contains:
"Hi Stefano Feltre Let's learn C"
Continue? (y/n) - n

Getting "Segmentation fault Core Dumped Error " while reversing a string

I am trying to learn C, I am getting this error while reversing a string. I am not well versed with memory allocation stuffs, can you please point out where I am doing wrong.
#include<stdio.h>
#include<string.h>
char* strrev(char *str);
int main()
{
char str[1000];
char *str1;
printf("Please enter a String\n");
gets(str);
str1=strrev(str);
puts(str1);
}
char* strrev(char *str)
{
char *str1;
int i,length,c;
length=strlen(str);
for (i=length-1;i<=0;i--)
{
*(str1+c) = *(str+i);
c++;
}
*(str1+c) ='\0';
return str1;
}
for (i=length-1;i<=0;i--)
This will never (unless string is 0 or 1 character long) run due to i<=0, should be i>=0 probably.
Also in general you need to make pointer point to some valid memory in order to be able to dereference it. In your case you should probably use malloc for allocating sufficient number of bytes, and assign its result to str1. Then you can write to it as you are doing.
Inside your strrev() function, str1 is not allocated memory. Hence, *(str1+c) = *(str+i); is UB.
Then, c is an automatic local variable which is not initialized before use. Also UB.
Next, as Giorgi mentioned, correct your for loop.
That said, don't use gets(), it suffers from buffer overrun issues. Use fgets() instead.
What you are trying to do is not reversing a string. Neither string is reversed in your program. You are trying to copy one string in another string in the reverse order.
So the sring where you are going to copy the original string in the reverse order shall have enough space to store the copied characters.
However in your function
char* strrev(char *str)
{
char *str1
//...
pointer str1 was not initialized and does not point to an extent of memory of the appropriate size.
So your program has undefined behaviour.
Take also in account that function gets is unsafe and is not supported by the C standard any more. Use function fgets instead.
If your compiler supports Variable Length Arrays (VLA) then the program can look the following way
#include <stdio.h>
#include <string.h>
char * reverse_copy( char *s2, const char *s1 )
{
size_t n = strlen( s1 );
size_t i = 0;
for ( ; i < n; i++ ) s2[i] = s1[n-i-1];
s2[i] = '\0';
return s2;
}
int main( void )
{
char s1[1000];
printf( "Please enter a String: " );
fgets( s1, sizeof( s1 ), stdin );
size_t n = strlen( s1 );
if ( n != 0 && s1[n-1] == '\n' ) s1[n-1] = '\0';
char s2[n + 1];
puts( s1 );
puts( reverse_copy( s2, s1 ) );
return 0;
}
If to enter for example
Hello Asfakul Islam
then the output will look like
Please enter a String: Hello Asfakul Islam
Hello Asfakul Islam
malsI lukafsA olleH
Otherwise if your compiler does not support VLA(s) you need to dynamically allocate an array of the appropriate size. In this case the program can look for example the following way
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char * reverse_copy( char *s2, const char *s1 )
{
size_t n = strlen( s1 );
size_t i = 0;
for ( ; i < n; i++ ) s2[i] = s1[n-i-1];
s2[i] = '\0';
return s2;
}
int main( void )
{
char s1[1000];
printf( "Please enter a String: " );
fgets( s1, sizeof( s1 ), stdin );
size_t n = strlen( s1 );
if ( n != 0 && s1[n-1] == '\n' ) s1[n-1] = '\0';
char *s2 = malloc( ( n + 1 ) * sizeof( char ) );
puts( s1 );
puts( reverse_copy( s2, s1 ) );
free( s2 );
return 0;
}
You don't initialize str1 in strrev()
If you enter string whose length is 2 characters or more, i<=0 is false and the block inside the for loop won't be executed.
*(str1+c) ='\0'; will cause the crash because the value of str1 is indeterminate and you have few chance that str1 points some valid place.
UPD: c in strrev() is also uninitialized, and it will cause some trouble.
In your function, you did not initialize c
int i,length,c;
and are using it inside the for loop
*(str1+c) = *(str+i);
Plus other problems are there..
1) str1 inside the function is not allocated memory.
2) This loop will never get executed, as the condition in for (i=length-1;i<=0;i--) is never true (unless string is 0 or 1 character long).
3) Do not use gets(), it is deprecated. Instead use fgets()

Resources