Return String of Characters Repeated x Times - c

Can someone please help me with this function.
char *repeat(char *s, int x)
Returns a new string consisting of the characters in s repeated x times. For example, if s is the string all right , the function returns the new string all right all right all right. If s is NULL, the function returns NULL.
It is up to the caller to free any memory allocated by the function.
This is what I have so far...
char *repeat(char *s, int x){
int i;
int count = 0;
while(s[count] != '\0')
{
count++;
}
int repeat = count * x;
char *newArray = malloc(5000);
for(i = 0; i < repeat; i++)
{
while(*s != '\0')
*newArray++ = *s++;
}
return (char*)newArray;
}

char *repeat(const char *s, int x){
if(s){
int i, count = 0;
while(s[count] != '\0'){
++count;
}
char *newArray = malloc(count * x + 1);
if(newArray){
char *na = newArray;
for(i = 0; i < x; ++i) {
const char *p=s;
while(*p)
*na++ = *p++;
}
*na = '\0';
}
return newArray;
} else {
return NULL;
}
}

The main issue--assuming you're only getting one copy back--is that you need to "reset" the pointer s between your copies. Right now, you hit the end of s, so the successive iterations are trying to copy a string of "\0".
Two potential other problems (for the future) are:
You should be using (I'm guessing you know this one and aren't allowed to do otherwise) strcpy() to do the copying.
Memory should always be allocated by the function's caller. The pointer to the new string goes on the call stack and the memory goes on the heap technically assigned to repeat(), so when you return, the run-time is under no obligation to preserve any of it for the caller to use. It "usually works," but it can be painfully dangerous.

First allocate memory then copy/move the memory.
For your reference, a simple one(not fully test):
char *repeat(char *s, int x)
{
char *result = malloc(sizeof(s) * x + 1);
while (x > 0) {
strcat(result, s);
x --;
}
return result;
}
int main(int argc, const char * argv[])
{
// insert code here...
char *sample = "hell";
char *result = repeat(sample, 3);
printf("result : %s\n", result);
free(result);
return 0;
}
You'd better:
don't forget x should be the integer and greater than 0;
always remember to free the created string

Related

Test Crashed Caught unexpected signal: 6 on CodeWars in C

I have done a code to solve the Sum String as Numbers problem on CodeWars.
On my machine it runs and returns the correct value, it also passes all tests on CodeWars, but for some reasons it's raised the Caught unexpected signal: 6 and free(): invalid pointer.
I have checked other questions related to this and other forums but it seems that i don't anything form there. I have used only size_t my pointer don't increase like a++ or anything in order to free to not be able to dealocate memory.
My code consists on:
a function char *to_num(const char *a,size_t *size) which converts all digits from ASCII to numbers (i.e. '3' => 3) and returns a char* to a dynamic allocated array with all that numbers. Also it removes all prefixed zeros.
void no_zeros(char *a) which simply deletes all the 0 from the start of a string (i.e. "0012" => "12")
a custom len function, because i use a different nul character, as my 0 in array is tehnically 0 digit. On this example i use 10 as terminating character
char *fill(char* a,size_t size) that returns a string prefixed with as many zeros as needed to reach the length size (i.e. for a="12" and size=4 it returns 0012)
and finnaly the main function char *strsum(const char *a, const char *b) which returns the sum written as a string (i.e. "123" + "456" returns "579")
The flow of this program goes like:
convert the strings received as parameter to numbers with to_num
if one number is longer than another the fill function is called to complet the smaller one so that we can perform the addition
than we perform the addition per components and return the number as string
I have a bug that prefixes my result with zero so i call the no_zeros on resut.
My code
#include <stdio.h>
#include <malloc.h>
#include <string.h>
void display(const char *a,size_t size){
for(size_t i=0;a[i]!=0 && i<size;i++){
if(a[i]>'0'){
printf("%c",a[i]);
}
else{
printf("%d",a[i]);
}
}
printf("\n");
}
char *to_num(const char *a,size_t *size){
size_t i=0,j=0;
*size = strlen(a);
char *result = malloc((*size+1)*sizeof(char));
if(result==NULL){return 0;}
while(a[i]=='0'){i++;}
while(a[i]!=0){
result[j] = a[i];
i++;
j++;
}
result[j]=0;
*size = j;
for(size_t i=0;i<*size;i++){
result[i] = result[i]-'0';
}
result[*size] =10;
return result;
}
void no_zeros(char *a){
size_t i=0,j=0;
while(a[i]=='0'){i++;}
while(a[i]!=0){
a[j] = a[i];
i++;
j++;
}
a[j]=0;
}
size_t len(char *a){
size_t s=0;
for(size_t i=0;a[i]!=10;i++){
s++;
}
return s;
}
char *fill(char* a,size_t size){
size_t a_size = len(a);
char *copy = malloc((size+2)*sizeof(char));
if(copy==NULL){return 0;}
for(size_t i=0;i<size-a_size;i++){
copy[i] = 0;
}
for(size_t i=0;i<a_size;i++){
copy[i+size-a_size] = a[i];
}
copy[size] = 0;
for(size_t i=0;i<size;i++){
}
return copy;
}
char *strsum(const char *a, const char *b)
{
size_t size_a,size_b,bigger,smaller;
char *x,*y;
x = to_num(a,&size_a);
y = to_num(b,&size_b);
bigger = size_a>=size_b ? size_a : size_b;
smaller = size_a<=size_b ? size_a : size_b;
if(bigger != smaller){
if(bigger == size_a){
y = fill(y,bigger);
size_b = bigger;
}
else{
x = fill(x,bigger);
size_a = bigger;
}
}
char *result = malloc((bigger+2)*sizeof(char));
if(result==NULL){return 0;}
int carry=0;
size_t i;
for(i=bigger;i>=0;i--){
result[i] = (x[i-1]+y[i-1]+carry)%10+'0';
carry = (x[i-1]+y[i-1]+carry)/10;
if(i==0) break;
}
result[bigger+1]=0;
no_zeros(result);
if(result[0]==0){return "0";}
free(x);
free(y);
return result;
}
int main(){
printf("%s\n",strsum("9567","800"));
}
display(): for(size_t i=0;a[i]!=0 && i<size;i++){: swap the order of the conditions so you do the boundary check before a[i].
strsum(): for(i=bigger;i>=0;i--){ doesn't make sense as i is a size_t i.e. unsigned and in the loop body you do x[i-1] and y[i-1] which is wrong when i is 0. What about this?
for(i=bigger; i; i--){
result[i] = (x[i-1]+y[i-1]+carry)%10+'0';
carry = (x[i-1]+y[i-1]+carry)/10;
}
result[0] = carry + '0';
strsum(): x and y leak as you free them after a return:
free(x);
free(y);
if(result[0]==0){return "0";}
strsum(): to_num() allocates an array and then fill() allocates a copy (2 mallocs) and in strsum() you may leak the first malloc() for either x or y:
x = to_num(a,&size_a);
y = to_num(b,&size_b);
// ...
if(bigger != smaller){
if(bigger == size_a){
y = fill(y,bigger);
size_b = bigger;
}
else{
x = fill(x,bigger);
size_a = bigger;
}
}
Either realloc() in fill() instead of creating a copy or use a temporary variable in strsum() so you can free the original malloc'ed value:
if(bigger != smaller){
if(bigger == size_a){
char *tmp = fill(y, bigger);
free(y);
y = tmp;
size_b = bigger;
}
else{
char *tmp = fill(x, bigger);
free(x);
x = tmp;
size_a = bigger;
}
}
Btw, this is the same code in both branches so consider writing a function.
main(): leaks the returned string:
int main(){
char *s = strsum("9567","800");
printf("%s\n", s);
free(s);
}
strsum(): Once you fix above mention leak in main() you can no longer do return "0". You would need a size check and possible realloc() before doing:
return strcpy(result, "0");
or you could free(result); return strdup("0");. This is most likely the root cause (in calling test code you don't see).

How do I pass an array of strings passed to a function to another function?

I'm new to pointers and I can already see how confusing they can be.
I have tried to look this up in several threads and google but they don't quite return what I'm looking for maybe out of my inexperience.
I'm being passed an array of strings and I have to pass it again to another function however I'm extremely confused on how to do this and don't know what * or & to use or where.
My code:
#include <stdlib.h>
#include <stdio.h>
char *ft_strcat(char *dest, char *src)
{
unsigned int c;
unsigned int count;
count = 0;
while (dest[count] != 0)
{
count++;
}
c = 0;
while (src[c] != '\0')
{
dest[c + count] = src[c];
c++;
}
dest[c + count] = 0;
return (dest);
}
int size_str(char *str)
{
int c;
c = 0;
while (str[c] != '\0')
{
c++;
}
return (c - 1);
}
int size_all(int size, char *strs[], char *sep)
{
int i;
int counter;
i = 0;
counter = 0;
counter += size_str(sep) * (size - 1);
while (i < size)
{
counter += size_str(strs[i]);
i++;
}
return (counter);
}
char *ft_strjoin(int size, char **strs, char *sep)
{
int i;
char *str;
str = malloc(sizeof(char) * size_all(size, strs, sep));
str = strs[0];
i = 1;
while (i < size)
{
str = ft_strcat(str, strs[i]);
}
return (str);
}
int main(void)
{
char *sep = " ";
char a1[] = "Batata";
char a2[] = "frita";
char a3[] = "\'e";
char a4[] = "melhor";
char a5[] = "que";
char a6[] = "Banana";
char *strs[] = {a1, a2, a3, a4, a5, a6};
char *final = ft_strjoin(6, strs, sep);
printf("%s", final);
}
I thought that size all would have to have an extra dereference operator on the declaration of the function and an reference operator when I call it, but this works just fine. Am I doing something wrong or am I just misunderstanding how pointers work? Don't I have to add an extra * each time I pass it?
Finally why doesn't while (src[c] != '\0') work?
In size_str:
There's nothing wrong with while (src[c] != '\0'), but return (c - 1); is causing an off-by-one error with your string lengths. The NUL byte wasn't counted in the loop, there's no need to subtract 1.
In ft_strcat:
The first loop is repeating work that could be handled by a call to size_str.
In ft_strjoin:
str = malloc(sizeof(char) * sizeall(size, strs, sep)));
sizeof (char) is uneccessary, as it is always 1. You need an additional 1 byte added to the length passed to malloc to make room for the NUL byte in your final string.
Remember that pointers are values too. str = strs[0]; assigns the pointer held in strs[0] to the the variable str. It does not copy the contents of strs[0]. You are overwriting the value returned by malloc with a pointer to a different piece of memory.
Instead, given this set of functions, initialize the memory returned by malloc to be the empty string, by setting the first byte to NUL, and use ft_strcat to concatenate the first string.
There's no need to continually reassign the result of ft_strcat, as you are already altering str, and the return value will never change.
A complete example. One must not forget to free the resulting string when it is no longer needed.
#include <stdlib.h>
#include <stdio.h>
int size_str(char *str)
{
int i = 0;
while (str[i])
i++;
return i;
}
char *ft_strcat(char *dest, char *src)
{
int i = 0,
length = size_str(dest);
do
dest[length++] = src[i];
while (src[i++]);
return dest;
}
int size_all(int size, char **strs, char *sep)
{
int total_length = size_str(sep) * (size - 1);
for (int i = 0; i < size; i++)
total_length += size_str(strs[i]);
return total_length;
}
char *ft_strjoin(int size, char **strs, char *sep)
{
char *result = malloc(1 + size_all(size, strs, sep));
result[0] = '\0';
ft_strcat(result, strs[0]);
for (int i = 1; i < size; i++) {
ft_strcat(result, sep);
ft_strcat(result, strs[i]);
}
return result;
}
int main(void)
{
char *sep = " ";
char a1[] = "Batata";
char a2[] = "frita";
char a3[] = "\'e";
char a4[] = "melhor";
char a5[] = "que";
char a6[] = "Banana";
char *strs[] = {a1, a2, a3, a4, a5, a6};
char *final = ft_strjoin(6, strs, sep);
printf("%s\n", final);
free(final);
}
Output:
Batata frita 'e melhor que Banana
I have worked lately about this problematic, string joint. I noticed that you forgot to add an if condition where the size would be 0. Moreover, the while loop need an iteration, which means that it will give you an infinite loop.
You can find as follows some adjustment to your code:
int i;
char *str;
int j;
int k;
i = 0;
k = 0;
str = (char *)malloc(sizeof(char) * sizeall(size, strs, sep) + 1));
if (size == 0)
return (0);
while (i < size)
{
j = 0;
while (strs[i][j])
str[k++] = strs[i][j++];
j = 0;
if (i < size - 1)
while (sep[j])
str[k++] = sep[j++];
i++;
}
str[k] = '\0';
return (str);
Feel free to ask me if there is something you did not understand, and good luck.

Printing array of strings produces bad output

I'm trying to solve a challenge, but I have no idea of what's wrong with my code!
The challenge is:
Create a function that splits a string of characters into words.
Separators are spaces, tabs and line breaks.
This function returns an array where each box contains a character-string’s address represented by a word. The last element of this array should be equal to 0 to emphasise the end of the array.
There can’t be any empty strings in your array. Draw the necessary conclusions.
The given string can’t be modified.
Note: The only allowed function is malloc()
The bug/problem:
I faced this problem and I tried to solve it but I wasn't able to identify what's wrong.
I created a function named split_whitespaces() to do the job.
When I print the array of strings inside of the split_whitespaces function, I get the following output:
Inside the function:
arr_str[0] = This
arr_str[1] = is
arr_str[2] = just
arr_str[3] = a
arr_str[4] = test!
And when I print the array of string inside the main function, I get the following output:
Inside the main function:
arr_str[0] = #X#?~
arr_str[1] = `X#?~
arr_str[2] = just
arr_str[3] = a
arr_str[4] = test!
I created a function word_count to count how many words in the input string so I can allocate memory using malloc and with word_count + 1 (null pointer).
int word_count(char *str) {
int i;
int w_count;
int state;
i = 0;
w_count = 0;
state = 0;
while (str[i]) {
if (!iswhitespace(str[i])) {
if (!state)
w_count++;
state = 1;
i++;
} else {
state = 0;
i++;
}
}
return (w_count);
}
And another function called strdup_w to mimic the behavior of strdup but just for single words:
char *strdup_w(char *str, int *index) {
char *word;
int len;
int i;
i = *index;
len = 0;
while (str[i] && !iswhitespace(str[i]))
len++, i++;;
word = (char *) malloc(len + 1);
if (!word)
return (NULL);
i = 0;
while (str[*index]) {
if (!iswhitespace(str[*index])) {
word[i++] = str[*index];
(*index)++;
} else
break;
}
word[len] = '\0';
return (word);
}
Here's my full code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **split_whitespaces(char *str);
char *strdup_w(char *str, int *index);
int word_count(char *str);
int iswhitespace(char c);
int main(void) {
char *str = "This is just a test!";
char **arr_str;
int i;
i = 0;
arr_str = split_whitespaces(str);
printf("\nOutside the function:\n");
while (arr_str[i]) {
printf("arr_str[%d] = %s\n", i, arr_str[i]);
i++;
}
return (0);
}
char **split_whitespaces(char *str) {
char **arr_str;
int i;
int words;
int w_i;
i = 0;
w_i = 0;
words = word_count(str);
arr_str = (char **)malloc(words + 1);
if (!arr_str)
return (NULL);
printf("Inside the function:\n");
while (w_i < words) {
while (iswhitespace(str[i]) && str[i])
if (!str[i++])
break;
arr_str[w_i] = strdup_w(str, &i);
printf("arr_str[%d] = %s\n", w_i, arr_str[w_i]);
w_i++;
}
arr_str[words] = 0;
return (arr_str);
}
char *strdup_w(char *str, int *index) {
char *word;
int len;
int i;
i = *index;
len = 0;
while (str[i] && !iswhitespace(str[i]))
len++, i++;;
word = (char *)malloc(len + 1);
if (!word)
return (NULL);
i = 0;
while (str[*index]) {
if (!iswhitespace(str[*index])) {
word[i++] = str[*index];
(*index)++;
} else
break;
}
word[len] = '\0';
return (word);
}
int word_count(char *str) {
int i;
int w_count;
int state;
i = 0;
w_count = 0;
state = 0;
while (str[i]) {
if (!iswhitespace(str[i])) {
if (!state)
w_count++;
state = 1;
i++;
} else {
state = 0;
i++;
}
}
return (w_count);
}
int iswhitespace(char c) {
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
return (1);
return (0);
}
I'm sorry, if anything this is my first time trying to seek help.
There are multiple problems in the code:
the size is incorrect in arr_str = (char **)malloc(words + 1); You must multiply the number of elements by the size of the element:
arr_str = malloc(sizeof(*arr_str) * (words + 1));
it is good style to free the array in the main() function after use.
the test while (iswhitespace(str[i]) && str[i]) is redundant: if w_count is computed correctly, testing str[i] should not be necessary. You should use strspn() to skip the white space and strcspn() to skip the word characters.
if (!str[i++]) break; is completely redundant inside the loop: str[i] has already been tested and is not null.
while (str[i] && !iswhitespace(str[i])) len++, i++;; is bad style. Use braces if there is more than a single simple statement in the loop body.
the last loop in strdup_w is complicated, you could simply use memcpy(word, str + *index, len); *index += len;
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
char **split_whitespaces(const char *str);
char *strdup_w(const char *str, int *index);
int word_count(const char *str);
int iswhitespace(char c);
int main(void) {
const char *str = "This is just a test!";
char **arr_str;
int i;
arr_str = split_whitespaces(str);
if (arr_str) {
printf("\nOutside the function:\n");
i = 0;
while (arr_str[i]) {
printf("arr_str[%d] = %s\n", i, arr_str[i]);
i++;
}
while (i --> 0) {
free(arr_str[i]);
}
free(arr_str);
}
return 0;
}
char **split_whitespaces(const char *str) {
char **arr_str;
int i;
int words;
int w_i;
i = 0;
w_i = 0;
words = word_count(str);
arr_str = malloc(sizeof(*arr_str) * (words + 1));
if (!arr_str)
return NULL;
printf("Inside the function:\n");
while (w_i < words) {
while (iswhitespace(str[i]))
i++;
arr_str[w_i] = strdup_w(str, &i);
if (!arr_str[w_i])
break;
printf("arr_str[%d] = %s\n", w_i, arr_str[w_i]);
w_i++;
}
arr_str[words] = NULL;
return arr_str;
}
char *strdup_w(const char *str, int *index) {
char *word;
int len;
int start;
int i;
i = *index;
start = i;
while (str[i] && !iswhitespace(str[i])) {
i++;
}
*index = i;
len = i - start;
word = malloc(len + 1);
if (!word)
return NULL;
i = 0;
while (i < len) {
word[i] = str[start + i];
i++;
}
word[i] = '\0';
return word;
}
int word_count(const char *str) {
int i;
int w_count;
int state;
i = 0;
w_count = 0;
state = 0;
while (str[i]) {
if (!iswhitespace(str[i])) {
if (!state)
w_count++;
state = 1;
} else {
state = 0;
}
i++;
}
return w_count;
}
int iswhitespace(char c) {
return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
}
From my top comment ...
In split_whitespaces, try changing:
arr_str = (char **) malloc(words + 1);
into:
arr_str = malloc(sizeof(*arr_str) * (words + 1));
As you have it, words is a count and not a byte length, so you're not allocating enough space, so you have UB.
UPDATE:
But watched some tutorials and they said that malloc takes one argument which is the size of the memory to be allocated (in bytes), that's why I allocated memory for 5 bytes! can you please tell my an alternative of using malloc without sizeof() function. I'll appreciate it. – Achraf EL Khnissi
There's really no clean way to specify this without sizeof.
sizeof is not a function [despite the syntax]. It is a compiler directive. It "returns" the number of bytes occupied by its argument as a compile time constant.
If we have char buf[5];, there are 5 bytes, so sizeof(buf) [or sizeof buf] is 5.
If we have: int buf[5];, there are 5 elements, each of size int which is [typically] 4 bytes, so the total space, in bytes, is sizeof(int) * 5 or 4 * 5 which is 20.
But, int can vary depending on the architecture. On Intel 8086's [circa the 1980's], an int was 2 bytes (i.e. 16 bits). So, the above 4 * 5 would be wrong. It should be 2 * 5.
If we use sizeof(int), then sizeof(int) * 5 works regardless of the architecture.
Similarly, on 32 bit machines, a pointer is [usually] 32 bits. So, sizeof(char *) is 4 [bytes]. On a 64 bit machine, a pointer is 64 bits, which is 8 bytes. So, sizeof(char *) is 8.
Because arr_str is: char **arr_str, we could have done:
arr_str = malloc(sizeof(char *) * (words + 1));
But, if the definition of arr_str ever changed (to (e.g.) struct string *arr_str;), then what we just did would break/fail if we forgot to change the assignment to:
arr_str = malloc(sizeof(struct string) * (words + 1));
So, doing:
arr_str = malloc(sizeof(*arr_str) * (words + 1));
is a preferred idiomatic way to write cleaner code. More statements will adjust automatically without having to find all affected lines of code manually.
UPDATE #2:
You might just add why you removed the (char **) cast :) -- chqrlie
Note that I removed the (char **) cast. See: Do I cast the result of malloc?
This just adds extra/unnecessary "stuff" as the void * return value of malloc can be assigned to any type of pointer.
If we forgot to do: #include <stdlib.h>, there would be no function prototype for malloc, so the compiler would default the return type to int.
Without the cast, the compiler would issue an an error on the statement [which is what we want].
With the cast, this action is masked at compile time [more or less]. On a 64 bit machine, the compiler will use a value that is truncated to 32 bits [because it thinks malloc returns a 32 bit value] instead of the full 64 bit return value of malloc.
This truncation is a "silent killer". What should have been flagged as a compile time error produces a runtime fault (probably segfault or other UB) that is much harder to debug.

C updating string incrementally

I am trying to update string step by step in C. The code i tried is below:
#include <stdlib.h>
#include <stdio.h>
int writech(char **text, char ch) {
**text = ch;
return 1;
}
char *write(int array[], size_t size) {
char *string = (char*)malloc(sizeof(char)*(size+1));
int i, n;
for (i = 0; i < size; ++i) {
n = writech(&string, '0' + array[i]);
string += n;
}
return string;
}
int main() {
int arr[] = { 1, 2, 3, 4, 5 };
char *str = write(arr, sizeof(arr)/sizeof(arr[0]));
printf("%s\n", str);
return 0;
}
Here, write function should update string by calling other function and return updated string at the end. The code compiled and run successfully, though str (at the end of main) is empty after all. Actually, my task is to create string that contain table of some data and return it at the end. Pseudo code for my idea is below:
char *render_table() {
char *table = malloc(sizeof table);
write_header(table);
write_row(table, some_data);
write_row(table, some_data);
write_footer(table)
return table;
}
For implementing this pseudo code I wrote the above code, but not able to update passed string successfully. I know pointers are passed to function as copies, and passed memory of my string (writech(&string) to function, but string not updated still. What am i missing?
P.S. Tweaking with pointers is really struggling for me as beginner in C. What would you suggest?
string is updated. The problem is the pointer string is updated and the information of the beginning of the string is lost. You have to hold the information.
One more point is that terminating null-character must be added to pass the buffer for %s (without specifying length to print).
Also note that casting results of malloc() in C is discouraged.
Try this:
char *write(int array[], size_t size) {
char *string = malloc(sizeof(char)*(size+1));
char *cursor = string;
int i, n;
for (i = 0; i < size; ++i) {
n = writech(&cursor, '0' + array[i]);
cursor += n;
}
writech(&cursor, '\0');
return string;
}
Seems to me that you are making this much more complicated than needed.
Simply do:
for (i = 0; i < size; ++i) {
string[i] = '0' + array[i]);
}
string[i] = '\0';
If for some reason you really want to use the writech function, you can change it to:
void writech(char *text, char ch) {
*text = ch;
}
and call it like:
for (i = 0; i < size; ++i) {
writech(string + i, '0' + array[i]);
}
string[i] = '\0';
but it's really just making a simple task complex.
EDIT due to comment
If you (in your real code) don't know how many chars will be added by a function call, you simply do:
int writeSomethingA(char* str, ... other arguments ...)
{
// update str, e.g. like str[0] = 'a'; str[1] = 'b';
// or strcpy(str, "Some text");
return NumberOfCharAdded;
}
(make similar B and C versions)
and call them like:
char* string malloc(....);
int idx = 0;
idx += writeSomethingA(string + idx, ... other arguments ...);
idx += writeSomethingB(string + idx, ... other arguments ...);
idx += writeSomethingC(string + idx, ... other arguments ...);
string[idx] = '\0';
For starters it is unclear why the function writech
int writech(char **text, char ch) {
**text = ch;
return 1;
}
has the first parameter with the type char ** instead of char *.
The function can be defined like
int writech( char *text, char ch ) {
*text = ch;
return 1;
}
Within the function write the pointer string is being changed in the for loop. So the function returns a pointer that does not point to the beginning of the allocated memory.
Also as you are using the conversion specifier %s to output the character array in main then the array shall contain a string. That is the array shall have contain the terminating zero character '\0'.
The function can be implemented the following way
char * write( const int array[], size_t size ) {
char *string = malloc( size + 1 );
if ( string != NULL )
{
char *p = string;
while ( size-- ) {
p += writech( p, '0' + *array++ );
}
*p = '\0';
}
return string;
}
And you should free the allocated memory before exiting main like
free( str );

How to add string elements successively in C?

I want to add string elements successively, for example st[]="morty", and I want to repeat its elements for example seven times. It should be st[]="mortymo". I wrote a function which is at below. (The length function is strlen).
void repeat(char* st,int n){
int i,k=0,l=length(st);
char* ptr;
ptr=(char*)malloc((n+1)*sizeof(char));
for (i=0;i<n;i++){
*(ptr+i)=*(st+k);
k++;
if(k==l)k=0;
}
}
The program below repeats characters from the original string.
Comments in the code:
#include<stdio.h>
#include<stdlib.h>
char* repeat(const char* st, size_t n){
// use `const` to note that pointer `st` will not be modified
// for purity you may want to use type `size_t` since returning type of strlen is `size_t`
size_t i, k=0;
size_t l = strlen(st);
// do not use (char *) cast
char* ptr = malloc((n+1)*sizeof(char)); // allocate enough room for characters + NULL
for (i=0; i< n; i++)
{
ptr[i] = st[k]; // use index for readability
k++;
if (k == l)
k=0;
}
ptr[i] = 0; // terminate the string
return ptr;
}
int main( )
{
char *str = "12345";
str = repeat(str, 15);
printf("%s\n",str);
free (str); // free the allocated memory inside the repeat function
return 0;
}
OUTPUT:
123451234512345
In your repeat function, you allocated ptr to hold the repeated string, but you didn't return or assign it to st. You can modify your repeat function as follows:
char* repeat(char* st,int n){
int i,k=0,l=strlen(st);
char* ptr;
ptr=(char*)malloc((n+1)*sizeof(char));
for (i=0;i<n;i++){
*(ptr+i)=*(st+k);
k++;
if(k==l)k=0;
}
*(ptr+n) = '\0';
return ptr;
}
/* some code*/
char *st = "morty";
st = repeat(st, 7);
Such that you are storing the result of the repeated string in st after.
If I have understood the assignment correctly then you need a function like that one shown in the demonstrative program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * repeat( const char *s, size_t n )
{
char *p = NULL;
size_t len = strlen( s );
if ( len == 0 ) n = 0;
p = ( char * )malloc( n + 1 );
if ( p )
{
size_t i = 0;
for ( size_t j = 0; i < n; i++ )
{
p[i] = s[j];
if ( ++j == len ) j = 0;
}
p[i] = '\0';
}
return p;
}
int main(void)
{
char *s = "Hi, Zusaetlich.";
char *p = repeat( s, 2 * strlen( s ) );
puts( p );
free( p );
return 0;
}
The program output is
Hi, Zusaetlich.Hi, Zusaetlich.
Pay attention to that the function is designed such a way that if the original string is empty then the resulted string is also empty because there is nothing to repeat.
As for your function then it has at least a memory leak because the memory allocated in the function is not freed.
Also as the original string is not changed then the corresponding parameter should be qualified with the const specifier. And the second parameter should have type size_t because at least the function strlen has the return type size_t.
So the function should be declared as it is shown in the demonstrative program.
Since you don't intend to modify the contents of st, go ahead and declare it as const. Since you intend to allocate a new string in your function, you should return it to the caller.
char *repeat(const char* st,int n){
k is unnecessary for your problem. Call the standard functions.
int i,l=strlen(st);
char* ptr;
Don't cast the result of malloc, as this can mask a fatal error in C. sizeof(char) is always 1. Check the result of the malloc call for success.
ptr=malloc(n+1);
if (ptr == NULL) return NULL;
for (i=0;i<n;i++){
Access arrays idiomatically with []. Note that k increments whenever i does, but you are applying a modulo operation of k. However, C has a modulo operator, which you can use directly on i.
ptr[i]=st[i%l];
}
Make sure the new string is NUL terminated. Your function is declared to return a result, but your implementation fails to do so.
ptr[n] = '\0';
return ptr;
}
C has many functions you can call to do the copying for you rather than the byte by byte loop you have written. There is simplicity in your implementation, but below is an alternative, that also includes additional error checking that is lacking in your solution.
(Some may balk at the use of sprintf, but it is being used correctly.)
char *
repeat (const char *st, int n) {
int l = st ? strlen(st) : 0;
char *ret = (st && n > 0 ? malloc(n+1) : 0), *p = ret;
while (ret && n > 0) {
p += sprintf(p, "%.*s", (l < n ? l : n), st);
n -= l;
}
return ret ? ret : "(nil)";
}
Try it online!

Resources