I am writing some C Code where the user enters the desired string size and then a string which will be reversed then printed (as opposed to being printed in reverse.) I also would like to mention that I don't want to use external libraries, the whole point of this is to be able to do it manually. I used dynamic memory allocation to create a string of a size inputted by the user and called a "Reverse Array" function. Everything works fine until the function is called. My method for reversing the string followed the same principle as reversing a normal array but instead of moving integers around I moved characters around. Can you explain to me what I have done wrong?
My Code:
#include <stdio.h>
#include <stdlib.h>
int RvsArr(char *Str, int end)
{
int start = 0;
char tmp;
while (start < end)
{
tmp = Str[start];
Str[start] = Str[end];
Str[end] = tmp;
start++;
end--;
}
printf("%s", Str);
return 0;
}
int main()
{
int ArrSz;
printf("Please enter array size: ");
scanf("%i", &ArrSz);
char *Str;
Str = (char *)malloc(ArrSz * sizeof(char));
printf("Please enter your string: ");
scanf("%s", Str);
RvsArr(Str, ArrSz);
free(Str);
return 0;
}
You need to reverse the actual string, not the full buffer.
char *RvsArr(char* Str)
{
char *end, *wrk = Str;
char tmp;
if(wrk && *wrk)
{
end = Str + strlen(wrk) - 1;
while(wrk < end)
{
tmp = *wrk;
*wrk++ = *end;
*end-- = tmp;
}
}
return Str;
}
int main()
{
int ArrSz;
printf("Please enter array size: ");
scanf(" %i", &ArrSz);
char* Str;
Str = malloc(ArrSz * sizeof(char));
printf("Please enter your string: ");
scanf(" %s", Str);
printf("\n`%s`\n", RvsArr(Str));
free(Str);
return 0;
}
https://godbolt.org/z/azob5s
For starters the user can enter a string the size of which can be less than the size of the dynamically allocated character array that stores the string.
So passing the size of the array does not make a sense. The size of the array is not the same as the size of the entered string.
Also this expression Str[end] access memory beyond the allocated array in the first iteration of the while loop.
And the return type int also does not make a sense.
Apart from this the function should not output anything. It is the caller of the function that will decide to output the result string or not.
Pay attention to that this call
scanf("%s", Str);
is unsafe. It would be better to use the function fgets. For example
fgets( Str, ArrSz, stdin );
In this case you will need to remove the new line character '\n' that the function can append to the entered string.
Without using standard string functions the function can be defined the following way as it is shown in the demonstrative program below.
Instead of the senseless return type int the function returns a pointer to the first character of the reversed string.
#include <stdio.h>
char * RvsArr( char *s )
{
char *last = s;
while ( *last ) ++last;
if ( last != s )
{
for ( char *first = s; first < --last; ++first )
{
char c = *first;
*first = *last;
*last = c;
}
}
return s;
}
int main(void)
{
char s[] = "Hello World!";
puts( s );
puts( RvsArr( s ) );
return 0;
}
The program output is
Hello World!
!dlroW olleH
If you are allowed to use standard string functions then the function RvsArr can look the following way (provided that the header <string.h> is included)
char * RvsArr( char *s )
{
char *last = s + strlen( s );
if ( last != s )
{
for ( char *first = s; first < --last; ++first )
{
char c = *first;
*first = *last;
*last = c;
}
}
return s;
}
Character arrays or string in c(as it is generally referred to) requires one extra byte which store null character ('\o' or 0) to indicate the end of string. You can store ArrSz - 1 character in your array and ArrSz byte stores the termination character('\o' or 0).
int RvsArr(char* Str, int end)
{
if (Str == 0 || end <= 1)
return 0;
int start = 0;
char tmp;
while(start < end)
{
tmp = Str[start];
Str[start] = Str[--end]; // pre decrement the counter to last char
Str[end] = tmp;
start++;
}
printf("%s", Str);
return 0;
}
or in other version
int RvsArr(char* Str, int end)
{
if (Str == 0 || end <= 1)
return 0;
int start = 0;
int last = end - 1;
char tmp;
while(start < last)
{
tmp = Str[start];
Str[start] = Str[last];
Str[last] = tmp;
start++;
last--;
}
printf("%s", Str);
return 0;
}
And some changes in main function are
int main()
{
int ArrSz;
printf("Please enter array size: ");
scanf("%i", &ArrSz);
char *Str;
Str = (char *)malloc(ArrSz * sizeof(char));
printf("Please enter your string: ");
scanf("%s", Str);
Str[ArrSz] = '\0'; // Here we have no control on how many characters are read, scan is a security vulnerability becuse of this
printf("Input=%s, len=%d\n", Str, strlen(Str));
RvsArr(Str, strlen(Str));
free(Str);
return 0;
}
Related
I'm trying to create word generator in C and found Segmentation Fault message.
gdb output :
_GI___strtok_r (
s=0x562d88201188 "some text without comma",
delim=0x562d8820117f " ", save_ptr=0x7f570a47aa68 <olds>) at strtok_r.c:72
code with strtox function :
char **words = malloc(sizeof(char *) * NUM_WORDS);
int num_words = 0;
char *save_ptr;
char *word = strtok(text, " ");
while (word != NULL) {
// Strip leading and trailing whitespace
while (isspace(*word)) {
word++;
}
int len = strlen(word);
while (len > 0 && isspace(word[len - 1])) {
len--;
}
// Allocate memory for the word and copy it using strdup()
words[num_words] = strdup(word);
// Move to the next word
num_words++;
word = strtok(NULL, " ");
}
how to use function with an indeterminate number of words in text?
Can't believe someone finally asked for this!
You may want to add verification that realloc() hasn't returned a NULL.
In brief, the string is chopped on the delimiters provided to strtok() while realloc() is used to grow an array of pointers to each of those segments.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char buf[] = "Once upon a time there lived a beautiful princess.", *p = buf;
char **t = NULL; size_t sz = sizeof *t;
int n = 0;
while(!!(t=realloc(t,(n+1)*sz))&&!!(t[n]=strtok(p," .\n"))) p=NULL, n++;
for( int i = 0; i < n; i++ )
puts( t[i] );
free( t );
return 0;
}
Once
upon
a
time
there
lived
a
beautiful
princess
EDIT
Then there is the extension that can handle multiple input lines:
int main() {
char *buf[] = { "Once upon a time\n", "there lived\n", " a beautiful princess.\n" };
char **t = NULL; size_t sz = sizeof *t;
int n = 0;
for( int ln = 0; ln < sizeof buf/sizeof buf[0]; ln++ ) {
char *p = buf[ln];
while(!!(t=realloc(t,(n+1)*sz))&&!!(t[n]=strtok(p," .\n"))) p=NULL, n++;
}
for( int i = 0; i < n; i++ )
puts( t[i] );
free( t );
return 0;
}
/* Output same as shown above */
Put the strtok() as the parameter to strdup() and you've got yourself something that will preserve words while using a single line input buffer.
How do i make below program work properly, The main problem i have seen so far is str1 is not defined properly which may be the real cause for the program not working properly.
#include<stdio.h>
#include<string.h>
int main()
{
char string[]="We will rock you";
char s1[10],s2[10];
printf("Enter string 1 ");
gets(s1);
printf("Enter string 2 ");
gets(s2);
int start,end,compare;
for(int i=0;string[i]!='\0';i++)
if(string[i]==s1[0])
{
start=i;
break;
}
//printf("%d",start);
end=start+strlen(s1);
//printf("\n%d",end);
char str1[30],check[10];
//Defining string 1
for(int i=0;i<start;i++)
str1[i]=string[i];
//printf("\n%sd",str1);
//Defining check
for(int i=start;i<end;i++)
check[i-start]=string[i];
//printf("\n%s\n",check,str1);
compare=strcmp(check,s1);
//printf("\n%d",compare);
if(compare==0)
strcat(str1,s1);
printf("\n%s",str1);
for(int i=end,j=strlen(str1);i<strlen(string);i++)
{
str1[j]=string[i];
}
strcpy(string,str1);
printf("\n%s",string);
}
I know this is not the best way to do it, it has so many loopholes as it wont work for words appearing again and it may also change words like (ask, task or asking) if str1 is given ask.
But still help me , What am i doing wrong???
What am i doing wrong???
For starters the function gets is unsafe and is not supported by the C Standard. Instead either use scanf or fgets.
If in this for loop
int start,end,compare;
for(int i=0;string[i]!='\0';i++)
if(string[i]==s1[0])
{
start=i;
break;
}
the condition string[i]==s1[0] does not evaluate to true then the variable start will have an indeterminate value because it is not initialized and all the subsequent code after the for loop invokes undefined behavior because there is used the uninitialized variable start.
If the condition evaluates to true then the value of end
end=start+strlen(s1);
can be larger than the length of the original string string. That again can invoke undefined behavior in this for loop
for(int i=0;i<start;i++)
str1[i]=string[i];
After this for loop
for(int i=start;i<end;i++)
check[i-start]=string[i];
//printf("\n%s\n",check,str1);
compare=strcmp(check,s1);
the array check does not contain a string. So calling the function strcmp also invokes undefined behavior.
It seems that in this call there is at least a typo.
if(compare==0)
strcat(str1,s1)
it seems you mean
strcat( str1, s2 );
^^^
If s1 was not found in string then this loop
for(int i=end,j=strlen(str1);i<strlen(string);i++)
{
str1[j]=string[i];
}
just does not make a sense.
Pay attention to that in general the length of s2 can be greater than the length of s1. In this case you may not change s1 to s2 within string declared like
char string[]="We will rock you";
because that results in accessing memory outside the array.
Function replacing string in the string.
char *strreplace(char *haystack, const char *needle, const char *replace, char *buff)
{
int length = strlen(haystack);
int needlelength = strlen(needle);
int replacelength = strlen(replace);
char *ptr = buff;
char *start, *source, *dest;
if (buff == NULL)
{
ptr = malloc((length + 1) * sizeof(char));
source = ptr;
dest = haystack;
}
else
{
source = haystack;
dest = buff;
}
if (ptr != NULL)
{
if (buff == NULL) strcpy(ptr, haystack);
else
{
if (!length)
{
*buff = 0;
}
}
while (needlelength && *source)
{
size_t chunklen;
char *result;
start = source;
if ((result = strstr(source, needle)) == NULL)
{
strcpy(dest, source);
break;
}
chunklen = result - start;
strncpy(dest, start, chunklen);
dest += chunklen;
strcpy(dest, replace);
dest += replacelength;
source = result;
source += needlelength;
}
if (buff == NULL)
{
free(ptr);
ptr = haystack;
}
else
{
ptr = buff;
}
}
return ptr;
}
Hello and Sorry for bad English.
I think this code can help you
char* replace ( char text[] , char mainchar, char replace_char )
{
char out [120];
char* out_pointer = out ;
register char index_2=0;
for ( register char index_1 = 0 ; index_1 < strlen (text) ; ++index_1 )
{
if ( text[index_1] != mainchar )
{
out_pointer[index_2]=text[index_1];
++index_2 ;
}
else
{
out_pointer[index_2]=replace_char;
++index_2 ;
}
}
return out_pointer;
}
To use this function in your source code, proceed as follows :
#include <stdio.h>
#include <string.h>
int main ()
{
char* replace ( char text[] , char mainchar, char replace_char )
{
char out [120];
char* out_pointer = out ;
register char index_2=0;
for ( register char index_1 = 0 ; index_1 < strlen (text) ; ++index_1 )
{
if ( text[index_1] != mainchar )
{
out_pointer[index_2]=text[index_1];
++index_2 ;
}
else
{
out_pointer[index_2]=replace_char;
++index_2 ;
}
}
return out_pointer;
}
char Array[100];
strcpy (Array, replace("Hello", 'H', 'e'));
printf ("%s", Array);
}
This question already has answers here:
What is a debugger and how can it help me diagnose problems?
(2 answers)
Closed 4 years ago.
I tried to develop a function which take a string reverse letters and return pointer to string.
char *reverseStr(char s[])
{
printf("Initial string is: %s\n", s);
int cCounter = 0;
char *result = malloc(20);
while(*s != '\0')
{
cCounter++;
s++;
}
printf("String contains %d symbols\n", cCounter);
int begin = cCounter;
for(; cCounter >= 0; cCounter--)
{
result[begin - cCounter] = *s;
s--;
}
result[13] = '\0';
return result;
}
in main function I invoke the function and tried to print the result in this way:
int main()
{
char testStr[] = "Hello world!";
char *pTestStr;
puts("----------------------------------");
puts("Input a string:");
pTestStr = reverseStr(testStr);
printf("%s\n", pTestStr);
free(pTestStr);
return 0;
}
but the result is unexpected, there is no reverse string.
What is my fault?
There are multiple mistakes in the shared code, primarily -
s++; move the pointer till '\0'. It should be brought back 1 unit to
point to actual string by putting s--. Other wise the copied one will start with '\0' that will make it empty string.
Magic numbers 20 and 13. where in malloc() 1 + length of s should be
sufficient instead or 20. For 13 just move a unit ahead and put '\0'
However, using string.h library functions() this can be super easy. But I think you are doing it for learning purpose.
Therefore, Corrected code without using string.h lib function() should look like this:
char *reverseStr(char s[])
{
printf("Initial string is: %s\n", s);
int cCounter = 0;
while(*s != '\0')
{
cCounter++;
s++;
}
s--; //move pointer back to point actual string's last charecter
printf("String contains %d symbols\n", cCounter);
char *result = (char *) malloc(sizeof(char) * ( cCounter + 1 ));
if( result == NULL ) /*Check for failure. */
{
puts( "Can't allocate memory!" );
exit( 0 );
}
char *tempResult = result;
for (int begin = 0; begin < cCounter; begin++)
{
*tempResult = *s;
s--; tempResult++;
}
*tempResult = '\0';
//result[cCounter+1] = '\0';
return result;
}
Calling from main
int main()
{
char testStr[] = "Hello world!";
char *pTestStr;
puts("----------------------------------");
puts("Input a string:");
pTestStr = reverseStr(testStr);
printf("%s\n", pTestStr);
free(pTestStr);
}
Output
----------------------------------
Input a string:
Initial string is: Hello world!
String contains 12 symbols
!dlrow olleH
As per WhozCraig suggestion just by using pointer arithmetic only -
char *reverseStr(const char s[])
{
const char *end = s;
while (*end)
++end;
char *result = malloc((end - s) + 1), *beg = result;
if (result == NULL)
{
perror("Failed to allocate string buffer");
exit(EXIT_FAILURE);
}
while (end != s)
*beg++ = *--end;
*beg = 0;
return result;
}
Your code can be simplified using a string library function found in string.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *reverseStr(char s[])
{
printf("Initial string is: %s\n", s);
int cCounter = strlen(s);
char *result = malloc(cCounter + 1);
printf("String contains %d symbols\n", cCounter);
int begin = cCounter;
for(; cCounter > 0; cCounter--)
{
result[begin - cCounter] = s[cCounter - 1];
}
result[begin] = '\0';
return result;
}
int main()
{
char testStr[] = "Hello world!";
char *pTestStr;
puts("----------------------------------");
puts("Input a string:");
pTestStr = reverseStr(testStr);
printf("%s\n", pTestStr);
free(pTestStr);
return 0;
}
Output:
----------------------------------
Input a string:
Initial string is: Hello world!
String contains 12 symbols
!dlrow olleH
I want to write a program in C that displays each word of a whole sentence (taken as input) at a seperate line. This is what I have done so far:
void manipulate(char *buffer);
int get_words(char *buffer);
int main(){
char buff[100];
printf("sizeof %d\nstrlen %d\n", sizeof(buff), strlen(buff)); // Debugging reasons
bzero(buff, sizeof(buff));
printf("Give me the text:\n");
fgets(buff, sizeof(buff), stdin);
manipulate(buff);
return 0;
}
int get_words(char *buffer){ // Function that gets the word count, by counting the spaces.
int count;
int wordcount = 0;
char ch;
for (count = 0; count < strlen(buffer); count ++){
ch = buffer[count];
if((isblank(ch)) || (buffer[count] == '\0')){ // if the character is blank, or null byte add 1 to the wordcounter
wordcount += 1;
}
}
printf("%d\n\n", wordcount);
return wordcount;
}
void manipulate(char *buffer){
int words = get_words(buffer);
char *newbuff[words];
char *ptr;
int count = 0;
int count2 = 0;
char ch = '\n';
ptr = buffer;
bzero(newbuff, sizeof(newbuff));
for (count = 0; count < 100; count ++){
ch = buffer[count];
if (isblank(ch) || buffer[count] == '\0'){
buffer[count] = '\0';
if((newbuff[count2] = (char *)malloc(strlen(buffer))) == NULL) {
printf("MALLOC ERROR!\n");
exit(-1);
}
strcpy(newbuff[count2], ptr);
printf("\n%s\n",newbuff[count2]);
ptr = &buffer[count + 1];
count2 ++;
}
}
}
Although the output is what I want, I have really many black spaces after the final word displayed, and the malloc() returns NULL so the MALLOC ERROR! is displayed in the end.
I can understand that there is a mistake at my malloc() implementation, but I do not know what it is.
Is there another more elegant or generally better way to do it?
http://www.cplusplus.com/reference/clibrary/cstring/strtok/
Take a look at this, and use whitespace characters as the delimiter. If you need more hints let me know.
From the website:
char * strtok ( char * str, const char * delimiters );
On a first call, the function expects a C string as argument for str, whose first character is used as the starting location to scan for tokens. In subsequent calls, the function expects a null pointer and uses the position right after the end of last token as the new starting location for scanning.
Once the terminating null character of str is found in a call to strtok, all subsequent calls to this function (with a null pointer as the first argument) return a null pointer.
Parameters
str
C string to truncate.
Notice that this string is modified by being broken into smaller strings (tokens).
Alternativelly [sic], a null pointer may be specified, in which case the function continues scanning where a previous successful call to the function ended.
delimiters
C string containing the delimiter characters.
These may vary from one call to another.
Return Value
A pointer to the last token found in string.
A null pointer is returned if there are no tokens left to retrieve.
Example
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
For the fun of it here's an implementation based on the callback approach:
const char* find(const char* s,
const char* e,
int (*pred)(char))
{
while( s != e && !pred(*s) ) ++s;
return s;
}
void split_on_ws(const char* s,
const char* e,
void (*callback)(const char*, const char*))
{
const char* p = s;
while( s != e ) {
s = find(s, e, isspace);
callback(p, s);
p = s = find(s, e, isnotspace);
}
}
void handle_word(const char* s, const char* e)
{
// handle the word that starts at s and ends at e
}
int main()
{
split_on_ws(some_str, some_str + strlen(some_str), handle_word);
}
malloc(0) may (optionally) return NULL, depending on the implementation. Do you realize why you may be calling malloc(0)? Or more precisely, do you see where you are reading and writing beyond the size of your arrays?
Consider using strtok_r, as others have suggested, or something like:
void printWords(const char *string) {
// Make a local copy of the string that we can manipulate.
char * const copy = strdup(string);
char *space = copy;
// Find the next space in the string, and replace it with a newline.
while (space = strchr(space,' ')) *space = '\n';
// There are no more spaces in the string; print out our modified copy.
printf("%s\n", copy);
// Free our local copy
free(copy);
}
Something going wrong is get_words() always returning one less than the actual word count, so eventually you attempt to:
char *newbuff[words]; /* Words is one less than the actual number,
so this is declared to be too small. */
newbuff[count2] = (char *)malloc(strlen(buffer))
count2, eventually, is always one more than the number of elements you've declared for newbuff[]. Why malloc() isn't returning a valid ptr, though, I don't know.
You should be malloc'ing strlen(ptr), not strlen(buf). Also, your count2 should be limited to the number of words. When you get to the end of your string, you continue going over the zeros in your buffer and adding zero size strings to your array.
Just as an idea of a different style of string manipulation in C, here's an example which does not modify the source string, and does not use malloc. To find spaces I use the libc function strpbrk.
int print_words(const char *string, FILE *f)
{
static const char space_characters[] = " \t";
const char *next_space;
// Find the next space in the string
//
while ((next_space = strpbrk(string, space_characters)))
{
const char *p;
// If there are non-space characters between what we found
// and what we started from, print them.
//
if (next_space != string)
{
for (p=string; p<next_space; p++)
{
if(fputc(*p, f) == EOF)
{
return -1;
}
}
// Print a newline
//
if (fputc('\n', f) == EOF)
{
return -1;
}
}
// Advance next_space until we hit a non-space character
//
while (*next_space && strchr(space_characters, *next_space))
{
next_space++;
}
// Advance the string
//
string = next_space;
}
// Handle the case where there are no spaces left in the string
//
if (*string)
{
if (fprintf(f, "%s\n", string) < 0)
{
return -1;
}
}
return 0;
}
you can scan the char array looking for the token if you found it just print new line else print the char.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *s;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
s = realloc(s, strlen(s) + 1);
int len = strlen(s);
char delim =' ';
for(int i = 0; i < len; i++) {
if(s[i] == delim) {
printf("\n");
}
else {
printf("%c", s[i]);
}
}
free(s);
return 0;
}
char arr[50];
gets(arr);
int c=0,i,l;
l=strlen(arr);
for(i=0;i<l;i++){
if(arr[i]==32){
printf("\n");
}
else
printf("%c",arr[i]);
}
I was having some difficulties when trying to print out the string pointer after dynamically insert a character at the front of char array.
The parameter *str is a dynamic char array from my main whereas the input is a single character which should append to the first element of the dynamic array after executing the insert().
int main(){
//code snippet. I removed other part to keep the question short
printf("How many characters do you want to input: ");
scanf("%d", &n);
str = malloc(n + 1);
printf("Input the string class: ");
scanf("%s", str);
//switch statement
case '1':
printf("What is the character you want to insert: ");
scanf(" %c", &input);
insert(&str, input);
break;
}
return 0;
}
void insert(char *str, char input) {
char *new_str;
int i, len = strlen(str);
new_str = malloc(len + 1);
new_str[0] = input;
strncpy(&new_str[1], str, len - 1);
new_str[len] = 0;
for (i = 0; i < len; i++) {
printf("%c", new_str[i]);
}
}
When I tried to loop thru the new_str and print out the string array, it gives me weird symbols and I have no idea what are they. Any ideas?
EDIT
The expected output as below:
How many characters do you want to input: 5
Input the string:datas
The string is: datas
Do you want to 1-insert or 2-remove or 3-quit?: 1
What is the character you want to insert: a
Resulting string: adata
The output I am getting:
Alternative version, avoiding any string copy functions. (Since, alter the strlen() you already know the string length to copy, you don't need any more string functions)
char * insert_a_character(char * str, char ch)
{
char * new;
size_t len;
if (!str) return NULL;
len = strlen(str);
new = malloc (1+len+1);
if (!new) retun NULL;
new[0] = ch;
memcpy(new+1, str, len);
new[len+1] = 0;
return new;
}
I assume that the caller will free if required for orig
char * insert(char *orig, char input) {
char * new_str = malloc(strlen(orig) + 2); // An extra one for null
strcpy(new_str + 1, orig);
new_str[0] = input;
printf("%s", new_str); // To print it out
return new_str; // The caller needs to free this;
}
That should work.
Assembling all comments:
void insert(char *str, char input) {
char *new_str;
int i, len = strlen(str);
new_str = malloc(len + 2);
new_str[0] = input;
strcpy(new_str+1, str);
new_str[len+1] = 0;
for (i = 0; i <= len; i++) {
printf("%c", new_str[i]);
}
}
Of course you still need to do something with the new string, such as returning it or freeing it.