Unknown Segfault - c

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

Related

Is there an easy way to remove specific chars from a char*?

char * deleteChars = "\"\'.“”‘’?:;-,—*($%)! \t\n\x0A\r"
I have this and i'm trying to remove any of these from a given char*. I'm not sure how I would go about comparing a char* to it.
For example if the char* is equal to "hello," how would I go about removing that comma with my deleteChars?
So far I have
void removeChar(char*p, char*delim){
char*holder = p;
while(*p){
if(!(*p==*delim++)){
*holder++=*p;
p++;
}
}
*holder = '\0';
A simple one-by-one approach:
You can use strchr to decide if the character is present in the deletion set. You then assign back into the buffer at the next unassigned position, only if not a filtered character.
It might be easier to understand this using two indices, instead of using pointer arithmetic.
#include <stdio.h>
#include <string.h>
void remove_characters(char *from, const char *set)
{
size_t i = 0, j = 0;
while (from[i]) {
if (!strchr(set, from[i]))
from[j++] = from[i];
i++;
}
from[j] = 0;
}
int main(void) {
const char *del = "\"\'.“”‘’?:;-,—*($%)! \t\n\x0A\r";
char buf[] = "hello, world!";
remove_characters(buf, del);
puts(buf);
}
stdout:
hello world
If you've several delimiters/characters to ignore, it's better to use a look-up table.
void remove_chars (char* str, const char* delims)
{
if (!str || !delims) return;
char* ans = str;
int dlt[256] = {0};
while (*delims)
dlt[(unsigned char)*delims++] = 1;
while (*str) {
if (dlt[(unsigned char)*str])
++str; // skip it
else //if (str != ans)
*ans++ = *str++;
}
*ans = '\0';
}
You could do a double loop, but depending on what you want to treat, it might not be ideal. And since you are FOR SURE shrinking the string you don't need to malloc (provided it was already malloced). I'd initialize a table like this.
#include <string.h>
...
char del[256];
memset(del, 0, 256 * sizeof(char));
for (int i = 0; deleteChars[i]; i++) del[deleteChars[i]] = 1;
Then in a function:
void delChars(char *del, char *string) {
int i, offset;
for (i = 0, offset = 0; string[i]; i++) {
string[i - offset] = string[i];
if (del[string[i]]) offset++;
}
string[i - offset] = 0;
}
This will not work on string literals (that you initialize with char* x = "") though because you'd end up writing in program memory, and probably segfault. I'm sure you can tweak it if that's your need. (Just do something like char *newString = malloc(strlen(string) + 1); newString[i - offset] = string[i])
Apply strchr(delim, p[i]) to each element in p[].
Let us take advantage that strchr(delim, 0) always returns a non-NULL pointer to eliminate the the null character test for every interrelation.
void removeChar(char *p, char *delim) {
size_t out = 0;
for (size_t in; /* empty */; in++) {
// p[in] in the delim set?
if (strchr(delim, p[in])) {
if (p[in] == '\0') {
break;
}
} else {
p[out++] = p[in];
}
}
p[out] = '\0';
}
Variation on #Oka good answer.
it is better way - return the string without needless characters
#include <string.h>
char * remove_chars(char * str, const char * delim) {
for ( char * p = strpbrk(str, delim); p; p = strpbrk(p, delim) )
memmove(p, p + 1, strlen(p));
return str;
}

Duplicate function -> exited, segmentation fault ç_ç

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;
}

realloc, two dimention allocation, leak and errors in valgrind

I wrote a program to split given string according to certain delimiter. Everything works fine but there are leak and error in valgrind.
split algorithm is correct.
substr works fine.
My program:
#include <stdio.h>
#include <stdlib.h>
char** split(const char*, char, int*);
char* substr(const char*, int, int);
void freepath(char**, int);
int main(void) {
char *str = "home///ubuntu//Desktop";
char **path = NULL;
int size = 0;
path = split(str, '/', &size);
freepath(path, size);
return 0;
}
char** split(const char *str, char c, int *size) {
char **path = NULL;
const char *save = str;
int from=-1, i;
if(str == NULL)
return NULL;
for(i=0 ; 1; ++i) {
if(*str == '\0') {
if(from != -1) {
++(*size);
path = (char**)realloc(path, (sizeof(char**) *(*size)));
*(path+(*size)-1) = substr(save, from, i);
}
break;
}
if(*str != '/') {
if(from == -1)
from = i;
}
else {
if(from != -1) {
++(*size);
path = (char**)realloc(path, (sizeof(char)*(*size)));
*(path+(*size)-1) = substr(save, from, i);
}
from = -1;
}
++str;
}
return path;
}
void freepath(char **path, int size) {
int i=0;
for(i=0; i<size; ++i) {
free(*(path+i));
*(path+i) = NULL;
}
free(path);
path = NULL;
}
char* substr(const char *src, int m, int n)
{
int len = n - m;
char *dest = (char*)malloc(sizeof(char) * (len + 1));
for (int i = m; i < n && (*(src + i) != '\0'); i++)
{
*dest = *(src + i);
++dest;
}
*dest = '\0';
return dest - len;
}
Valgrind output:
What should be the reason ? , I really stuck with it !
clang analyser has found 4 suspected points in your code:
1.
char *str = "home///ubuntu//Desktop";
needs const in front of char (pointer to const).
2.
char** split(const char *str, char c, int *size) {
contains an unused parameter (c).
3.
path = (char**)realloc(path, (sizeof(char**) *(*size)));
clang-analyser does not like char** as the argument of sizeof, replacing it with char* removes the warning.
4.
path = (char**)realloc(path, (sizeof(char)*(*size)));
The same warning as in 3. Errr, no, not the same. Bingo! Replace char inside sizeof with char* and you're back home.
One final remark. When you use valgrind, always add debugging information to the compiled code, that is, add -g to the compiler command-line options (gcc, clang, etc.). This will give you the information about the exact lines numbers in your source code corresponding to the places where the problem was spotted by valgrind. My screenshot of your program under valgrind contains more information than yours:
Please notice that valgrind correctly identifies line 44 as the line with the buggy memory allocation (or line 45 with a buggy usage of the buffer allocated at line 44. Both options are a priori possibly correct).

C - Freeing string after cycle for

I have this simple function for extrapolate a substring in a string.
char* substr(const char *string, size_t start, size_t end) {
const char *char_start = &string[start];
const char *char_end = &string[end];
char *substring = (char *) calloc(1, char_end - char_start + 1);
memcpy(substring, char_start, char_end - char_start + 1);
return substring;
}
I have only one calloc, that create the returned string.
I try the code in a cycle, for extrapolate the substring of a string array.
This is the main code where I test the function:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t i;
char *tmp = NULL;
char *kmer_array[5] = {"GTGAA", "ACGGT", "AACGG", "AGTGA", "TGAAC"};
for ( i = 0; i < 5; i++ ) {
tmp = substr(kmer_array[i], 1, strlen(kmer_array[i]));
}
free(tmp);
return 0;
}
But when I test the code with valgrind this is the output (link).
I dont't understade where I lost the byte
You set tmp inside the loop 5 times but only free the last one (outside the loop)

In C, how can one dynamically build an array of strings in a function and return to caller

RHEL6
I'm trying to implement a perl split funciton in a C subroutine which dynamically builds the array of strings. My attempt fails with a segfault. But it does not fail if I comment out the printf statement in the for loop (perhaps implying that the segfault is in where its getting built as opposed to how)
Here it is...
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int split(char *s, char **arr);
void main(int argc, char* argv[])
{
int x;
int arrsz;
char str[]="aaa:bbb:ccc";
char **arr;
arrsz=split(str,arr);
for(x=0;x<arrsz;x++) {
printf("%s\n",arr[x]);
}
exit(0);
}
/***********************************/
int split(char *str, char **arr) {
int arrsz=0;
char delim[2] = ":";
char *tok;
arr = malloc(sizeof(char **));
arr[0] = malloc(1);
arr[0] = '\0';
tok = strtok(str,delim);
while(tok != NULL) {
arrsz++;
arr = (char **)realloc(arr,(arrsz*sizeof(char *))+1);
arr[arrsz-1] = malloc((sizeof(char)*strlen(tok))+1);
strcpy(arr[arrsz-1],tok);
arr[arrsz]=malloc(1);
arr[arrsz]='\0';
tok = strtok(NULL,delim);
}
return(arrsz);
}
I think the problem is in how I'm passing "arr" to the split function or how it's being received and used in the function. I say this because if I move the body of the function to main, it works there.
I tried dealing with arr inside the functions as it it was a (char ***), but that didn't work.
Can a C expert out there set me straight ?
The main error is that you should pass a pointer to the strings list to the split function, not the strings list itself, so you should use an ***arr:
int split(char *str, char ***arr);
And you should use & to pass the pointer in main:
...
arrsz=split(str,&arr);
...
In the function you could use a double pointer to avoid confusion and at the end assign that pointer to the parameter:
int split(char *str, char ***arrreturn) {
char **arr; //Use this strings list to add the strings
...
*arreturn = arr;
return(arrsz);
}
-You should not call realloc anytime you need to insert a string, but you could oversize it and increment its dimension if you need.
-I cannot see the need of assign '\0' at the end of the list if you have a variable with the length
-You can use strdup instead of malloc-strcpy funcs:
char *first = "ciao";
char *str = malloc(strlen(first) * sizeof(char));
strcpy(str, first);
Is equal to:
char *first = "ciao";
char *str = strdup(first);
I corrected your code:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int split(char *str, char ***arrreturn);
void main(int argc, char *argv[]) {
int x;
int arrsz;
char str[] = "aaa:bbb:ccc";
char **arr;
arrsz = split(str, &arr);
for (x = 0; x < arrsz; x++) {
printf("%s\n", arr[x]);
}
exit(0);
}
/***********************************/
int split(char *str, char ***arrreturn) {
int arrsz = 1;
int len = 0;
char delim[2] = ":";
char *tok;
char **arr;
arr = malloc(sizeof(char **));
tok = strtok(str, delim);
while (tok != NULL) {
len++;
if (len >= arrsz) {
arrsz *= 2;
arr = realloc(arr, arrsz * sizeof(char **));
}
arr[len - 1] = strdup(tok);
tok = strtok(NULL, delim);
}
*arrreturn = arr;
return (len);
}
There are a few bugs. I've annotated and [partially] fixed bugs. It will still segfault. I added a refactored version that will work correctly.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int split(char *s, char **arr);
void main(int argc, char* argv[])
{
int x;
int arrsz;
char str[]="aaa:bbb:ccc";
char **arr;
#if 1
#endif
arrsz=split(str,arr);
for(x=0;x<arrsz;x++) {
printf("%s\n",arr[x]);
}
exit(0);
}
/***********************************/
int split(char *str, char **arr) {
int arrsz=0;
char delim[2] = ":";
char *tok;
// NOTE/BUG: this function only changes arr within the function and does
// _not_ propagate it to the caller
arr = malloc(sizeof(char **));
// NOTE/BUG: this is replaced in the loop and leaks memory
#if 0
arr[0] = malloc(1);
arr[0] = '\0';
#endif
tok = strtok(str,delim);
while(tok != NULL) {
arrsz++;
// NOTE/BUG: this is incorrect -- it only adds a byte instead of another
// pointer (i.e. it doesn't allocate enough)
#if 0
arr = (char **)realloc(arr,(arrsz*sizeof(char *))+1);
#else
arr = (char **)realloc(arr,sizeof(char *) * (arrsz + 1));
#endif
#if 0
arr[arrsz-1] = malloc((sizeof(char)*strlen(tok))+1);
strcpy(arr[arrsz-1],tok);
#else
arr[arrsz-1] = strdup(tok);
#endif
// NOTE/BUG: this is wrong and leaks memory
#if 0
arr[arrsz]=malloc(1);
arr[arrsz]='\0';
#endif
tok = strtok(NULL,delim);
}
#if 1
arr[arrsz] = NULL;
#endif
return(arrsz);
}
But, as written, your function doesn't update caller's value of arr.
To fix your function, split would need arr to be defined as a "three star" pointer (e.g. char ***arr) which is considered cumbersome and very bad practice.
So, a better/simpler solution is to refactor the function and pass back arr as return (e.g. char **split(char *str,int *sizrtn):
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **split(char *s, int *arsiz);
int main(int argc, char* argv[])
{
int x;
int arrsz;
char str[]="aaa:bbb:ccc";
char **arr;
arrsz = 0;
arr = split(str,&arrsz);
for(x=0;x<arrsz;x++) {
printf("%s\n",arr[x]);
}
return 0;
}
/***********************************/
char **split(char *str, int *sizrtn)
{
int arrsz=0;
const char *delim = ":";
char *tok;
char **arr = NULL;
tok = strtok(str,delim);
while (tok != NULL) {
arrsz++;
arr = realloc(arr,sizeof(char *) * (arrsz + 1));
arr[arrsz - 1] = strdup(tok);
tok = strtok(NULL,delim);
}
if (arr == NULL)
arr = malloc(sizeof(*arr));
arr[arrsz] = NULL;
*sizrtn = arrsz;
return arr;
}
To modify an object in the caller's scope you must pass a pointer to the object - so you need one more level of indirection. There is also at least one semantic error in the implementation - assigning '\0' to the pointer returned by malloc(), will both invalidate the pointer and cause a memory leak.
Change split() prototype to:
int split( char* s, char*** arr ) ;
Then call it thus:
arrsz = split( str, &arr ) ;
And change the implementation:
int split( char* str, char*** arr )
{
int arrsz = 0 ;
char delim[2] = ":" ;
char* tok ;
*arr = malloc(sizeof(char**));
*arr[0] = malloc(1);
**arr[0] = '\0'; // <<< This is fixed too
tok = strtok( str, delim ) ;
while( tok != NULL )
{
arrsz++;
*arr = (char **)realloc(*arr,(arrsz*sizeof(char *))+1);
*arr[arrsz-1] = malloc((sizeof(char)*strlen(tok))+1);
strcpy(*arr[arrsz-1],tok);
*arr[arrsz]=malloc(1);
*arr[arrsz]='\0';
tok = strtok(NULL,delim);
}
return(arrsz);
}
There may be other errors I have not spotted, but that is fundamental. Best from hereon debugged using a debugger rather then Q&A.
the following proposed code:
cleanly compiles
performs the desired functionality
properly checks for errors from system functions
eliminates any need to use a *** parameter -- google three star programer as to why that is bad
does not include header files those contents are not used
and now, the proposed code:
//#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char ** split(char *str, size_t *arrsz);
int main( void )
{
size_t x;
size_t arrsz;
char str[]="aaa:bbb:ccc";
char **arr=split(str,&arrsz);
for(x=0;x<arrsz;x++)
{
printf("%s\n",arr[x]);
}
exit(0);
}
/***********************************/
char ** split(char *str, size_t *arrsz)
{
char **arr = NULL;
size_t count = 0;
char delim[2] = ":";
char *tok;
tok = strtok(str,delim);
while(tok != NULL)
{
count++;
char **temp = realloc(arr,(count*sizeof(char *)));
if( !temp )
{
perror( "malloc failed" );
// perform cleanup and
free( arr );
exit( EXIT_FAILURE );
}
arr = temp;
arr[count-1] = strdup( tok );
if( !arr[count-1] )
{
perror( "strdup failed" );
// perform cleanup and
free( arr );
exit( EXIT_FAILURE );
}
tok = strtok(NULL,delim);
}
*arrsz = count;
return( arr );
}
OP's code does not return the allocated memory assigned to arr
int split(char *str, char **arr) {
...
// Memory allocated and assigned to local `arr`
// Yet `arr` is not returned.
// Calling code never sees the result of this assignment.
arr = malloc(sizeof(char **));
...
return(arrsz);
}
Instead, I took a whole new approach to mimic split /PATTERN/,EXPR.
I really wanted to avoid all the ** and *** programming.
IMO, a split() should not change the expression so directly using strtok() is out. A common implementation of strtok() effectively does a strspn() and strcspsn(), so coding those directly avoids the strtok().
The below returns a string list type. Various other function signatures could be used, this return type seemed natural for OP's goal. Another solution might return a NULL terminated array of char * pointers.
When memory allocations fails, it is detected and then code calls TBD_Code();. Unclear how OP wants to handle that. Code could print a message and exit or attempt some recovery.
#include <stdlib.h>
#include <string.h>
typedef struct {
size_t n;
char **strings;
} string_list;
string_list split(const char *pattern, const char *expr) {
string_list list = { 0, NULL };
size_t length;
// Find length of initial matching characters
while ((length = strspn(expr, pattern)), expr[length]) {
// Skip leading characters from `expr` that match the pattern
expr += length;
// Find length of characters NOT from the pattern
length = strcspn(expr, pattern);
// Allocate for 1 more pointer
void *tmp = realloc(list.strings, sizeof *(list.strings) * (list.n + 1));
if (tmp == NULL) TBD_Code();
list.strings = tmp;
//Allocate for the token and save it
list.strings[list.n] = malloc(length + 1u);
if (list.strings[list.n] == 0) TBD_Code();
memcpy(list.strings[list.n], expr, length);
list.strings[list.n][length] = '\0';
// Advance
list.n++;
expr += length;
}
return list;
}
void string_list_free(string_list list) {
if (list.strings) {
for (size_t i = 0; i < list.n; i++) {
free(list.strings[i]);
}
free(list.strings);
}
}
Test code
#include <stdio.h>
void print_string_list(string_list list) {
for (size_t i = 0; i < list.n; i++) {
printf("%zu: <%s>\n", i, list.strings[i]);
}
string_list_free(list);
}
int main(void) {
print_string_list(split(":", "aaa:bbb:ccc"));
print_string_list(split(":b", "aaa:bbb:ccc"));
print_string_list(split("a:", "aaa:bbb:ccc"));
print_string_list(split(":c", "aaa:bbb:ccc"));
}
Output
0: <aaa>
1: <bbb>
2: <ccc>
0: <aaa>
1: <ccc>
0: <bbb>
1: <ccc>
0: <aaa>
1: <bbb>

Resources