Duplicate function -> exited, segmentation fault ç_ç - c

I'm programming in C, I know why when I start my program, the terminal show me this error, but I don't know how to fix it (I have read many question about this, but no I can't solve this problem) :
My function is :
char * String_dup(char const string[]) {
size_t size = strlen(string);
char * copy = malloc(size * copy[0]);
assert(copy != NULL);
strcpy(copy, string);
return copy;
}
it consist to duplicate my string[].
And this is my test :
void StringTest_dup(void) {
char string[] = "voiture";
assert(strcmp(string, String_dup(string)));
}
Thank you for your help.

I re-wrote it a bit and it seems to work without a problem. One obvious misundertanding you have is that strcmp returns 1 when they match which is wrong. If the two inputs to strcmp are the same then it returns 0, thus !strcmp(...).
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
char* String_dup(const char* string) {
size_t size = strlen(string);
char* copy = malloc(size * sizeof(char) + 1);
assert(copy != NULL);
strcpy(copy, string);
return copy;
}
int main(void) {
const char* string = "test";
char* copy = String_dup(string);
assert(!strcmp(string, copy));
printf("%s\n", string);
printf("%s\n", copy);
free(copy);
return 0;
}

Related

how can I multiply strings in C like I do in python?

in python you can easily type:
str = "hi"
print(str * 10)
and the output would be hi printed 10 times. I'm currently learning how to code in C and I have to do this. Can someone teach me how I can do this kind of thing in C? Thanks in advance
Use for() loop:
Example:
#include <stdio.h>
int main() {
char* str = "hi";
for (int i = 0; i < 10; ++i) {
printf("%s", str);
}
}
And if you need to actually multiply the string (not just print n times) you can use the following mulstr(), just don't forget to test for NULL and to free():
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>
char* mulstr(char* str, size_t i) {
size_t len = strlen(str);
char* newstr = malloc(len * i + 1);
if (newstr) {
char* writer = newstr;
for (; i; --i) {
memcpy(writer, str, len);
writer += len;
}
*writer = 0;
} else {
perror("malloc");
}
return newstr;
}
int main() {
char* str = "hi";
char* newstr = mulstr(str, 10);
if (newstr) {
printf("%s", newstr);
free(newstr);
}
}
Using for-loop is the best way to implement this.
You can just create a customized print function which will do the same thing as python does. I am just giving a prototype here.
#include <stdio.h>
void print(char *string,int n)
{
int i;
for(i=0;i<n;i++)
{
printf("%s\n",string);
}
}
int main()
{
char *str="Hi";
print(str,2);
return 0;
}
Here second argument in the function n will tell you how many times you want to print the string.
The output will look like
Hi
Hi

Why use const char *prt1 when we can't change the containing of the pointer

If we use for example:
char* strs[2];
strs[1] = "Hello";
strs[2] = "World!";
strcat(strs[1],strs[2]);
Then an access violation comes up (Access violation writing location 0x0028CC75).
So why use const char *strs[2]; since the strs1[1], strs1[2] cannot be changed?
// string literals are non-writeable so const is appropriate here
const char* strs[2] = {"Hello", "World!"};
// let's create a target buffer with sufficient space
char buffer[20];
// copy the first string there
strcpy(buffer, strs[0]);
// add the second string there
strcat(buffer, strs[1]);
Two sources of access violation in your case
String literals are read only and writing to them is undefined behavior
In c arrays are 0 index based, so strs[2] does not exist, only strs[0] and strs[1].
Using const prevents you from accidentally modifying them, but it does not forbid you.
Arrays are modifiable though,
#include <stdio.h>
#include <string.h>
int
main(void)
{
char strs[2][11] = {"Hello", "World"};
strcat(strs[0], strs[1]);
return 0;
}
the above works as you expected it.
Here it is how you would do it correctly with dynamic allocation
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *
autostrcat(const char *const head, const char *const tail)
{
char *result;
size_t headlen;
size_t taillen;
if ((head == NULL) || (tail == NULL))
return NULL;
headlen = strlen(head);
taillen = strlen(tail);
result = malloc(1 + headlen + taillen);
if (result == NULL)
return NULL;
memcpy(result, head, headlen);
memcpy(&result[headlen], tail, taillen);
result[headlen + taillen] = '\0';
return result;
}
int
main(void)
{
const char *strs[2] = {"Hello", "World"};
char *result = autostrcat(strs[0], strs[1]);
if (result != NULL)
printf("%s\n", result);
free(result);
return 0;
}
Since you used strlen() you know what the lengths of the strings are, so using strcat() would be unecessarily expensive because it would again figure out the length of the first string as strlen() does.
Wow. So much wrong.
Arrays are 0 based, not 1 based in C.
The strings are based in program space, most likely, so aren't writeable.
you should create a buffer, and then fill it.
char* concat = (char *) _alloca(strlen(strs[0]) + strlen(strs[1])+1);
strcpy(concat, strs[0]);
strcat(concat, strs[1]);

Unknown Segfault

Thanks in advance for your help. I've done all the research I could trying to debug this. Adding printf's seems to change where the segfault occurs. I'm hardly familiar with gdb but somehow the program ran without issue in it. I've got some quantum observation problem going on. Let's get into the code.
This is just to reacquaint myself with C. The segfault is happening somewhere in create_string(). I could never get a printf() to show up right before the set_string(str, src); call.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char* value;
size_t mlength;
size_t length;
} StringContainer;
typedef struct {
StringContainer* value;
StringContainer* next;
} StringContainerList;
void set_string(StringContainer *str, const char* src);
StringContainer* create_string(const size_t max_length, const char* src);
size_t string_length(StringContainer* str);
int main(int argc, char *argv[])
{
StringContainer* str = create_string(100, "The quick brown fox jumped over the lazy dog.");
printf("Test: string_length\n");
printf("%zu\n", string_length(str));
return 0;
}
StringContainer* create_string(const size_t max_length, const char* src)
{
StringContainer* str;
size_t str_len;
if ( src == NULL )
{
str_len = 0;
}
else
{
str_len = strlen(src);
}
str = (StringContainer*)malloc(sizeof(StringContainer));
str->mlength = max_length;
if ( str_len > 0 )
{
// set_string will delayed-malloc str->value :)
set_string(str, src);
}
return str;
}
void set_string(StringContainer* str, const char* src)
{
if (str->value == NULL)
{
str->value = (char*)malloc(str->mlength * sizeof(char));
memset(str->value, '\0', str->mlength);
}
strcpy(str->value, src);
str->length = strlen(str->value);
}
size_t string_length(StringContainer* str)
{
char* value = str->value;
size_t max_length = str->mlength;
size_t offset_idx = 0;
size_t division = max_length / 2;
while (division != 0)
{
if ( value[offset_idx + division] != '\0' )
{
offset_idx = offset_idx + division;
}
division /= 2;
}
return offset_idx;
}
Thanks all for your time. I'm sure it's simple, something possibly fundamental, but my Google-foo is not developed enough to find the root of the issue.
Also, is this design pattern common? Obviously the malloc's should have free's associated. I'll also add in checking the malloc was successful.
In the create_string() function you should properly set the values of malloced str so that it does not contain any random values.
Especially, str->value is not set to NULL. And then you are checking it in set_string() which may not succeed and you would strcpy() to unallocated memory causing undefined behavior.
So for minimum update your create_string() function as
str = (StringContainer*)malloc(sizeof(StringContainer));
str->mlength = max_length;
str->value = NULL; //add this

Overwriting parts of a string with parts of another string

I'm trying to overwrite a part of a string with parts of another String.
Basically, I want to access a given index of a string, write a given number of chars from another given index of another string.
So a function like memcpy(stringa[indexa], stringb[indexb], length);, except that this does not work.
Using strncpy would also suffice.
More code, as requested:
void mymemset(char* memloc, char* cmd, int data_blocks[], int len)
{
int i = 0;
while(i < len)
{
//missing part. Where I want the "memcpy" operation to take place
i++;
}
return;
}
memloc is the string we want to overwrite, cmd is the string we are overwriting from, data_blocks contains information about where in memloc we are supposed to write, and len is the number of operations we are executing. So I want to overwrite at location data_blocks[i], from cmd 8 chars at a time.
EDIT: I think I just forgot an &, so sorry to have confused you and thanks for your time. This seems to work:
void mymemset(char* memloc, char* cmd, int data_blocks[], int len)
{
int i = 0;
while(i < len)
{
memcpy(&memloc[data_blocks[i]], &cmd[i*8], 8);
i++;
}
return;
}
Takes 8 bytes at a time from cmd, stores them in memloc at the index given by data_blocks[i]. As commented, data_blocks contains information about different indexes in memloc that is available, and segmentation of the string cmd can occur.
Supposing stringa and stringb are declared as follows
char stringa[] = "Hello" ;
char stringb[] = "World" ;
This should work:
memcpy(&stringa[1], &stringb[1], 2) ;
Your example should not compile, or if it compiles if is likely to crash or to cause undefined behaviour :
memcpy(stringa[1], stringb[1], 2) ;
Your naming is confusing : memset works on bytes. If you manipulate strings you have extra precaution to take: think of the \0.
I think you want something like that:
void my_str_overwrite(char* dest, const char* ref, int idx, size_t count)
{
size_t input_len = strlen(dest);
if(input_len <= idx+count)
{
// Error: not enough space
}
for(size_t i=0; i<count; i++)
{
dest[idx+i] = ref[i];
}
return;
}
You don't need to pass the whole data_block[] array, you just interested in one element of this array which contains an offset for your copy, if I understood correctly.
As you don't modify cmd it should be const
The code above does not handle the NULL terminating byte which should be appended to memloc if it is actually a string
So I want to overwrite at location data_blocks[i], from cmd 8 chars at a time.
This one is confusing. If you know that you only want 8 bytes to be copied each time you call the function then in the code above make count an local variable within the function and fix it size_t count = 8;
if strings are the same size the you can just use memcpy:
#include <strings.h>
char text[] = "Hello James!";
char name[] = "Jenny";
char* pos = strstr(text, "James");
memcpy(pos, name, strlen(name)-1); // for the '\0'
If they're not then you must reallocate the string as the length will change
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define STR "Hello James!"
void replace(char** src, char* find, char* rep) {
char* ret = NULL;
char* pos = strstr(*src, find);
if (!pos)
return; // no changes
int l = (1 + strlen(*src) + strlen(rep) - strlen(find));
ret = (char*)malloc(sizeof(char) * l);
ret[l-1] = 0;
int ind = (int)(pos - *src);
strncpy(ret, *src, ind);
printf("ind: %d; %s\n", ind, ret);
strncpy(&ret[ind], rep, strlen(rep));
strncpy(&ret[ind+strlen(rep)], &pos[strlen(find)], strlen(pos)-strlen(find));
printf("%s\n", ret);
free(*src);
*src = ret;
}
int main() {
char *str = NULL;
str = (char*)malloc(sizeof(char) * (strlen(STR)+1));
assert(str);
strcpy(str, STR);
printf("before: %s\n", str);
replace(&str, "James", "John");
printf("after: %s\n", str);
free(str);
return 0;
}
This code in not optimized.

Splitting string with delimiters in C - segmentation fault

I want to write a function that will split a string into a char array. I know that the result array will ALWAYS have only two elements - servername and serverport. I wrote this, but it gives me "Segmentation fault" after compilation:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* splitString(char stringToSplit[])
{
int i = 0;
char serverinfo[2];
char *tmp;
tmp = strtok(stringToSplit, ":");
while (tmp != NULL)
{
serverinfo[i] = tmp;
tmp = strtok(NULL, ":");
i++;
}
return serverinfo;
}
int main(int argc, char **argv)
{
char st[] = "servername:1234";
char *tab = splitString(st);
printf("%s\n", tab[0]);
printf("%s\n", tab[1]);
return 0;
}
char serverinfo[2];
allocates space for two chars, but you store char*s there, so make it
char* serverinfo[2];
But you return it from the function, however, the local variable doesn't exist anymore after the function returned, so you need to malloc it
char **serverinfo = malloc(2*sizeof *serverinfo);
and declare the function as
char **splitString(char stringToSplit[])
for the correct type.

Resources