char *concat(char *num1, const char *num2, int index) {
int length1 = strlen(num1);
int length2 = strlen(num2);
int lengthNum = 0;
char *num = malloc(length1 + length2 + 1);
if (num == NULL) {
free(num);
return NULL;
}
// memcpy(num, num1, length1);
// memcpy(num + length1, num + index, length2 + 1);
for (int i = 0; i < length1; i++) {
num[lengthNum] = num1[i];
lengthNum++;
}
for (int i = index; i < length2; i++) {
num[lengthNum] = num2[i];
lengthNum++;
}
return num;
}
I tried to use memcpy, but than my program doesn't work correctly (copies wrongly, but valgrind doesn't show an error).
But when I use two for loops instead, it works properly, but than valgrind shows an error
uninitialised value was created by a heap allocation.
How to use properly memcpy in this case?
memcpy(num, num1, length1);
memcpy(num + length1, num2, length2 + 1);
Your program has multiple issues:
freeing a null pointer when malloc failed is useless (but harmless).
you allocate length1 + length2 + 1 bytes, which is most likely too large as you intend to copy from index in the second string.
you should use type size_t for the lengths and offsets.
you copy from num2 + index without checking that index is a valid offset inside the string num2.
you should set a null terminator at the end of the new string.
Here is a modified version:
#include <stdlib.h>
#include <string.h>
char *concat(const char *num1, const char *num2, size_t index) {
size_t length1 = strlen(num1);
/* skip index bytes in num2 */
while (index --> 0 && *num2)
num2++;
size_t length2 = strlen(num2);
char *num = malloc(length1 + length2 + 1);
if (num != NULL) {
size_t j = 0;
while (*num1) {
num[j++] = *num1++;
}
while (*num2) {
num[j++] = *num2++;
}
num[j] = '\0';
}
return num;
}
and using memcpy:
#include <stdlib.h>
#include <string.h>
char *concat(const char *num1, const char *num2, size_t index) {
size_t length1 = strlen(num1);
/* skip index bytes in num2 */
while (index --> 0 && *num2)
num2++;
size_t length2 = strlen(num2);
char *num = malloc(length1 + length2 + 1);
if (num != NULL) {
memcpy(num, num1, length1);
memcpy(num + length1, num2, length2 + 1);
}
return num;
}
concat returns a pointer to an allocation array. It is the responsibilty of the caller to free this object after use. For example:
#include <stdio.h>
int main() {
char *p = concat("Hello", "dear world", 4);
if (p != NULL) {
printf("%s\n", p);
free(p);
}
return 0;
}
Related
I am having trouble with the very last line in my function, where I am stilly learning the basics of C. I have the signature of this function given and am tasked to write a function to concatenate two strings. The commented line outputs the correct result.
#include <stdio.h>
#include <stdlib.h>
// 1) len = dst-len + max_dst_len
int strlcat(char *dst, const char *src, int max_dst_len) {
int len = 0;
while (dst[len] != '\0') {
len++;
}
int total_len = len + max_dst_len;
char *new_str = malloc(sizeof(char) * total_len);
for (int i = 0; i < len; i++) {
new_str[i] = dst[i];
}
for (int i = len; i < total_len; i++) {
new_str[i] = src[i - len];
}
new_str[total_len] = '\0';
//printf("%s <--\n", new_str);
dst = *new_str;
return total_len;
}
int main() {
char test1[] = "dst";
char test1src[] = "src";
printf("%s\n", test1);
printf("%d\n", strlcat(test1, test1src, 10));
printf("%s\n", test1);
}
You should not be adding max_dst_len to the length of dst. max_dst_len is the amount of memory that's already allocated in dst, you need to ensure that the concatenated string doesn't exceed this length.
So you need to subtract len from max_dst_len, and also subtract 1 to allow room for the null byte. This will tell you the maximum number of bytes you can copy from src to the end of dst.
In your main() code, you need to declare test1 to be at least 10 bytes if you pass 10 as the max_dst_len argument. When you omit the size in the array declaration, it sizes the array just big enough to hold the string you use to initialize it. It's best to use sizeof test1 as this argument, to ensure that it's correct for the string you're concatenating to.
#include <stdio.h>
int strlcat(char *dst, const char *src, int max_dst_len) {
int len = 0;
while (dst[len] != '\0') {
len++;
}
int len_to_copy = max_dst_len - len - 1;
int i;
for (i = 0; i < len_to_copy && src[i] != '\0'; i++) {
dst[len+i] = src[i];
}
dst[i] = '\0';
//printf("%s <--\n", new_str);
return i + len;
}
int main() {
char test1[6] = "dst";
char test1src[] = "src";
printf("%s\n", test1);
printf("%d\n", strlcat(test1, test1src, sizeof test1));
printf("%s\n", test1);
}
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.
I need to convert Integer to Char, I can use only pointers without array indexes. Char array must be dynamically allocated. Can anybody review my code and tell my what am I doing wrong?
#include <stdio.h>
#include <stdlib.h>
int main(){
int myNumber = 1234;
char *myString = (char*)malloc(2 * sizeof(char)); //memory for 1 char and '\0'
int i = 0; //parameter for tracking how far my pointer is from the beggining
if (myNumber < 0){
*myString = '-'; //if myNumber is negative put '-' in array
*myString = *(myString + 1); //move pointer to next position
i++;
}
while (myNumber != 0){
myString = (char*)realloc(myString, (i + 2) * sizeof(char)); //increse memory =+1
*myString = (myNumber % 10) + '0'; //put digit as char to array
myNumber /= 10;
*myString = *(myString + 1); //move pointer to next position
i++;
}
*myString = '\0'; //mark end of string
*myString = *(myString - i); //move pointer back to the beggining of string
printf("\n%s", *myString); // print char array (not working..)
return 0;
}
I know there are better ways of converting Int to String (sprintf), but my task is to do it that way.
In the code above I`m taking the digits from Int backwards, can it be done in correct order?
edit. as mentioned in the comments the part:
*myString = *(myString + 1);
is wrong, correct way of redirecting pointer by one space is:
myString++;
same with:
*myString = *(myString - i); //wrong
myString -=i; //ok
Edit2:
Now my code works! But I need to think how to correct the order of the digits.
#include <stdio.h>
#include <stdlib.h>
int main(){
int myNumber = 1234;
char *myString = (char*)malloc(2 * sizeof(char)); //memory for 1 char and '\0'
char * position = myString;
int i = 0;
if (myNumber < 0){
*position = '-'; //if myNumber is negative put '-' in array
position += i; //move pointer to next position
i++;
}
while (myNumber != 0){
myString = (char*)realloc(myString, ((i + 2) * sizeof(char))); //increse memory =+1
position = myString + i; // getting current position after reallocating
*position = (myNumber % 10) + '0'; //put digit to array
myNumber /= 10;
position++; //move pointer to next position
i++;
}
*position = '\0'; //mark end of string
char * temp = myString;
while (*temp != '\0'){
printf("%c", *temp); // print char array (not working..)
temp++;
}
return 0;
}
Edit 3 Problem solved, thanks for comments, I`m posting code in case anybody will look for similar solution.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// move each character in array one place to the right
// we need to make place for new character on the left
void moveArrayElementsRight(char *ptr, int len) {
for (int j = len; j > 1; j--) {
*(ptr + j - 1) = *(ptr + j - 2);
}
}
void intToStr(int myNumber, char* myString){
int i = 1; //track size of allocated memory
bool isMinus = false;
if (myNumber < 0) {
myNumber *= -1; //without this (myNumber % 10) + '0' wont work
isMinus = true;
}
if (myNumber == 0){ //special case for 0
myString = (char*)realloc(myString, ((i + 1) * sizeof(char)));
*myString = '0';
*(myString + 1) = '\0';
}
while (myNumber != 0) {
myString = (char*)realloc(myString, ((i + 1) * sizeof(char))); //increse memory =+1 for next digit
i++;
moveArrayElementsRight(myString, i);
*myString = (myNumber % 10) + '0'; //put digit to array
myNumber /= 10;
}
if (isMinus) {
myString = (char*)realloc(myString, ((i + 1) * sizeof(char))); //increse memory =+1 for '-' sign
i++;
moveArrayElementsRight(myString, i);
*myString = '-'; //put sign at the beginning
}
}
int main() {
int numberToConvert = -10;
char *numberAsString = (char*)malloc(sizeof(char)); //create empty array, with place only for '\0'
*numberAsString = '\0'; //mark the end of array
intToStr(numberToConvert, numberAsString);
printf("%s", numberAsString);
return 0;
}
SPOILER: Don't read or copy this if you don't want the solution.
The following is an example of implementation, using recursive:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include <string.h>
#include <time.h>
#include <errno.h>
static size_t int_to_str_size(int n, size_t acc, int base_size) {
int next = n / base_size;
if (next != 0) {
return int_to_str_size(next, acc + 1, base_size);
} else {
return n < 0 ? acc + 2 : acc + 1;
}
}
static void int_to_str_write(int n, char *str, char *base, int base_size) {
*str = base[abs(n % base_size)];
int next = n / base_size;
if (next != 0) {
int_to_str_write(next, str - 1, base, base_size);
} else {
if (n < 0) {
*(str - 1) = '-';
}
}
}
static char *int_to_str(int n, char *base) {
size_t base_size = strlen(base);
if (base_size < 2 || base_size > INT_MAX) {
errno = EINVAL;
return NULL;
}
size_t size = int_to_str_size(n, 0, (int)base_size);
char *str = malloc(size + 1);
if (str == NULL) {
return NULL;
}
str[size] = '\0';
int_to_str_write(n, str + size - 1, base, (int)base_size);
return str;
}
int main(void) {
srand((unsigned int)time(NULL));
for (uintmax_t i = 0; i < 42; i++) {
int n = rand() % 2 ? rand() : -rand();
char *str = int_to_str(n, "0123456789");
if (str != NULL) {
printf("%d == %s\n", n, str);
free(str);
} else {
perror("int_to_str()");
}
}
}
I need to replace a strings in some text. I found this function here at stackoverflow:
char *replace(const char *s, const char *old, const char *new)
{
char *ret;
int i, count = 0;
size_t newlen = strlen(new);
size_t oldlen = strlen(old);
for (i = 0; s[i] != '\0'; i++) {
if (strstr(&s[i], old) == &s[i]) {
count++;
i += oldlen - 1;
}
}
ret = malloc(i + count * (newlen - oldlen));
if (ret == NULL)
exit(EXIT_FAILURE);
i = 0;
while (*s) {
if (strstr(s, old) == s) {
strcpy(&ret[i], new);
i += newlen;
s += oldlen;
} else
ret[i++] = *s++;
}
ret[i] = '\0';
return ret;
}
This function works for me fine for single replacement. But i need to replace a whole array "str2rep" to "replacement". So what i'm trying to do(im just a beginner)
****
#define MAXTEXT 39016
int l;
int j;
char *newsms = NULL;
char text[MAXTEXT];
char *str2rep[] = {":q:",":n:"};
char *replacement[] = {"?","\n"};
strcpy((char *)text,(char *)argv[5]);
l = sizeof(str2rep) / sizeof(*str2rep);
for(j = 0; j < l; j++)
{
newsms = replace(text,(char *)str2rep[j],(char *)replacement[j]);
strcpy(text,newsms);
free(newsms);
}
textlen = strlen(text);
This code even works locally, If I build it from single file... But this is asterisk module, so when this is being executed, asterisk stops with:
* glibc detected * /usr/sbin/asterisk: double free or corruption (!prev): 0x00007fa720006310 *
Issues:
ret = malloc(i + count * (newlen - oldlen)); is too small. Need + 1.
Consider what happens with replace("", "", ""). If your SO ref is this, it is wrong too.
Questionable results mixing signed/unsigned. count is signed. newlen, oldlen are unsigned.
I think the original code works OK, but I do not like using the wrap-around nature of unsigned math when it can be avoided which is what happens when newlen < oldlen.
// i + count * (newlen - oldlen)
size_t newsize = i + 1; // + 1 for above reason
if (newlen > oldlen) newsize += count * (newlen - oldlen);
if (newlen < oldlen) newsize -= count * (oldlen - newlen);
ret = malloc(newsize);
Insure enough space. #hyde Various approaches available here.
// strcpy(text, newsms);
if (strlen(newsms) >= sizeof text) Handle_Error();
strcpy(text, newsms);
Minor
No need for casts
// newsms = replace(text, (char *) str2rep[j], (char *) replacement[j]);
newsms = replace(text, str2rep[j], replacement[j]);
Better to use size_t for i. A pedantic solution would also use size_t count.
// int i;
size_t i;
I will suggest something that to me looks a bit more clear as an alternative, in place of a proper dynamic string implementation. Exception handling is left as an exercise for the reader to add. :)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *appendn(char *to, char *from, int length)
{
return strncat(realloc(to, strlen(to) + length + 1), from, length);
}
char *replace(char *string, char *find, char *sub)
{
char *result = calloc(1, 1);
while (1)
{
char *found = strstr(string, find);
if (!found)
break;
result = appendn(result, string, found - string);
result = appendn(result, sub, strlen(sub));
string = found + strlen(find);
}
return appendn(result, string, strlen(string));
}
int main()
{
const char text[] = "some [1] with [2] to [3] with other [2]";
char *find[] = {"[1]", "[2]", "[3]", NULL};
char *sub[] = {"text", "words", "replace"};
char *result, *s;
int i;
result = malloc(sizeof(text));
(void) strcpy(result, text);
for (i = 0; find[i]; i ++)
{
s = replace(result, find[i], sub[i]);
free(result);
result = s;
}
(void) printf("%s\n", result);
free(result);
}
Can someone please explain me why I get "Segmentation fault..." and how to fix it on this bit of code?
#include<stdio.h>
int str_length(char *s) {
int length = 0, i;
for(i = 0; *s; i++) {
s++;
}
return i;
}
char *strdel(char *s, int pos, int n) {
int i;
char *p, str[] = "";
p = str;
for(i = 0; i < str_length(s) - n + 1; i++) {
if(i >= pos) {
*(p + i) = *(s + i + n);
}
else {
*(p + i) = *(s + i);
}
}
s = str;
return s;
}
int main() {
char *str = "abcdef";
printf("str_lengh: %d\n", str_length(str));
printf("strdel: %s\n", strdel(str, 1, 2));
return 0;
}
And I get this output:
str_lengh: 6
strdel: adef
Segmentation fault (core dumped)
Also, is there a better way to create a function:
char *strdel(char *s, int pos, int n);
that deletes the n characters from position pos than the one I did?
I think you are writing all over the stack here...
char *strdel(char *s, int pos, int n) {
int i;
char *p, str[] = "";
p = str; // p points to str which is "" and is on the stack with length 0.
for(i = 0; i < str_length(s) - n + 1; i++) {
if(i >= pos) {
*(p + i) = *(s + i + n); // now you are writing onto the stack past p
}
else {
*(p + i) = *(s + i);// now you are writing onto the stack past p
}
}
s = str; // now s points to space on stack
return s; // now you return a pointer to the stack which is about to disapear
}
Whenever you write past p, which is often, you are running into Undefined Behavior. UB
You are writing into space which has not been allocated on the heap or on the stack.
You can write a version of strdel that works only on s. Something like this if I understand strdel right: (roughly, not tested!, needs bounds checking on pos and n )
char *strdel(char *s, int pos, int n) {
char *dst = s + pos, *src = s + pos + n;
while(*src) {
*dst++ = *src++;
}
*dst = 0;
return s;
}
I'll throw in my solution for the second part as well. Here's my strdel
char * strdel(char * s, int pos, int n){
memmove(s + pos, s + pos + n, strlen(s) - pos - n + 1);
return s;
}
It doesn't copy, it doesn't do bounds checking and the return-value is rather redundant (as it's equal to the input s). So all-in-all it's very standard-C-library-like.
Warning! Cannot be used for string-constants as it modifies s (hence no const char * s).
To address the second part of your question, I would have written it something like this (assuming you're going to be passing in string constants and therefore must make a copy of the incoming string):
/*
* Returns a copy of the NUL terminated string at s, with the
* portion n characters long starting at position pos removed.
*/
char* strdel(char* s, int pos, int n)
{
int size = strlen(s);
char* t = malloc(size - n);
memcpy(t, s, pos);
memmove(t + pos, s + pos + n, size - n + 1);
return t;
}