how I do to repeat a string?
something like "hello world" * 3
the output "hello world hello world hello world"
In your source code, without much processing, probably the easiest way is with:
#define HI "hello world"
char str[] = HI " " HI " " HI;
This will declare a string of the requested value:
"hello world hello world hello world"
If you want code that will do it, you can use something like:
char *repeatStr (char *str, size_t count) {
if (count == 0) return NULL;
char *ret = malloc (strlen (str) * count + count);
if (ret == NULL) return NULL;
strcpy (ret, str);
while (--count > 0) {
strcat (ret, " ");
strcat (ret, str);
}
return ret;
}
Now keep in mind this can be made more efficient - multiple strcat operations are ripe for optimisation to avoid processing the data over and over (a). But this should be a good enough start.
You're also responsible for freeing the memory returned by this function.
(a) Such as with:
// Like strcat but returns location of the null terminator
// so that the next myStrCat is more efficient.
char *myStrCat (char *s, char *a) {
while (*s != '\0') s++;
while (*a != '\0') *s++ = *a++;
*s = '\0';
return s;
}
char *repeatStr (char *str, size_t count) {
if (count == 0) return NULL;
char *ret = malloc (strlen (str) * count + count);
if (ret == NULL) return NULL;
*ret = '\0';
char *tmp = myStrCat (ret, str);
while (--count > 0) {
tmp = myStrCat (tmp, " ");
tmp = myStrCat (tmp, str);
}
return ret;
}
You could use sprintf.
char s[20] = "Hello";
char s2[20];
sprintf(s2,"%s%s%s",s,s,s);
I've made this function based on earlier answers in this post.
I share it here because some of previous examples has been thrown me segfaults
const char* str_repeat(char* str, size_t times)
{
if (times < 1) return NULL;
char *ret = malloc(sizeof(str) * times + 1);
if (ret == NULL) return NULL;
strcpy(ret, &str);
while (--times > 0) {
strcat(ret, &str);
}
return ret;
}
http://ideone.com/5sNylW
#include <stdio.h>
#include <string.h>
int main(void) {
char k[100];
gets(k);
int lk=strlen(k);
int times;
scanf("%d",×);
int tl= times*lk;
int i,x=0;
for(i=lk-1;i<tl;i++)
{
k[i+1]=k[x];
x++;
}
for(i=0;i<tl;i++)
{
printf("%c",k[i]);
}
return 0;
}
You may try write own function. It will be work with single-length string also (i. e. duplication a single char). It use the function "strcat()" from the "string.h", so do not forget include this header.
char *
str_repeat(char str[], unsigned int times)
{
if (times < 1)
return NULL;
char *result;
size_t str_len = strlen(str);
result = malloc(sizeof(char) * str_len + 1);
while (times--) {
strcat(result, str);
}
return result;
}
But, if you need only duplication of a string for print it, try macro
#define PRINT_STR_REPEAT(str, times) \
{ \
for (int i = 0; i < times; ++i) \
printf("%s", str); \
puts(""); \
}
Results
PRINT_STR_REPEAT("-", 10); // ----------
puts(str_repeat("-", 10)); // ----------
PRINT_STR_REPEAT("$", 2); // $$
puts(str_repeat("$", 2)); // $$
PRINT_STR_REPEAT("*\t*", 10); // * ** ** ** ** ** ** ** ** ** *
puts(str_repeat("*\t*", 10)); // * ** ** ** ** ** ** ** ** ** *
PRINT_STR_REPEAT("*_*", 10); // *_**_**_**_**_**_**_**_**_**_*
puts(str_repeat("*_*", 10)); // *_**_**_**_**_**_**_**_**_**_*
Here's a way to repeat a string in C, N times.
That is have a string "abc"
and I want a string of length 7 that is comprised of this string repeated.
N = 7;
result: "abcabca"
while(Index != N){
repeatedString[Index] = oldString[Index%strlen(oldString)];
Index++;
}
Where repeated String would be "abcabca" at the end, and oldString is "abc".
Related
I am getting used to writing eBPF code as of now and want to avoid using pointers in my BPF text due to how difficult it is to get a correct output out of it. Using strtok() seems to be out of the question due to all of the example codes requiring pointers. I also want to expand it to CSV files in the future since this is a means of practice for me. I was able to find another user's code here but it gives me an error with the BCC terminal due to the one pointer.
char str[256];
bpf_probe_read_user(&str, sizeof(str), (void *)PT_REGS_RC(ctx));
char token[] = strtok(str, ",");
char input[] ="first second third forth";
char delimiter[] = " ";
char firstWord, *secondWord, *remainder, *context;
int inputLength = strlen(input);
char *inputCopy = (char*) calloc(inputLength + 1, sizeof(char));
strncpy(inputCopy, input, inputLength);
str = strtok_r (inputCopy, delimiter, &context);
secondWord = strtok_r (NULL, delimiter, &context);
remainder = context;
getchar();
free(inputCopy);
Pointers are powerful, and you wont be able to avoid them for very long. The time you invest in learning them is definitively worth it.
Here is an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
Extracts the word with the index "n" in the string "str".
Words are delimited by a blank space or the end of the string.
}*/
char *getWord(char *str, int n)
{
int words = 0;
int length = 0;
int beginIndex = 0;
int endIndex = 0;
char currentchar;
while ((currentchar = str[endIndex++]) != '\0')
{
if (currentchar == ' ')
{
if (n == words)
break;
if (length > 0)
words++;
length = 0;
beginIndex = endIndex;
continue;
}
length++;
}
if (n == words)
{
char *result = malloc(sizeof(char) * length + 1);
if (result == NULL)
{
printf("Error while allocating memory!\n");
exit(1);
}
memcpy(result, str + beginIndex, length);
result[length] = '\0';
return result;
}else
return NULL;
}
You can easily use the function:
int main(int argc, char *argv[])
{
char string[] = "Pointers are cool!";
char *word = getWord(string, 2);
printf("The third word is: '%s'\n", word);
free(word); //Don't forget to de-allocate the memory!
return 0;
}
I have a variable length string that I am trying to divide from plus signs and study on:
char string[] = "var1+vari2+varia3";
for (int i = 0; i != sizeof(string); i++) {
memcpy(buf, string[0], 4);
buf[9] = '\0';
}
since variables are different in size I am trying to write something that is going to take string into loop and extract (divide) variables. Any suggestions ? I am expecting result such as:
var1
vari2
varia3
You can use strtok() to break the string by delimiter
char string[]="var1+vari2+varia3";
const char delim[] = "+";
char *token;
/* get the first token */
token = strtok(string, delim);
/* walk through other tokens */
while( token != NULL ) {
printf( " %s\n", token );
token = strtok(NULL, delim);
}
More info about the strtok() here: https://man7.org/linux/man-pages/man3/strtok.3.html
It seems to me that you don't just want to want to print the individual strings but want to save the individual strings in some buffer.
Since you can't know the number of strings nor the length of the individual string, you should allocate memory dynamic, i.e. use functions like realloc, calloc and malloc.
It can be implemented in several ways. Below is one example. To keep the example simple, it's not performance optimized in anyway.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
char** split_string(const char* string, const char* token, int* num)
{
assert(string != NULL);
assert(token != NULL);
assert(num != NULL);
assert(strlen(token) != 0);
char** data = NULL;
int num_strings = 0;
while(*string)
{
// Allocate memory for one more string pointer
char** ptemp = realloc(data, (num_strings + 1) * sizeof *data);
if (ptemp == NULL) exit(1);
data = ptemp;
// Look for token
char* tmp = strstr(string, token);
if (tmp == NULL)
{
// Last string
// Allocate memory for one more string and copy it
int len = strlen(string);
data[num_strings] = calloc(len + 1, 1);
if (data[num_strings] == NULL) exit(1);
memcpy(data[num_strings], string, len);
++num_strings;
break;
}
// Allocate memory for one more string and copy it
int len = tmp - string;
data[num_strings] = calloc(len + 1, 1);
if (data[num_strings] == NULL) exit(1);
memcpy(data[num_strings], string, len);
// Prepare to search for next string
++num_strings;
string = tmp + strlen(token);
}
*num = num_strings;
return data;
}
int main()
{
char string[]="var1+vari2+varia3";
// Split the string into dynamic allocated memory
int num_strings;
char** data = split_string(string, "+", &num_strings);
// Now data can be used as an array-of-strings
// Example: Print the strings
printf("Found %d strings:\n", num_strings);
for(int i = 0; i < num_strings; ++i) printf("%s\n", data[i]);
// Free the memory
for(int i = 0; i < num_strings; ++i) free(data[i]);
free(data);
}
Output
Found 3 strings:
var1
vari2
varia3
You can use a simple loop scanning the string for + signs:
char string[] = "var1+vari2+varia3";
char buf[sizeof(string)];
int start = 0;
for (int i = 0;;) {
if (string[i] == '+' || string[i] == '\0') {
memcpy(buf, string + start, i - start);
buf[i - start] = '\0';
// buf contains the substring, use it as a C string
printf("%s\n", buf);
if (string[i] == '\0')
break;
start = ++i;
} else {
i++;
}
}
Your code does not have any sense.
I wrote such a function for you. Analyse it as sometimes is good to have some code as a base
char *substr(const char *str, char *buff, const size_t start, const size_t len)
{
size_t srcLen;
char *result = buff;
if(str && buff)
{
if(*str)
{
srcLen = strlen(str);
if(srcLen < start + len)
{
if(start < srcLen) strcpy(buff, str + start);
else buff[0] = 0;
}
else
{
memcpy(buff, str + start, len);
buff[len] = 0;
}
}
else
{
buff[0] = 0;
}
}
return result;
}
https://godbolt.org/z/GjMEqx
I have a program, that splits strings based on the delimiter. I have also, 2 other functions, one that prints the returned array and another that frees the array.
My program prints the array and returns an error when the free array method is called. Below is the full code.
#include "stringsplit.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
/* Split string by another string, return split parts + NULL in array.
*
* Parameters:
* str: the string to split
* split: the string to split str with
*
* Returns:
* A dynamically reserved array of dynamically reserved string parts.
*
* For example called with "Test string split" and " ",
* returns ["Test", "string", "split", NULL].
* Or called with "Another - test" and " - ",
* returns ["Another", "test", NULL].
*/
unsigned long int getNofTokens(const char *string) {
char *stringCopy;
unsigned long int stringLength;
unsigned long int count = 0;
stringLength = (unsigned)strlen(string);
stringCopy = malloc((stringLength + 1) * sizeof(char));
strcpy(stringCopy, string);
if (strtok(stringCopy, " \t") != NULL) {
count++;
while (strtok(NULL, " \t") != NULL)
count++;
}
free(stringCopy);
return count;
}
char **split_string(const char *str, const char *split) {
unsigned long int count = getNofTokens(str);
char **result;
result = malloc(sizeof(char *) * count + 1);
char *tmp = malloc(sizeof(char) * strlen(str));
strcpy(tmp, str);
char *token = strtok(tmp, split);
int idx = 0;
while (token != NULL) {
result[idx++] = token;
token = strtok(NULL, split);
}
return result;
}
void print_split_string(char **split_string) {
for (int i = 0; split_string[i] != NULL; i++) {
printf("%s\n", split_string[i]);
}
}
void free_split_string(char **split_string) {
for (int i = 0; split_string[i] != NULL; i++) {
char *currentPointer = split_string[i];
free(currentPointer);
}
free(split_string);
}
Also, do I need to explicitly add \0 at the end of the array or does strtok add it automatically?
There are some problems in your code:
[Major] the function getNofTokens() does not take the separator string as an argument, it counts the number of words separated by blanks, potentially returning an inconsistent count to its caller.
[Major] the size allocated in result = malloc(sizeof(char *) * count + 1); is incorrect: it should be:
result = malloc(sizeof(char *) * (count + 1));
Storing the trailing NULL pointer will write beyond the end of the allocated space.
[Major] storing the said NULL terminator at the end of the array is indeed necessary, as the block of memory returned by malloc() is uninitialized.
[Major] the copy of the string allocated and parsed by split_string cannot be safely freed because the pointer tmp is not saved anywhere. The pointer to the first token will be different from tmp in 2 cases: if the string contains only delimiters (no token found) or if the string starts with a delimiter (the initial delimiters will be skipped). In order to simplify the code and make it reliable, each token could be duplicated and tmp should be freed. In fact your free_split_string() function relies on this behavior. With the current implementation, the behavior is undefined.
[Minor] you use unsigned long and int inconsistently for strings lengths and array index variables. For consistency, you should use size_t for both.
[Remark] you should allocate string copies with strdup(). If this POSIX standard function is not available on your system, write a simple implementation.
[Major] you never test for memory allocation failure. This is OK for testing purposes and throw away code, but such potential failures should always be accounted for in production code.
[Remark] strtok() is a tricky function to use: it modifies the source string and keeps a hidden static state that makes it non-reentrant. You should avoid using this function although in this particular case it performs correctly, but if the caller of split_string or getNofTokens relied on this hidden state being preserved, it would get unexpected behavior.
Here is a modified version:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "stringsplit.h"
/* Split string by another string, return split parts + NULL in array.
*
* Parameters:
* str: the string to split
* split: the string to split str with
*
* Returns:
* A dynamically reserved array of dynamically reserved string parts.
*
* For example called with "Test string split" and " ",
* returns ["Test", "string", "split", NULL].
* Or called with "Another - test" and " - ",
* returns ["Another", "test", NULL].
*/
size_t getNofTokens(const char *string, const char *split) {
char *tmp = strdup(string);
size_t count = 0;
if (strtok(tmp, split) != NULL) {
count++;
while (strtok(NULL, split) != NULL)
count++;
}
free(tmp);
return count;
}
char **split_string(const char *str, const char *split) {
size_t count = getNofTokens(str, split);
char **result = malloc(sizeof(*result) * (count + 1));
char *tmp = strdup(str);
char *token = strtok(tmp, split);
size_t idx = 0;
while (token != NULL && idx < count) {
result[idx++] = strdup(token);
token = strtok(NULL, split);
}
result[idx] = NULL;
free(tmp);
return result;
}
void print_split_string(char **split_string) {
for (size_t i = 0; split_string[i] != NULL; i++) {
printf("%s\n", split_string[i]);
}
}
void free_split_string(char **split_string) {
for (size_t i = 0; split_string[i] != NULL; i++) {
free(split_string[i]);
}
free(split_string);
}
Here is an alternative without strtok() and without intermediary allocations:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "stringsplit.h"
size_t getNofTokens(const char *str, const char *split) {
size_t count = 0;
size_t pos = 0, len;
for (pos = 0;; pos += len) {
pos += strspn(str + pos, split); // skip delimiters
len = strcspn(str + pos, split); // parse token
if (len == '\0')
break;
count++;
}
return count;
}
char **split_string(const char *str, const char *split) {
size_t count = getNofTokens(str, split);
char **result = malloc(sizeof(*result) * (count + 1));
size_t pos, len, idx;
for (pos = 0, idx = 0; idx < count; pos += len, idx++) {
pos += strspn(str + pos, split); // skip delimiters
len = strcspn(str + pos, split); // parse token
if (len == '\0')
break;
result[idx] = strndup(str + pos, len);
}
result[idx] = NULL;
return result;
}
void print_split_string(char **split_string) {
for (size_t i = 0; split_string[i] != NULL; i++) {
printf("%s\n", split_string[i]);
}
}
void free_split_string(char **split_string) {
for (size_t i = 0; split_string[i] != NULL; i++) {
free(split_string[i]);
}
free(split_string);
}
EDIT After re-reading the specification in your comment, there seems to be some potential confusion as to the semantics of the split argument:
if split is a set of delimiters, the above code does the job. And the examples will be split as expected.
if split is an actual string to match explicitly, the above code only works by coincidence on the examples given in the comment.
To implement the latter semantics, you should use strstr() to search for the split substring in both getNofTokens and split_string.
Here is an example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "stringsplit.h"
/* Split string by another string, return split parts + NULL in array.
*
* Parameters:
* str: the string to split
* split: the string to split str with
*
* Returns:
* A dynamically reserved array of dynamically reserved string parts.
*
* For example called with "Test string split" and " ",
* returns ["Test", "string", "split", NULL].
* Or called with "Another - test" and " - ",
* returns ["Another", "test", NULL].
*/
size_t getNofTokens(const char *str, const char *split) {
const char *p;
size_t count = 1;
size_t len = strlen(split);
if (len == 0)
return strlen(str);
for (p = str; (p = strstr(p, split)) != NULL; p += len)
count++;
return count;
}
char **split_string(const char *str, const char *split) {
size_t count = getNofTokens(str, split);
char **result = malloc(sizeof(*result) * (count + 1));
size_t len = strlen(split);
size_t idx;
const char *p = str;
for (idx = 0; idx < count; idx++) {
const char *q = strstr(p, split);
if (q == NULL) {
q = p + strlen(p);
} else
if (q == p && *q != '\0') {
q++;
}
result[idx] = strndup(p, q - p);
p = q + len;
}
result[idx] = NULL;
return result;
}
void print_split_string(char **split_string) {
for (size_t i = 0; split_string[i] != NULL; i++) {
printf("%s\n", split_string[i]);
}
}
void free_split_string(char **split_string) {
for (size_t i = 0; split_string[i] != NULL; i++) {
free(split_string[i]);
}
free(split_string);
}
When debugging, take note of values that you got from malloc, strdup, etc. Let's call these values "the active set". It's just a name, so that we can refer to them. You get a pointer from those functions, you mentally add it to the active set. When you call free, you can only pass values from the active set, and after free returns, you mentally remove them from the set. Any other use of free is invalid and a bug.
You can easily find this out by putting breakpoints after all memory allocations, so that you can write down the pointer values, and then breakpoints on all frees, so that you can see if one of those pointer values got passed to free - since, again, to do otherwise is to misuse free.
This can be done also using "printf" debugging. Like this:
char *buf = malloc(...); // or strdup, or ...
fprintf(stderr, "+++ Alloc %8p\n", buf);
And then whenever you have free, do it again:
fprintf(stderr, "--- Free %8p\n", ptr);
free(ptr);
In the output of the program, you must be able to match every +++ with ---. If you see any --- with a value that wasn't earlier listed with a +++, there's your problem: that's the buggy invocation of free :)
I suggest using fprintf(stderr, ... instead of printf(..., since the former is typically unbuffered, so if your program crashes, you won't miss any output. printf is buffered on some architectures (and not buffered on others - so much for consistency).
I need the string "on" to be replaced with "in", strstr() function returns a pointer to a string so i figured assigning the new value to that pointer would work but it didn't
#include <stdio.h>
#include <string.h>
int main(void) {
char *m = "cat on couch";
*strstr(m, "on") = "in";
printf("%s\n", m);
}
Replacing a substring with another is easy if both substrings have the same length:
locate the position of the substring with strstr
if it is present, use memcpy to overwrite it with the new substring.
assigning the pointer with *strstr(m, "on") = "in"; is incorrect and should generate a compiler warning. You would avoid such mistakes with gcc -Wall -Werror.
note however that you cannot modify a string literal, you need to define an initialized array of char so you can modify it.
Here is a corrected version:
#include <stdio.h>
#include <string.h>
int main(void) {
char m[] = "cat on couch";
char *p = strstr(m, "on");
if (p != NULL) {
memcpy(p, "in", 2);
}
printf("%s\n", m);
return 0;
}
If the replacement is shorter, the code is a little more complicated:
#include <stdio.h>
#include <string.h>
int main(void) {
char m[] = "cat is out roaming";
char *p = strstr(m, "out");
if (p != NULL) {
memcpy(p, "in", 2);
memmove(p + 2, p + 3, strlen(p + 3) + 1);
}
printf("%s\n", m);
return 0;
}
In the generic case, it is even more complicated and the array must be large enough to accommodate for the length difference:
#include <stdio.h>
#include <string.h>
int main(void) {
char m[30] = "cat is inside the barn";
char *p = strstr(m, "inside");
if (p != NULL) {
memmove(p + 7, p + 6, strlen(p + 6) + 1);
memcpy(p, "outside", 7);
}
printf("%s\n", m);
return 0;
}
Here is a generic function that handles all cases:
#include <stdio.h>
#include <string.h>
char *strreplace(char *s, const char *s1, const char *s2) {
char *p = strstr(s, s1);
if (p != NULL) {
size_t len1 = strlen(s1);
size_t len2 = strlen(s2);
if (len1 != len2)
memmove(p + len2, p + len1, strlen(p + len1) + 1);
memcpy(p, s2, len2);
}
return s;
}
int main(void) {
char m[30] = "cat is inside the barn";
printf("%s\n", m);
printf("%s\n", strreplace(m, "inside", "in"));
printf("%s\n", strreplace(m, "in", "on"));
printf("%s\n", strreplace(m, "on", "outside"));
return 0;
}
There are a few problems with this approach. First, off, m is pointing to read-only memory, so attempting to overwrite the memory there it is undefined behavior.
Second, the line: strstr(m, "on") = "in" is not going to change the pointed-to string, but instead reassign the pointer.
Solution:
#include <stdio.h>
#include <string.h>
int main(void)
{
char m[] = "cat on couch";
memcpy(strstr(m, "on"), "in", 2);
printf("%s\n", m);
}
Note that if you had just used plain strcpy it would null-terminate after "cat in", so memcpy is necessary here. strncpy will also work, but you should read this discussion before using it.
It should also be known that if you are dealing with strings that are not hard-coded constants in your program, you should always check the return value of strstr, strchr, and related functions for NULL.
This function performs a generic pattern replace for all instances of a substring with a replacement string. It allocates a buffer of the correct size for the result. Behaviour is well defined for the case of the empty substring corresponding to the javascript replace() semantics. Where possible memcpy is used in place of strcpy.
/*
* strsub : substring and replace substring in strings.
*
* Function to replace a substring with a replacement string. Returns a
* buffer of the correct size containing the input string with all instances
* of the substring replaced by the replacement string.
*
* If the substring is empty the replace string is written before each character
* and at the end of the string.
*
* Returns NULL on error after setting the error number.
*
*/
char * strsub (char *input, char *substring, char *replace)
{
int number_of_matches = 0;
size_t substring_size = strlen(substring), replace_size = strlen(replace), buffer_size;
char *buffer, *bp, *ip;
/*
* Count the number of non overlapping substring occurences in the input string. This
* information is used to calculate the correct buffer size.
*/
if (substring_size)
{
ip = strstr(input, substring);
while (ip != NULL)
{
number_of_matches++;
ip = strstr(ip+substring_size, substring);
}
}
else
number_of_matches = strlen (input) + 1;
/*
* Allocate a buffer of the correct size for the output.
*/
buffer_size = strlen(input) + number_of_matches*(replace_size - substring_size) + 1;
if ((buffer = ((char *) malloc(buffer_size))) == NULL)
{
errno=ENOMEM;
return NULL;
}
/*
* Rescan the string replacing each occurence of a match with the replacement string.
* Take care to copy buffer content between matches or in the case of an empty find
* string one character.
*/
bp = buffer;
ip = strstr(input, substring);
while ((ip != NULL) && (*input != '\0'))
{
if (ip == input)
{
memcpy (bp, replace, replace_size+1);
bp += replace_size;
if (substring_size)
input += substring_size;
else
*(bp++) = *(input++);
ip = strstr(input, substring);
}
else
while (input != ip)
*(bp++) = *(input++);
}
/*
* Write any remaining suffix to the buffer, or in the case of an empty find string
* append the replacement pattern.
*/
if (substring_size)
strcpy (bp, input);
else
memcpy (bp, replace, replace_size+1);
return buffer;
}
For testing purposes I include a main program that uses the replacement function.
#define BUFSIZE 1024
char * read_string (const char * prompt)
{
char *buf, *bp;
if ((buf=(char *)malloc(BUFSIZE))==NULL)
{
error (0, ENOMEM, "Memory allocation failure in read_string");
return NULL;
}
else
bp=buf;
printf ("%s\n> ", prompt);
while ((*bp=getchar()) != '\n')bp++;
*bp = '\0';
return buf;
}
int main ()
{
char * input_string = read_string ("Please enter the input string");
char * pattern_string = read_string ("Please enter the test string");
char * replace_string = read_string ("Please enter the replacement string");
char * output_string = strsub (input_string, pattern_string, replace_string);
printf ("Result :\n> %s\n", output_string);
free (input_string);
free (pattern_string);
free (replace_string);
free (output_string);
exit(0);
}
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