Changing size of dynamic *char - c

Is there way how to make my string to even size?
EDIT:
I need a few string in struct that have even length. So something like:
struct msg { char * first; char * second; char * third; };
so it is in the end something like first string "hi\0\0" second string "hello\0" third string "byebye\0\0" and i need to change them anytime+they are dynamic allocated.

Create a strdup_even().
Allocate memory as needed to copy the string, plus maybe 1 more to make "even".
char *strdup_even(const char *str) {
size_t len = strlen(str) + 1; // Size needed for the _string_
size_t len2 = len + len % 2; // Even allocation size
char *copy = malloc(len2);
if (copy) {
memcpy(copy, str, len);
if (len2 > len) {
copy[len] = '\0';
}
}
return copy;
}
Sample usage
struct msg m;
m.first = strdup_even("hi");
m.second = strdup_even("hello");

Use malloc() and realloc():
char *string = malloc(STRING_SIZE);
strcpy(string, "hi");
string = realloc(string, STRING_SIZE+1);
string[STRING_SIZE] = '\0';

Related

Appending strings results in "realloc(): Invalid pointer"

I have a function append_string, which appends str2 to str1:
void append_string(char* str1, char* str2) {
int new_length = strlen(str1)+strlen(str2);
size_t new_size = sizeof(char)*(new_length);
str1 = (char*) realloc(str1, new_size);
strcat(str1, str2);
}
As shown in the function, I'm trying to increase the size using a the combined size of the strings.
Whenever I call append_str("", "adc");, I get "realloc(): Invalid pointer"
What did I do wrong?
At least these problems:
Attempting to reallocate something not allocated.
realloc(str1, new_size) attempts to reallocate the string literal "" leading to "realloc(): Invalid pointer".
Size off by 1
New size did not account for the null character.
// size_t new_size = sizeof(char)*(new_length);
size_t new_size = sizeof(char)*(new_length + 1);
Code loses the allocated pointer
Calling code lost the value of the new pointer str.
Weak type for sizing
Use size_t.
Instead, pass in an allocated pointer or NULL by its address.
void append_string(char** str, const char* appendage) {
size_t new_length = strlen(*str) + strlen(appendage);
size_t new_size = sizeof(char)*(new_length + 1);
*str = realloc(*str, new_size);
strcat(*str, appendage);
}
// Usage
char *s = malloc(1);
strcpy(s, "");
append_str(&s, "adc");
puts(s);
Advanced issues include:
What to do if realloc() returns NULL?
How to handle appendage overlapping str?
Do not use strcat(). Avoid slow code. Better to retain the original string length and copy from there.
void append_string(char** str, const char* appendage) {
size_t str_len = *str ? strlen(*str) : 0;
size_t app_len = strlen(appendage);
void *p = realloc(*str, str_len + app_len + 1);
if (p == NULL) {
// Handle Error - various approaches
free(*str);
*str = NULL;
} else {
strcpy(*str + str_len, appendage);
}
}
Still need to handle case when appendage overlaps *str.
void append_string_when_overlap_possible(char** str, const char* appendage) {
size_t str_len = *str ? strlen(*str) : 0;
size_t app_len = strlen(appendage);
char *p = malloc(str_len + app_len + 1);
if (p == NULL) {
// Handle Error - various approaches
free(*str);
*str = NULL;
} else {
if (*str) {
strcpy(p, *str);
}
strcpy(p + str_len, appendage);
free(*str);
*str = p;
}
}

How to copy char array in C without inner function

This is my code
char function(char *dst)
{
int i;
char *arr;
i = 0;
while(dst[i] != '\0')
{
arr[i] = dst[i];
i++;
}
dst[i] != '\0'
return(arr);
}
int main(void)
{
char a[] ="asdf"
printf("%s", function(a);
}
I want to copy *dst to empty *arr but my code didn't work.
I can't understand.
How can I copy array without inner function in C(ex_strcpy, memspy....)
Thank you
Apart from missing ; and making sure that the string being passed to the function is always a '\0' terminated one ( else the program will run into side effects strcpy causes ). and returning char* instead of char, you missed allocating memory for arr
// return char * instead of char
char* function(char *dst)
{
// Note - sizeof(dst) wont work
// Neither does sizeof(dst)/sizeof(char)
// allocate one extra for '\0'
size_t size_to_alloc = (strlen(dst) + 1) * (sizeof *arr);
char *arr = malloc( size_to_alloc );
char *p = arr;
for ( ; *dst ; p++, dst++)
*p = *dst;
*p = '\0';
return(arr);
}
If you want to dynamically copy an array, you'll need to allocate memory for the char array using malloc or other equivalent. Make sure you free the memory once you're done with it. I would suggest reading some posts on malloc and allocating memory in c.
This is probably a good place to start.
https://www.geeksforgeeks.org/dynamic-memory-allocation-in-c-using-malloc-calloc-free-and-realloc/
#include <stdio.h>
#include <stdlib.h>
char* function(char *dst, size_t length) {
int i;
// Allocating the memory needed for the char array.
char *arr = (char*) malloc (sizeof(char) * length);
i = 0;
while(dst[i] != '\0') {
arr[i] = dst[i];
i++;
}
arr[length - 1] = '\0';
return(arr);
}
int main(void) {
char a[] ="asdf";
// Getting length of the array
size_t length = sizeof(a) / sizeof(a[0]);
char* val = function(a, length);
printf("%s", val);
free(val);
}
You are missing the memory allocation and basically attempting to recode strdup. See below:
char *ft_strdup(const char *src)
{
char *dst;
int len;
len = 0;
while (src[len]) // no inner function
++len;
if (!(dst = malloc(sizeof(char) * (len + 1)))) // need 1 extra char to NULL terminate.
return NULL;
dst[len] = '\0';
while (--len > -1)
dst[len] = src[len];
return dst;
}
Note that it makes sense to code your own version of strdup and include it in your program library as this function is not part of the C Standard.
If there is a possibility of copying strings without using c functions, perhaps it can be done by doing what c functions do.
it may be interesting to see what strcpy does:
https://code.woboq.org/userspace/glibc/string/strcpy.c.html
char *
STRCPY (char *dest, const char *src)
{
return memcpy (dest, src, strlen (src) + 1);
}
infact it uses memcpy: https://code.woboq.org/gcc/libgcc/memcpy.c.html
and here the magic...
void *
memcpy (void *dest, const void *src, size_t len)
{
char *d = dest;
const char *s = src;
while (len--)
*d++ = *s++;
return dest;
}
and strlen: https://code.woboq.org/userspace/glibc/string/strlen.c.html
You can use memcpy() to copy memory directly, like in Memcpy, string and terminator and https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html In C any string has to be terminated by \0 (sentinel value)
#include<stdio.h>
#include<string.h>
int main()
{
char source[] = "World";
char destination[] = "Hello ";
/* Printing destination string before memcpy */
printf("Original String: %s\n", destination);
/* Copies contents of source to destination */
memcpy (destination, source, sizeof(source));
/* Printing destination string after memcpy */
printf("Modified String: %s\n", destination);
return 0;
}
source : https://www.educative.io/edpresso/c-copying-data-using-the-memcpy-function-in-c

How can I predetermine the size of a malloc to concatenate an array of strings?

Implement the append function that has the prototype below. The function returns a string that represents the concatenation of all the strings present in an array of strings. For this problem, you can assume the end of the parameter array is marked by NULL. You need to allocate memory for the resulting string. You may not modify the array parameter.
char* append(char *data[]);
I don't understand how to determine the size to malloc the pointer.
First of all, to know the size of one string, you can use strlen from the library string.h. If you want to calculate the sum of all the sizes you can just use a loop and sum up all the strlens, and add 1 for the terminal NUL character, like this:
char* append(char *data[]) {
char **cur, *res;
size_t len = 0;
for (cur = data; *cur != NULL; *cur++)
len += strlen(*cur);
res = malloc(len + 1);
// Now you can concatenate the strings...
}
Oh, and don't forget to check that the pointer returned by malloc is valid (i.e. not NULL).
An approach that goes through the strings twice seems good.
The first pass counts the sum of the lengths:
size_t len = 0;
for (char** pstr = data; *pstr; pstr++)
len += strlen(*pstr);
The second pass concatenates all the strings:
char *str = malloc(len + 1);
str[0] = '\0';
for (char** pstr = data; *pstr; pstr++)
strcat(str, *pstr);
return str;
You can optimize the concatenation part by storing the end point of the last concatenation:
char *str = malloc(len + 1);
str[0] = '\0';
char *p = str;
for (char** pstr = data; *pstr; pstr++) {
strcat(p, *pstr);
p += strlen(*pstr);
}

How to Concatenate 2 C strings, without overwriting any terminating Null characters?

I am trying to set up a list of file names for a parameter to SHFileOperation. I want to be able to concatenate a file name onto the char array, but i dont want to get rid of the terminating character. for example, I want this:
C:\...\0E:\...\0F:\...\0\0
when i use strcat(), it overwrites the null, so it looks like
C:\...E:\...F:\...0\
Is there any easy way to do this? or am i going to have to code a new strcat for myself?
The code is pretty straightforward. Use a helper pointer to track where the next string should start. To update the tracker pointer, increment by the length of the string +1:
const char *data[] = { "a", "b", "c" };
size_t data_count = sizeof(data) / sizeof(*data);
size_t d;
size_t buffer_size;
char *buffer;
char *next;
// calculate the size of the buffer
for (d = 0; d < data_count; ++d)
buffer_size += (strlen(data[d] + 1);
buffer_size += 1;
buffer = malloc(buffer_size);
// Next will track where we write the next string
next = buffer;
for (d = 0; d < data_count; ++d)
{
strcpy(next, data[d]);
// Update next to point to the first character after the terminating NUL
next += strlen(data[d]) + 1;
}
*next = '\0';
Use memcpy.
memcpy(dest, src1, strlen(src1)+1);
memcpy(&dest[strlen(src1)+1], src2, strlen(src2)+1);
Using the GNU stpcpy() may be slightly more elegant, if you know beforehand the maximum 'length' of the resulting char array.
char *src[] = {"C:\\foo", "E:\\bar", "F:\\foobar", 0};
char dst[MY_MAX_LEN], *p = dst;
int i;
for (i = 0; src[i]; i++)
p = stpcpy(p, src) + 1;
*p = 0;
assert(p < dst + sizeof dst);
If needed, stpcpy() can be defined as:
char *stpcpy(char * restrict dst, const char * restrict src)
{
return strcpy(dst, src) + strlen(src);
}
just use strcat to append to the original string, but add one to the offset so you're bypassing the previous string's 0 terminator.
// an example
char testString [256];
strcpy (testString, "Test1");
strcat (testString + strlen(testString)+1, "Test2");
strcat (testString + strlen(testString)+1, "Test3");
testString will now contain "Test1\0Test2\0Test3\0"

Homework: In C, how does one get a substring of an array using only pointers?

Using pointer arithmetic, it's possible to assign characters from one array to another. My question is, how does one do it given arbitrary start and stop points?
int main(void)
{
char string1[] = "something"; //[s][o][m][e][t][h][i][n][g][\0]
int start = 2, count = 3;
char string2[10] = {0};
char *ptr1 = &string1[start];
char *ptr2 = string2;
while (*ptr2++ = *ptr1++) { } //but stop after 3 elements???
printf("%s",&string2);
}
There's some kind of pointer arithmetic I'm missing to count/test the quantity of elements in a particular array. I do NOT want to declare an integral to count the loop! I want to do it all using pointers. Thanks!
When you write ptr1++;, it is equivalent to ptr1 = ptr1 + 1;. Adding an integer to a pointer moves the memory location of the pointer by the size (in bytes) of the type being pointed to. If ptr1 is a char pointer with value 0x5678 then incrementing it by one makes it 0x5679, because sizeof(char) == 1. But if ptr1 was a Foo *, and sizeof(Foo) == 12, then incrementing the pointer would make its value 0x5684.
If you want to point to an element that is 3 elements away from an element you already have a pointer to, you just add 3 to that pointer. In your question, you wrote:
char *ptr1 = &string1[start]; // array notation
Which is the same thing as:
char *ptr1 = string1 + start; // pointer arithmetic
You could rewrite as follows:
int main(void)
{
char string1[] = "something"; //[s][o][m][e][t][h][i][n][g][\0]
int start = 2, count = 3;
char string2[10] = {0};
// Ensure there is enough room to copy the substring
// and a terminating null character.
assert(count < sizeof(string2));
// Set pointers to the beginning and end of the substring.
const char *from = string1 + start;
const char *end = from + count;
// Set a pointer to the destination.
char *to = string2;
// Copy the indicated characters from the substring,
// possibly stopping early if the end of the substring
// is reached before count characters have been copied.
while (from < end && *from)
{
*to++ = *from++
}
// Ensure the destination string is null terminated
*to = '\0';
printf("%s",&string2);
}
Using const and meaningful variable names (from, to, or src, dst, instead of ptr1, ptr2) helps you avoid mistakes. Using assert and ensuring the string is null-terminated helps you avoid having to debug segfaults and other weirdness. In this case the destination buffer is already zeroed, but when you copy parts of this code to use in another program it may not be.
#include <stdio.h>
int main(void)
{
char string1[] = "something"; //[s][o][m][e][t][h][i][n][g][\0]
int start = 2, count = 3;
char string2[10] = {0};
char *ptr1 = &string1[start];
char *stop = ptr1 + count;
char *ptr2 = string2;
while ((ptr1 < stop) && (*ptr2++ = *ptr1++));
printf("%s",string2);
return 0;
}
I usually use a specific set of variable names in these situations, called:
src - source
dst - destination
end - the end of either the source (used here) or the destination
So:
int main(void)
{
char string1[] = "something";
int start = 2;
int count = 3;
char string2[10] = {0};
const char *src = &string1[start];
const char *end = &string1[start+count];
char *dst = string2;
assert(count < sizeof(string2);
while (src < end)
*dst++ = *src++;
*dst = '\0'; // Null-terminate copied string!
printf("%s",&string2);
return(0);
}
Or, more plausibly, packaged as a function:
char *copy_substr(char *dst, const char *str, size_t start, size_t len)
{
const char *src = str + start;
const char *end = src + len;
while (src < end)
*dst++ = *src++;
*dst = '\0';
return(dst);
}
int main(void)
{
char string1[] = "something";
char *end;
char string2[10] = {0};
end = copy_substr(string2, string1, 2, 3);
printf("%s",&string2);
return(0);
}
The function returns a pointer to the end of the string which is aconventional and doesn't provide a marked benefit in the example, but which does have some merits when you are building a string piecemeal:
struct substr
{
const char *str;
size_t off;
size_t len;
};
static struct substr list[] =
{
{ "abcdefghijklmnopqrstuvwxyz", 2, 5 },
...
{ "abcdefghijklmnopqrstuvwxyz", 18, 3 },
};
int main(void)
{
char buffer[256];
char *str = buffer;
char *end = buffer + sizeof(buffer) - 1;
size_t i;
for (i = 0; i < 5; i++)
{
if (str + list[i].len >= end)
break;
str = copy_substr(str, list[i].str, list[i].off, list[i].len);
}
printf("%s\n", buffer);
return(0);
}
The main point is that the return value - a pointer to the NUL at the end of the string - is what you need for string concatenation operations. (In this example, with strings that have known lengths, you could survive without this return value without needing to use strlen() or strcat() repeatedly; in contexts where the called function copies an amount of data that cannot be determined by the calling routine, the pointer to the end is even more useful.)
In order to get the size (i.e. number of elements) in a static array, you would usually do
sizeof(string1) / sizeof(*string1)
which will divide the size (in bytes) of the array by the size (in bytes) of each element, thus giving you the number of elements in the array.
But as you're obviously trying to implement a strcpy clone, you could simply break the loop if the source character *ptr1 is '\0' (C strings are zero-terminated). If you only want to copy N characters, you could break if ptr1 >= string1 + start + count.

Resources