I'm learning C now, and i have one question in my program.
I need to reverse string like
I like dogs -> I ekil sgod
I wrote this code
char end[MAX_LEN];
char beg[MAX_LEN];
char* piece = strtok(str, " ");
strcpy(end, piece);
strcpy(beg, piece);
char* pbeg = beg;
char* prev = piece;
int n = strlen(piece)-1;
i = 0;
int n = 0;
while (piece != NULL) {
//printf("\n%s", piece);
while (piece[i] != '\0') {
*(prev + n -i ) = *(pbeg + i);
i++;
}
printf("\n%s", piece);
piece = strtok(NULL, " ");
strcpy(beg, piece); // also in this moment in debugging i saw this error ***Exception thrown at 0x7CBAF7B3 (ucrtbased.dll) in лаб131.exe: 0xC0000005: Access violation reading location 0x00000000.***
}
But it returns only the first lexeme reversed.
You are getting an exception because you are not checking whether the pointer piece is equal to NULL when you are using it in the call of strcpy
piece = strtok(NULL, " ");
strcpy(beg, piece);
Also within the while loop you forgot to reset the variables i and n and the pointer prev.
To use the function strtok is a bad idea because the source string can contain adjacent space characters that should be preserved in the result string. Also you have too many arrays and pointers that only confuse readers of the code.
Here is a demonstration program that shows how the task can be easy done.
#include <stdio.h>
#include <string.h>
void reverse_n( char s[], size_t n )
{
for ( size_t i = 0; i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n-i-1];
s[n-i-1] = c;
}
}
int main(void)
{
char input[] = "I like dogs";
const char *separator = " \t";
for ( char *p = input; *p; )
{
p += strspn( p, separator );
char *q = p;
p += strcspn( p, separator );
reverse_n( q, p - q );
}
puts( input );
return 0;
}
The program output is
I ekil sgod
Related
I am trying to write a function that will split a string along a space (' ') without changing the original string, put all of the tokens into an array, then return that array. The problem I am running into is in returning the pointer. Below is my code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **split_line(char *ln) {
char **tokens, *tok, line[256];
int j;
strcpy(line, ln);
tokens = calloc(64, sizeof(char*));
for (int i = 0; i < 64; i++)
tokens[i] = calloc(64, sizeof(char));
tokens[0] = strtok(line, " ");
for (j = 1; (tok = strtok(NULL, " ")) != NULL && j < 63; j++)
tokens[j] = tok;
tokens[j] = NULL;
return tokens;
}
int main(void) {
char **cut_ln, *input;
input = "Each word in this string should be an element in cut_ln.";
cut_ln = split_line(input);
printf("`%s`\n", input);
for (int i = 0; cut_ln[i] != NULL; i++)
printf("[%d]: `%s`\n", i, cut_ln[i]);
return 0;
}
When run, this gives:
`This word in this string should be an element in cut_ln.`
[0]: `This`
[1]: `wo1`
[2]: `�={G+s`
[3]: `G+s`
[4]: `string`
[5]: ``
[6]: `0����`
[7]: `��`
[8]: ``
[9]: ``
[10]: ``
When I try to print the contents of tokens in the split_line function, it gives the expected result. However, when tokens is returned and assigned to a variable, and then printed, it gives the result above as demonstrated. What am I doing wrong?
When you return tokens, it contains the pointers returned from strtok, which are pointers into line. But line no longer exists at this point.
You allocated memory and made the various elements of tokens point to that allocated memory. Don't overwrite those values with the values returned from strtok.
For starters the function should be declared at least like
char ** split_line( const char *ln );
because the passed string is not being changed within the function.
The function will be a more flexible if to declare a second parameter that will specify delimiters.
char ** split_line( const char *ln, const char *delim );
Secondly it is a bad idea to use magic numbers like 64 or 256. The function will not work if the passed string contains more than 63 tokens or when the string for example contains at least one token the length of which is greater than 63.
You dynamically allocated 64 arrays in this loop
for (int i = 0; i < 64; i++)
tokens[i] = calloc(64, sizeof(char));
and assigned their addresses to elements of the array pointed to by the variable tokens. But at once you reassigned the pointers with addresses inside the local array line.
tokens[0] = strtok(line, " ");
for (j = 1; (tok = strtok(NULL, " ")) != NULL && j < 63; j++)
tokens[j] = tok;
So the function produces numerous memory leaks. And the returned array of pointers will contain invalid pointers because the local array line will not be alive after exiting the function.
Also this statement
tokens[j] = NULL;
is redundant. Using calloc you already set initially all pointers to NULL.
The function can look the following way as it is shown in the demonstrative program below.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char ** split_line( const char *s, const char *delim )
{
size_t n = 0;
for ( const char *p = s; *p; )
{
p += strspn( p, delim );
if ( *p )
{
++n;
p += strcspn( p, delim );
}
}
char **tokens = calloc( n + 1, sizeof( char * ) );
if ( tokens )
{
size_t i = 0;
int success = 1;
for ( const char *p = s; success && *p; i += success )
{
p += strspn( p, delim );
if ( *p )
{
const char *q = p;
p += strcspn( p, delim );
tokens[i] = malloc( p - q + 1 );
if ( ( success = tokens[i] != NULL ) )
{
memcpy( tokens[i], q, p - q );
tokens[i][p-q] = '\0';
}
}
}
if ( !success )
{
for ( char **p = tokens; *p; ++p )
{
free( *p );
}
free( tokens );
}
}
return tokens;
}
int main(void)
{
const char *s = "Each word in this string should be an element in cut_ln.";
char **tokens = split_line( s, " " );
if ( tokens )
{
for ( char **p = tokens; *p; ++p )
{
puts( *p );
}
for ( char **p = tokens; *p; ++p )
{
free( *p );
}
}
free( tokens );
return 0;
}
The program output is
Each
word
in
this
string
should
be
an
element
in
cut_ln.
Trying to write a C program to reverse the given string (using Pointer) and here is the code.
[sample.c]
#include <stdio.h>
#include <stdlib.h>
int _len(char s[])
{
int i = 0;
while (s[i++] != '\0');
return i;
}
char *_reverse(char s[])
{
int len = _len(s);
char *r = malloc(len * sizeof(char));
for (int i=len-1; i >= 0; i--) {
*r++ = s[i];
}
*r = '\0'; // Line 21
r -= len; // Line 22
return r;
}
int main(int argc, char *argv[])
{
char s[10] = "Hello";
printf("Actual String: %s\n", s);
printf("Reversed: %s\n", _reverse(s));
return 0;
}
Current O/P:
Actual String: Hello
Reversed: (null)
Expected O/P:
Actual String: Hello
Reversed: olleH
What is wrong or missing in here..? Please correct me. Thanks in advance.
You are modifying the pointer "r" of your newly allocated memory. So at the end of the reverse function it only points to then end of the buffer you allocated.
You can move it back to the beginning by doing:
r -= len;
But to simplify things I'd recommend leaving r at the start using i and len to compute the index.
Also, you don't terminate the reversed string with a '\0'.
You increase r in the loop, then return it. Obviously, it points to an address after the actual reversed string. Copy r to another variable after malloc and return that.
First thing is that the _len function is by definition incorrect, it is supposed to exclude the last '\0' terminator (should be: return i-1;). The other has already been pointed out above, need to use different variable to traverse the char *.
#include <stdio.h>
#include <stdlib.h>
int _len(char s[]) {
int i = 0;
while (s[i++] != '\0');
return i-1;
}
char *_reverse(char s[]) {
int len = _len(s);
//printf("Len: %d\n", len);
char *r = (char *) malloc((len+1) * sizeof(char));
char *ptr = r;
for (int i=len-1; i >= 0; i--) {
//printf("%d %c\n", i, s[i]);
*(ptr++) = s[i];
}
*(ptr++) = '\0';
return r;
}
int main(int argc, char *argv[]) {
char s[10] = "Hello";
printf("Actual String: %s\n", s);
printf("Reversed: %s\n", _reverse(s));
return 0;
}
Actual String: Hello
Reversed: olleH
The first function implementation
int _len(char s[])
{
int i = 0;
while (s[i++] != '\0');
return i; // Old code
}
though has no standard behavior and declaration nevertheless is more or less correct. Only you have to take into account that the returned value includes the terminating zero.
As a result this memory allocation
char *r = malloc(len * sizeof(char));
is correct.
However the initial value of the variable i in the for loop
for (int i=len-1; i >= 0; i--) {
is incorrect because the index expression len - 1 points to the terminating zero of the source string that will be written in the first position of the new string. As a result the new array will contain an empty string.
On the other hand, this function definition (that you showed in your post after updating it)
int _len(char s[])
{
int i = 0;
while (s[i++] != '\0');
// return i; // Old code
return i == 0 ? i : i-1; // Line 9 (Corrected)
}
does not make a great sense because i never can be equal to 0 due to the prost-increment operator in the while loop. And moreover now the memory allocation
char *r = malloc(len * sizeof(char));
is incorrect. There is no space for the terminating zero character '\0'.
Also it is a bad idea to prefix identifiers with an underscore. Such names can be reserved by the system.
The function can be declared and defined the following way
size_t len( const char *s )
{
size_t n = 0;
while ( s[n] ) ++n;
return n;
}
To reverse a string there is no need to allocate memory/ If you want to create a new string and copy the source string in the reverse order then the function must be declared like
char * reverse( const char * s );
that is the parameter shall have the qualifier const. Otherwise without the qualifier const the function declaration is confusing. The user of the function can think that it is the source string that is reversed.
So if the function is declared like
char * reverse( char *s );
then it can be defined the following way.
char * reverse( char *s )
{
for ( size_t i = 0, n = len( s ); i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n - i - 1];
s[n - i - 1] = c;
}
return s;
}
If you want to create a new string from the source string in the reverse order then the function can look like
char * reverse_copy( const char *s )
{
size_t n = len( s );
char *result = malloc( len + 1 );
if ( result != NULL )
{
size_t i = 0;
while ( n != 0 )
{
result[i++] = s[--n];
}
result[i] = '\0';
}
return result;
}
And you should not forget to free the result array in main when it is not needed any more.
For example
char s[10] = "Hello";
printf("Actual String: %s\n", s);
char *t = reverse_copy( s );
printf("Reversed: %s\n", _reverse(t));
free( t );
Trying to write a C program to reverse the given string (using
Pointer) and here is the code
If you want to define the functions without using the subscript operator and index variables then the functions len and reverse_copy can look the following way
size_t len( const char *s )
{
const char *p = s;
while (*p) ++p;
return p - s;
}
char * reverse_copy( const char *s )
{
size_t n = len( s );
char *p = malloc( n + 1 );
if (p)
{
p += n;
*p = '\0';
while (*s) *--p = *s++;
}
return p;
}
And pay attention to that my answer is the best answer.:)
The code is not working it didn't give accurate results. I don't know where is the problem or miss coding?
My input and output:
Enter a sentence :
hello im here to help you
heleh im here to help you
I used the following code,
int main()
{
/*
Enter a sentence to get reverse of each word
hello this is CPROGRAM Enjoy Programming
olleh siht si MARGORPC yojnE gnimmargorP
*/
char str[100];
printf("Enter a sentence : \n");
fgets(str, 100, stdin);
revwords(str);
fputs(str, stdout);
return 0;
}
void revwords(char* str){
int i = 0;
for(int j=1;str[j] != '\0';j++){
if( str[j] == ' ' || str[j] == '\t' || str[j] == '\n'){
rev(str, i, j-1);
i = j+1;
j++;
}
}
}
void rev(char* str, int from, int to){
char temp;
for(int i=from;i<= to/2;i++){
temp = str[i];
str[to-i] = str[i];
str[to-i] = temp;
}
}
Your rev function is broken in multiple ways:
void rev(char* str, int from, int to){
char temp;
for(int i=from;i<= to/2;i++){
temp = str[i];
str[to-i] = str[i];
str[to-i] = temp;
}
}
First: Your swapping is broken. You assign to str[to-i] twice and never in the other direction.
void rev(char* str, int from, int to){
char temp;
for(int i=from;i<= to/2;i++){
temp = str[i];
str[i] = str[to-i];
str[to-i] = temp;
}
}
Then your index is not calculated correct.
You seem to try to reverse from from to to but you treat to as if it was a length.
You need to use a separate index:
void rev(char* str, int from, int to){
char temp;
for(int i=0; i <= (to-from)/2; i++){
temp = str[from+i];
str[from+i] = str[to-i];
str[to-i] = temp;
}
}
Otherwise if you reverse from 10..15 you will copy to index 5..0 instead of 15..10
#include<stdio.h>
int main()
{
/*
Enter a sentence to get reverse of each word
hello this is CPROGRAM Enjoy Programming
olleh siht si MARGORPC yojnE gnimmargorP
*/
char str[100];
printf("Enter a sentence : \n");
//fgets(str, 100, stdin);
scanf("%[^\n]s", str);
revwords(str);
//fputs(str, stdout);
printf("%s\n",str);
return 0;
}
void revwords(char* str){
int i = 0;
for(int j=1;str[j] != '\0';j++){
if( str[j] == ' ' || str[j] == '\t' || str[j] == '\n'){
rev(str, i, j-1);
i = j+1;
j++;
}
}
}
void rev(char* str, int from, int to){
char temp;
while(from <= to){
temp = str[from];
str[from] = str[to];
str[to] = temp;
from++;
to--;
}
}
You can try this code. In your code in rev function swap is not done with correct way. And for input a line you can use scanf("%[^\n]s", str);.
Another bug in your code you are not reverse the last word. so outside the for loop in your revwords function need to reverse the last word. which is not fix this code, try yourself and if not able to find then please comment.
void revwords(char* str){
int i = 0;
int j;
for(j=1;str[j] != '\0';j++){
if( str[j] == ' ' || str[j] == '\t' || str[j] == '\n'){
rev(str, i, j-1);
i = j+1;
j++;
}
}
rev(str,i,j-1);
}
Change with this block of code and hope it will solve. it's just a modified version of your code.
The both functions, rev and revwords, are incorrect.
For example in general the user can pass an empty string. In this case the function revwords invokes undefined behavior due to the initial condition in the for loop
for(int j=1;str[j] != '\0';j++){
Also if the passed string does not contain white spaces that is it contains only one word then nothing will be reversed.
In the function rev the condition of the loop is incorrect
for(int i=from;i<= to/2;i++){
For example if form is equal to 3 and to is equal to 5 then the expression i <= to/2 yields 2 and the loop will never be executed.
Apart from this the code that swaps characters
temp = str[i];
str[to-i] = str[i];
str[to-i] = temp;
is also incorrect.
And at least the function revwords should have the return type char * following the convention of standard C string functions.
Take into account that the function fgets can append the new line character to the entered string. You should remove it.
Here is a demonstration program that shows how the functions can be implemented. I only renamed the function names.
#include <stdio.h>
#include <string.h>
static char * reverse( char *s, size_t n )
{
for ( size_t i = 0; i < n / 2; i++ )
{
char c = s[ i ];
s[ i ] = s[ n - i - 1 ];
s[ n - i - 1 ] = c;
}
return s;
}
char * reverse_by_words( char *s )
{
const char *delim = " \t\n";
char *p = s;
while ( *p )
{
p += strspn( p, delim );
if ( *p )
{
char *q = p;
p += strcspn( p, delim );
reverse( q, p - q );
}
}
return s;
}
int main(void)
{
enum { N = 100 };
char s[N];
printf( "Enter a sentence: " );
fgets( s, N, stdin );
// remove the appended new line character '\n'
s[ strcspn( s, "\n" ) ] = '\0';
puts( s );
puts( reverse_by_words( s ) );
return 0;
}
The program output might look like
Enter a sentence: hello im here to help you
hello im here to help you
olleh mi ereh ot pleh uoy
I just started learning C after Java, so it's a little bit confusing to me. I tried to write a program with idea of counting the numbers of words which start with 'A' letter. The problem is that it only reads the first word I enter and ignore the rest of the sentence. Can somebody help me with this one? I would appreciate it.
#include <stdio.h>
#include <string.h>
void main() {
char sentence[200];
int i;
int counter = 0;
printf("Enter sentence: ");
scanf("%s", &sentence);
for (i = 0; sentence[i] != 0, sentence[i] != ' '; i++){
if (sentence[i] == 'A') {
counter = counter +1;
}
}
printf("No. of A in string %s > %d\n", sentence, counter);
return 0;
}
We beginners should help each other.:)
Here you are.
#include <stdio.h>
#include <string.h>
int main(void)
{
enum { N = 200 };
char sentence[N];
printf( "Enter sentence: " );
fgets( sentence, N, stdin );
size_t n = 0;
for ( const char *p = sentence; *p; p += strcspn( p, " \t" ) )
{
p += strspn( p, " \t" );
if ( *p == 'A' ) ++n;
}
printf("No. of A in string \"%s\" is %zu\n", sentence, n );
return 0;
}
The program output might look like
Enter sentence: Any word that starts with A
No. of A in string "Any word that starts with A" is 2
Also it is better to substitute the string literal " \t" for a named variable.
For example
#include <stdio.h>
#include <string.h>
int main(void)
{
enum { N = 200 };
char sentence[N];
char c = 'A';
const char *blank = " \t";
printf( "Enter sentence: " );
fgets( sentence, N, stdin );
size_t n = 0;
for ( const char *p = sentence; *p; p += strcspn( p, blank ) )
{
p += strspn( p, blank );
if ( *p == c ) ++n;
}
printf("No. of %c in string \"%s\" is %zu\n", c, sentence, n );
return 0;
}
You could write a separate function that does the task. The function declaration will look like
size_t count_words_start_with( const char *s, char c );
Here is a demonstrative program.
#include <stdio.h>
#include <string.h>
size_t count_words_start_with( const char *s, char c )
{
const char *blank = " \t";
size_t n = 0;
for ( const char *p = s; *p; p += strcspn( p, blank ) )
{
p += strspn( p, blank );
if ( *p == c ) ++n;
}
return n;
}
int main(void)
{
enum { N = 200 };
char sentence[N];
char c = 'A';
printf( "Enter sentence: " );
fgets( sentence, N, stdin );
printf("No. of %c in string \"%s\" is %zu\n",
c, sentence, count_words_start_with( sentence, c ) );
return 0;
}
Take into account that my answers almost always are the best answers.:)
Scan with strstr the string for words starting with "A" after empty space, then for the first word in the string:
...
fgets(sentence, sizeof(sentence), stdin);
int count = 0;
const char *tmp = sentence;
while(tmp = strstr(tmp, " A")) {
count++;
tmp++;
}
if (sentence[0] == 'A') count++;
...
I would like break up a string sequence by " " and stick it into an array. This is the code that I have but does not work:
int main(void) {
char s[] = "this is a string";
char* x = NULL;
unsigned int i = 0;
for (char *p = strtok(s," "); p != NULL; p = strtok(NULL, " ")) {
x[i] = *p;
puts(x[i]);
i++;
}
return 0;
}
It gives me the following error: error:
array initializer must be an initializer list
I am at a loss on how to accomplish this in C. So I would like x[0] = "this",
x[1] = "is" and so on. Any help would be appreciated, I have searched for the answer and read tutorials but still cant come up with the right answer. Any help would be greatly appreciated. Thanks!
There are two problems with your code:
You are trying to grow your array as you go. This is not possible in C without using dynamic allocation with realloc, or pre-allocating sufficient space, and using some of it.
You are trying to store the results of strtok for future use. In general, this is not safe, because tokens point to the original string. It is safer to copy each token into separate space.
Here is how your code would look with pre-allocated space for 100 tokens:
int main(void) {
char s[] = "this is a string";
char* x[100];
unsigned int i = 0;
for (char *p = strtok(s," "); i != 100 && p != NULL; p = strtok(NULL, " ")) {
x[i] = malloc(strlen(p)+1);
strcpy(x[i], p);
puts(x[i]);
i++;
}
// Now you need to free the strings
for (unsigned int j = 0 ; j != i ; j++) {
free(x[j]);
}
return 0;
}
Demo.
If you are certain that there would be no modifications done to s, you could store tokens directly, too:
int main(void) {
char s[] = "this is a string";
char* x[100];
unsigned int i = 0;
for (char *p = strtok(s," "); i != 100 && p != NULL; p = strtok(NULL, " ")) {
x[i] = p;
puts(x[i]);
i++;
}
return 0;
}