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).
Related
I have been trying to convert a string in array of integers, floats and characters. While I could get it work for integers and floats, there is some problem for characters.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *s1;
int k, no=5;
char* variable = "R1,R2,R3,R4,R5";
void* value;
s1 = calloc(no,sizeof(char)*81);
for (k=0; k<no; k++) s1[k] = strdup(mchar);
ListChar(variable, s1, no, ",");
memcpy(value, s1, no*sizeof(char)*81);
free(s1);
int i;
for (i = 0; i < no; i++)
printf("%s", value[i]);
printf("\n");
return 0;
}
In the header file I have
#define mchar "A...(81times)"
Implementation:
int ListChar(char *buf, char *list, int maxloop, char* delim)
{
int n = 0;
char *s,*t;
s= strdup(buf);
t= strtok(s,delim);
while ( t && (n<maxloop))
{
if (list!=NULL) list[n] =strdup(t);
n++;
t=strtok(NULL,delim);
}
free(s);
return(n);
}
During the calloc memory assignment when I watch s1 its 0xsomeadress ""
After the for loop s1 becomes 0xsomeadress "Garbage value 81 times"
When s1 is assigned to list its still reads the same garbage value.
And when list [n] = strdup(t) list[0] reads the first block of garbage value like -21 '\221 ṗ'.
t is getting delimited correctly. I even tried initializing char *s1[81] = {"something"} and looping it on j but it wont work, same problem, and I need to free s1 at the end because this function runs for number of times. I did it for integers and floats by list[n]=atoi(t) it works fine. Can anyone suggest me something?
There seems to be a fundamental misunderstanding about how strings work. Your s1 clearly needs to be a char ** and the usage of strdup is incorrect. If s1 is of type char *, then s1[k] is of type char. But strdup returns a char *, so s1[k] = strdup ... is clearly an error which your compiler ought to warn you about. Perhaps you want something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void * xmalloc(size_t s);
void
ListChar(const char *buf, char **list, int maxloop, int delim)
{
char set[] = {delim, 0};
for( int n = 0; n < maxloop; n += 1 ){
size_t len = strcspn(buf, set);
list[n] = xmalloc(len + 1);
memcpy(list[n], buf, len);
buf += len + 1;
}
}
int
main(int argc, char **argv)
{
int delim = ',';
(void)argc; /* Suppress compiler warning */
while( *++argv ){
char **s1;
int k, num = 1;
char *input = *argv;
for( const char *p = input; *p; p += 1 ){
if( *p == delim ){
num += 1;
}
}
s1 = xmalloc(num * sizeof *s1);
ListChar(input, s1, num, delim);
for( int i = 0; i < num; i += 1 ){
printf("%s\n", s1[i]);
}
free(s1);
}
return 0;
}
void *
xmalloc(size_t s)
{
void *rv = malloc(s);
if( rv == NULL ){
perror("malloc");
exit(EXIT_FAILURE);
}
return rv;
}
Note that the above code scans each string twice, which is not ideal. Rather than scanning the string to find the number of delimiters and then parsing the string, it would be better to do both in one pass. But for the purposes of demonstrating how to break up the string, that seems like unnecessary complexity. (Though it's actually simpler, IMO)
I have function that finds all common chars and concatenates into one string.
char* commonString(char* p1,char* p2)
{
char* res = "";
for (int k=0;k<strlen(p1);k++)
{
for (int h=0;h<strlen(p2);h++)
{
if (p1[k] == p2[h])
{
strcat(res,&p1[k]);
}
}
}
return res;
}
What's wrong with it? Can you review and help to fix it?
Example of I/O:
Example 00
Input: "padinton" && "paqefwtdjetyiytjneytjoeyjnejeyj"
Output:
Return Value: "padinto"
P.S. I also have function that removes all duplicated chars except the first ocurrence of it from strings.
This function works after removing them
The two main problems in your code are that you are not allocating space for the resulting string and you are using the strcat function inappropriately. Below is a brief implementation of what you are trying to achieve.
#include <stdlib.h>
#include <string.h>
char *commonString(char* p1,char* p2)
{
const size_t lenp1 = strlen(p1);
char *res = malloc(lenp1 + 1);
size_t j = 0;
for (size_t i = 0; i < lenp1; ++i)
if (strchr(p2, p1[i]))
res[j++] = p1[i];
res[j] = 0;
return res;
}
Important Note: The pointer returned by the malloc function must be checked against NULL before being dereferenced. It is omitted here for brevity.
There are so many issues in your code.
Not allocating memory,
Modifying string literals
returning local variables
etc etc.
Your function is also inefficient. You call strlen on every iteration, call strcat (which is very expensive) just to add 1 char.
This function does what you want with or without the duplicates.
#include <stdlib.h>
#include <stdio.h>
char *mystrnchr(const char *str, const char ch, size_t size)
{
char *result = NULL;
while(size--)
{
if(*str == ch)
{
result = (char *)str;
break;
}
str++;
}
return result;
}
char *mystrchr(const char *str, const char ch)
{
char *result = NULL;
while(*str)
{
if(*str == ch)
{
result = (char *)str;
break;
}
str++;
}
return result;
}
char* commonString(char *buff, const char* p1, const char* p2, int duplicates)
{
size_t size = 0;
char p1c;
while((p1c = *p1++))
{
if(!duplicates)
{
if(mystrnchr(buff, p1c, size))
{
continue;
}
}
if(mystrchr(p2, p1c))
{
buff[size++] = p1c;
}
}
buff[size] = 0;
return buff;
}
int main()
{
char result[23];
char *str1 = "paaaadiiiiinton";
char *str2 = "paqefwtdjetyiytjneytjoeyjnejeyj";
printf("%s\n", commonString(result, str1, str2, 0));
printf("%s\n", commonString(result, str1, str2, 1));
}
You can experiment with it yourself here: https://godbolt.org/z/qMnsfa
Here's a solution along those lines:
#include <stdio.h>
#include <string.h>
#define MAX_LENGTH 512
void removeDup(char *result, char *string)
{
for (int i = 0; i < strlen(string); i++)
{
char C[2] = { string[i], '\0' };
if (strstr(result, C) == NULL)
strcat(result, C);
}
}
char *commonString(char *p1, char *p2)
{
char r[MAX_LENGTH] = { };
for (int i = 0; i < strlen(p1); i++)
for (int j = 0; j < strlen(p2); j++)
if (p1[i] == p2[j])
strcat(r, &p1[i]);
static char res[MAX_LENGTH] = { };
removeDup(res, r);
return res;
}
int main()
{
printf("%s\n", commonString("padinton", "paqefwtdjetyiytjneytjoeyjnejeyj"));
return 0;
}
$ cc string.c -o string && ./string
padinto
I am having trouble with this code I wrote for a generic binary search.
when trying to execute the search on an array of strings I noticed that the array of strings, passed to binSearch function does not contain the strings.
can someone suggest a hint?
Much appreciation
#define SIZE 100
typedef unsigned char BYTE
please consider this main:
void main()
{
char ** stringArr, stringToFind[SIZE];
int stringSize;
int res;
stringArr = getStringArr(&stringSize);
// string to find
gets(stringToFind);
res = stringBinSearch(stringArr, stringSize, stringToFind);
if (res == 1)
printf("The string %s was found\n", stringToFind);
else
printf("The string %s was not found\n", stringToFind);
}
char** getStringArr(int* stringSize)
{
int i, size, len;
char** arr;
char temp[SIZE];
scanf("%d", &size);
getchar();
arr = (char**)malloc(size * sizeof(char*));
checkAllocation(arr);
for (i = 0; i < size; i++)
{
gets(temp);
len = strlen(temp);
temp[len] = '\0';
arr[i] = (char*)malloc((len+1) * sizeof(char));
checkAllocation(arr[i]);
strcpy(arr[i], temp);
}
*stringSize = size;
return arr;
}
int stringBinSearch(char** stringArr, int stringSize, char* stringToFind)
{
return binSearch(stringArr, stringSize, sizeof(char*), stringToFind,compare2Strings);
}
int binSearch(void* Arr, int size, int ElemSize, void* Item, int(*compare)(void*, void*))
{
int left = 0, right = size - 1, place;
BOOL found = FALSE;
while (found == FALSE && left <= right)
{
place = (left + right) / 2;
if (compare(Item, (BYTE*)Arr + place*ElemSize) == 0)
found = TRUE;
else if (compare(Item, (BYTE*)Arr + place*ElemSize) < 0)
right = place - 1;
else
left = place + 1;
}
return found;
}
int compare2Strings(void* str1, void* str2)
{
char* elemA, *elemB;
elemA = (char*)str1;
elemB = (char*)str2;
return strcmp(elemA, elemB);
}
When you sort an array of int, the values passed are pointer to int, spelled int *. When you sort an array of strings (spelled char *), the values passed are pointer to string, spelled char **. You comparator is no use for comparing strings. As the inimitable BLUEPIXY said in their incredibly terse style — you need to modify the code to treat the passed void * arguments as char ** and not as char *.
With generic sorting, that's usually the end of the issue. With binary search, there's another issue that you run foul of. That is that the type of the item being searched for needs to be the same as the one of the entries in the array, so you need to pass a pointer to the item, not just the item.
So, adding material to allow the code to compile with minimal changes, changing from gets() to a cover for fgets() (because gets() is too dangerous to be used — ever! and programs that use it produce a warning when its used on macOS Sierra 10.12.5 — warning: this program uses gets(), which is unsafe.), and printing out the input data so you can see what's what, I end up with:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BOOL int
#define TRUE 1
#define FALSE 0
static inline char *sgets(size_t buflen, char *buffer)
{
char *result = fgets(buffer, buflen, stdin);
if (result)
buffer[strcspn(buffer, "\n")] = '\0';
return result;
}
#define checkAllocation(x) assert((x) != 0)
#define SIZE 100
typedef unsigned char BYTE;
char **getStringArr(int *stringSize);
int stringBinSearch(char **stringArr, int stringSize, char *stringToFind);
int binSearch(void *Arr, int size, int ElemSize, void *Item, int (*compare)(void *, void *));
int compare2Strings(void *str1, void *str2);
int main(void)
{
char **stringArr, stringToFind[SIZE];
int stringSize;
int res;
stringArr = getStringArr(&stringSize);
sgets(sizeof(stringToFind), stringToFind);
printf("Strings: %d\n", stringSize);
for (int i = 0; i < stringSize; i++)
printf("[%d] = [%s]\n", i, stringArr[i]);
printf("Search: [%s]\n", stringToFind);
res = stringBinSearch(stringArr, stringSize, stringToFind);
if (res == 1)
printf("The string %s was found\n", stringToFind);
else
printf("The string %s was not found\n", stringToFind);
return 0;
}
char **getStringArr(int *stringSize)
{
int i, size, len;
char **arr;
char temp[SIZE];
scanf("%d", &size);
getchar();
arr = (char **)malloc(size * sizeof(char *));
checkAllocation(arr);
for (i = 0; i < size; i++)
{
sgets(sizeof(temp), temp);
len = strlen(temp);
temp[len] = '\0';
arr[i] = (char *)malloc((len + 1) * sizeof(char));
checkAllocation(arr[i]);
strcpy(arr[i], temp);
}
*stringSize = size;
return arr;
}
int stringBinSearch(char **stringArr, int stringSize, char *stringToFind)
{
return binSearch(stringArr, stringSize, sizeof(char *), &stringToFind, compare2Strings);
}
int binSearch(void *Arr, int size, int ElemSize, void *Item, int (*compare)(void *, void *))
{
int left = 0, right = size - 1, place;
BOOL found = FALSE;
while (found == FALSE && left <= right)
{
place = (left + right) / 2;
if (compare(Item, (BYTE *)Arr + place * ElemSize) == 0)
found = TRUE;
else if (compare(Item, (BYTE *)Arr + place * ElemSize) < 0)
right = place - 1;
else
left = place + 1;
}
return found;
}
int compare2Strings(void *str1, void *str2)
{
char *elemA = *(char **)str1;
char *elemB = *(char **)str2;
return strcmp(elemA, elemB);
}
The key changes are:
compare2Strings() — compare the data in char ** values.
stringBinSearch() — pass the address of stringToFind.
AFAICR, any other change is cosmetic or 'infrastructure'.
Note that the return type of main() should be int — you can get away with void only on Windows where it is allowed.
Example run 1:
Data:
5
Antikythera
albatross
armadillo
pusillanimous
pygmalion
pygmalion
Output:
Strings: 5
[0] = [Antikythera]
[1] = [albatross]
[2] = [armadillo]
[3] = [pusillanimous]
[4] = [pygmalion]
Search: [pygmalion]
The string pygmalion was found
Example run 2:
Data file:
5
armadillo
pygmalion
Antikythera
pusillanimous
albatross
pygmalion
Output:
Strings: 5
[0] = [armadillo]
[1] = [pygmalion]
[2] = [Antikythera]
[3] = [pusillanimous]
[4] = [albatross]
Search: [pygmalion]
The string pygmalion was not found
The difference between the two sets of data is that in the first case, the strings are in correct sorted order — a prerequisite condition for successful (reliable) binary search — and in the second, the data is not in correct sorted order. (That said, I had one non-sorted order that still found 'pygmalion' — I used a different shuffle for the shown results. But the 'reliable' comment applies.)
Hello your problem is the way you send the array of strings to the binary search function. Because you need to pass an array of strings to it your Arr parameter must be void** not void*
int binSearch(void** Arr, int size, int ElemSize, void* Item, int(*compare)(void*, void*))
And in your function whenever you want to acces a string from your array it will be enough to acces it like: (char*) *(Arr+place*ElemSize)
Your approach which is to write a generic binary search is right. However attempting to return early slows down a binary search. It also means you can't use the C++ convention that "less than" is the comparison operator defined. Wait until left and right equal each other, and return that.
This is a simple program that should create a substring from a string, then it should return the substring as something that can be printed out.
It's actually an exercise and only the substring function can be changed. The problem is that I can't find a return type that doesn't spark all kinds of warnings and errors.
How should I change the return type?
static void panic(const char *serror)
{
printf("%s", serror);
exit(1);
}
static void *xmalloc(size_t size)
{
void *ptr;
if (size == 0)
panic("Size is 0!\n");
ptr = malloc(size);
if (!ptr)
panic("No mem left!\n");
return ptr;
}
static char *substring(const char *str, off_t pos, size_t len)
{
char out [len];
int index;
for(index = 0; index < (pos + len); index++)
{
if(index >= pos && index < (pos + len))
{
out[index - pos] = str[index];
}
}
return out;
}
int main(int argc, char **argv)
{
char *foo = "Nicht\n";
char *bar = substring(foo, 2, 3);
printf("%s", bar);
free(bar);
return 0;
}
You invoked two undefine behavior by
dereferencing a pointer bar that points at already vanished local variable.
passing a non-NULL pointer which doesn't point at buffer allocated via malloc(), calloc() or realloc().
Also note that
You have to terminate the string by adding null character.
Your loop is not efficient.
corrected code:
static char *substring(const char *str, off_t pos, size_t len)
{
char *out = xmalloc(len + 1);
int index;
for(index = pos; index < (pos + len); index++)
{
out[index - pos] = str[index];
}
out[len] = '\0';
return out;
}
i got a problem with my C code.
int split(char* source, char*** target, char* splitChar) {
int i;
int currentLength;
int splitCharPosition;
char* currentSubstring = source;
int splitCount = charcount(source, splitChar) + 1;
*target = (char**) malloc(splitCount * sizeof(char**));
for(i=0;i<splitCount;i++) {
splitCharPosition = indexOf(currentSubstring, splitChar);
substring(currentSubstring, target[i], 0, splitCharPosition);
currentLength = strlen(currentSubstring);
substring(currentSubstring, ¤tSubstring, splitCharPosition + 1, curr entLength-splitCharPosition);
}
return splitCount;
}
The problem is that if I use the Debugger, the pointer to splitChar is set to 0x0 after the first run of the for loop.
Does anybody know why it is set to 0x0?
EDIT:
int indexOf(char* source, char* template) {
int i;
int j;
int index;
for (i = 0; source[i]; i++) {
index = i;
for (j = 0; template[j]; j++) {
if (source[i + j] != template[j]) {
index = -1;
break;
}
}
if (index != -1) {
return index;
}
}
return -1;
}
EDIT2:
int charcount(char* source, const char* countChar) {
int i;
int count = 0;
for(i=0;source[i];i++) {
if(source[i] == countChar[0]) {
count++;
}
}
return count;
}
EDIT3:
char* substring(char* source, char** target, int start, int length) {
*target = (char*) malloc(length + 1);
strncpy(*target, source + start, length);
target[length] = '\0';
return *target;
}
EDIT4:
I just noticed that if I add
char* sndfpgjps = splitChar;
to my split() code it does not delete the reference. Anyone know why?
This line:-
substring(currentSubstring, ¤tSubstring, splitCharPosition + 1, curr entLength-splitCharPosition);
... will cause a memory leak, as well as being incredibly inefficient. The old substring is left dangling. and never freed.
It would be much better to write
currentSubString += splitCharPosition + 1;
I don't think that's the problem, but it's a problem.
Also, as you're using C library functions like strlen(), why aren't you using strtok or better yet, strtok_r?
I have some reservations about the code, but this works cleanly under valgrind (no leaks, no abuse). I've left the sub-functions largely unchanged except that constant strings are marked constant. The code in split() has been simplified. As I noted in a comment, I suggest writing the main split() function so that you have a local char **string_list; which you allocate and fill. Then, when you're about to return, you assign *target = string_list;. This will make it easier for you to understand what's going on. Triple indirection is nasty. You can justify it here (just), but minimize the time you spend working with triple pointers. The revision adopts that strategy.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern int split(const char *source, char ***target, const char *splitStr);
static int
indexOf(const char *source, const char *template)
{
int i;
int j;
int index;
for (i = 0; source[i]; i++)
{
index = i;
for (j = 0; template[j]; j++)
{
if (source[i + j] != template[j])
{
index = -1;
break;
}
}
if (index != -1)
return index;
}
return -1;
}
static int
charcount(const char *source, const char *countChar)
{
int count = 0;
for (int i = 0; source[i]; i++)
{
if (source[i] == countChar[0])
count++;
}
return count;
}
static char *
substring(const char *source, int start, int length)
{
char *target = (char *)malloc(length + 1);
if (target != 0)
{
memmove(target, source + start, length);
target[length] = '\0';
}
return target;
}
int
split(const char *source, char ***target, const char *splitStr)
{
int splitCount = charcount(source, splitStr) + 1;
char **result = (char **)malloc(splitCount * sizeof(*result));
if (result == 0)
return -1;
int splitLength = strlen(splitStr);
char **next = result;
const char *currentSubstring = source;
for (int i = 0; i < splitCount; i++)
{
int splitCharPosition = indexOf(currentSubstring, splitStr);
if (splitCharPosition < 0)
break;
*next++ = substring(currentSubstring, 0, splitCharPosition);
currentSubstring += splitCharPosition + splitLength;
}
*next++ = substring(currentSubstring, 0, strlen(currentSubstring));
*target = result;
return (next - result); /* Actual number of strings */
}
static void print_list(int nstrings, char **strings)
{
for (int i = 0; i < nstrings; i++)
{
if (strings[i] != 0)
printf("%d: <<%s>>\n", i, strings[i]);
}
}
static void free_list(int nstrings, char **strings)
{
for (int i = 0; i < nstrings; i++)
free(strings[i]);
free(strings);
}
int main(void)
{
const char source[] = "This is a string; it is really!";
char **strings;
int nstrings;
nstrings = split(source, &strings, " ");
printf("Splitting: <<%s>> on <<%s>>\n", source, " ");
print_list(nstrings, strings);
free_list(nstrings, strings);
nstrings = split(source, &strings, "is");
printf("Splitting: <<%s>> on <<%s>>\n", source, "is");
print_list(nstrings, strings);
free_list(nstrings, strings);
return 0;
}
Note that in the second example, charcount() returns 6 but there are only 4 strings. This caused a late adjustment to the source code. (You could realloc() the result so it is exactly the right size, but it probably isn't worth worrying about unless the discrepancy is really marked — say 'more than 10 entries'.) The error handling is not perfect; it doesn't access invalid memory after failure to allocate, but it doesn't stop trying to allocate, either. Nor does it report failures to allocate individual strings — it does for failure to allocate the array of pointers.
I'd probably avoid the triple pointer by creating a structure:
typedef struct StringList
{
size_t nstrings;
char **strings;
} StringList;
You can then pass a pointer to one of these into split(), and into the utility functions such as free_list() and print_list(). The free_list() function would then modify the structure so that both elements are zeroed after the data pointed at by the structure is freed.
I'd also be tempted to use a different implementation of indexOf():
int indexOf(const char *haystack, const char *needle)
{
const char *pos = strstr(haystack, needle);
if (pos != 0)
return (pos - haystack);
return -1;
}
I do not know what substring does, nor what signature it has, but in the line
substring(currentSubstring, target[i], 0, splitCharPosition);
target[i] is only defined for i==0. I believe you wanted to write
substring(currentSubstring, (*target)[i], 0, splitCharPosition);
See if your debugger also supports data breakpoints, i.e. break if some place in memory is modified. Then place one at the actual address of splitChar, and another at the address it points to. (Since you didn't specify whether the pointer is null or points to nil.) See where it breaks. It may be that it is a completely unrelated place; that would indicate a buffer overflow.
Also, you could make at least splitChar a pointer to const. You don't actually want to modify it, right? Better idea, make it a char, not a pointer, since its name suggests that there is only one character on which you split, not a string.
The first call to substring does not look correct:
substring(currentSubstring, target[i], 0, splitCharPosition);
I suspect it should be something like the following where it indexes the actual memory that was allocated:
substring(currentSubstring, &((*target)[i]), 0, splitCharPosition);
You first need to get the value that target points at (*target) and then index off of that and pass the address of that array location.