I'm trying to write a program that displays the longest common prefix using the divide and conquer method. My code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
const char *lcpUtil(char str1[], char str2[])
{
char *result = NULL;
result = (char *)malloc(sizeof(char) * 100);
int n1 = strlen(str1), n2 = strlen(str2);
for(int i = 0, j = 0; i <= n1-1 && j <= n2-1; i++, j++)
{
if(str1[i] != str2[j])
break;
strncat(result, &str1[i], 1); // append the prefix to the result string
}
return (result);
}
const char *lcp(char **str, int l, int r)
{
char str1[100], str2[100];
if(l == r)
{
return (str[l]);
}
if (l < r)
{
int m = (l + r)/2;
strcpy(str1, lcp(str, l, r));
strcpy(str2, lcp(str, m+1, r));
}
return (lcpUtil(str1, str2));
}
int main(int argc, char **argv)
{
char *arr[4] = {"apple", "application", "april", "apartment"}; // ap
int n = 4;
char prefix[100];
strcpy(prefix, lcp(arr, 0 , n-1));
if(strlen(prefix))
{
printf("The longest common prefix: %s\n", prefix);
}
else
printf("There is no common prefix");
return 0;
}
If I run this, a get a segmentation fault, debugging with gdb says:
Program received signal SIGSEGV, Segmentation fault.
0x00005555555552b7 in lcp (str=<error reading variable: Cannot access memory at address 0x7fffff7fefa8>, l=<error reading variable: Cannot access memory at address 0x7fffff7fefa4>,
r=<error reading variable: Cannot access memory at address 0x7fffff7fefa0>) at lab11.c:23
#1 0x0000555555555325 in lcp (str=0x7fffffffde40, l=0, r=3) at lab11.c:30
I know I didn't free the memory allocated with malloc, but it should still be working. I'm not sure why this is happening. Any ideas?
An infinite recursion is invoked because the function lcp(str, l, r) calls lcp(str, l, r).
Also undefined behavior is invoked by using contents of uninitialized buffer allocated via malloc() and assigned to result in strncmp() called from lcpUtil.
#include <string.h> /* needed for size_t */
size_t lcp_len(char *left, char *right)
{
/* if the strings differ we are done */
if (*left != *right) return 0;
/* if we reached the end of the string(s) we are done) */
if ( !*left ) return 0;
/* add 1 to the length and compare the next two characters, recursively */
return 1+lcp_len(left+1, right+1);
}
size_t lcp_fetch(char *dest, char *left, char *right)
{
if (*left != *right) { *dest=0; return 0; }
if ( !*left ) { *dest=0; return 0; }
*dest = *left;
return 1+lcp_fetch(dest+1, left+1, right+1);
}
Now let's call it:
#include <stdio.h>
int main(int argc, char **argv)
{
size_t result_len;
char result[100];
if (argc < 3) return 1;
result_len = lcp_fetch(result, argv[1], argv[2] );
printf("%zu:%s\n", result_len, result );
return 0;
}
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 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).
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
For example I have two strings:
lihuayu zhangxuehui sunyunlei guolei fuwenxia
lihuayu lixin fuwenxia zhangxuehui
And I will get
sunyunlei guolei lixin
I wrote following code
#include<stdio.h>
#include<string.h>
#define STRINGSIZE 64
void main()
{
char *line1 = NULL;
char *line2 = NULL;
size_t size1;
size_t size2;
getline(&line1, &size1, stdin);
getline(&line2, &size2, stdin);
char* spilted1 = strtok(line1, " ");
while (spilted1 != NULL){
if (strstr(line2, spilted1) == NULL){
printf("%s", spilted1);
}
spilted1 = strtok(NULL, " ");
}
}
But it's obviously wrong in that I can't get those distinct words in string2.
I know how to do it in Python but have no idea how to do it in C.
Here's one way:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAX_WORDS = 64 };
static int split_words(char *buffer, char **words, int max_words)
{
char *token;
char *next = buffer;
int num_words = 0;
while ((token = strtok(next, " \n")) != 0 && num_words < max_words)
{
words[num_words++] = token;
next = NULL;
}
return num_words;
}
static int word_in_list(char *word, char **list, int list_size)
{
for (int i = 0; i < list_size; i++)
{
if (strcmp(word, list[i]) == 0)
return 1;
}
return 0;
}
/* Print words in list w1 that do not appear in list w2 */
static void print_unique(char **w1, int n1, char **w2, int n2)
{
for (int i = 0; i < n1; i++)
{
if (!word_in_list(w1[i], w2, n2))
printf("[%s]\n", w1[i]);
}
}
int main(void)
{
char *line1 = NULL;
char *line2 = NULL;
size_t size1 = 0;
size_t size2 = 0;
if (getline(&line1, &size1, stdin) > 0 &&
getline(&line2, &size2, stdin) > 0)
{
char *w1[MAX_WORDS];
char *w2[MAX_WORDS];
int n1 = split_words(line1, w1, MAX_WORDS);
int n2 = split_words(line2, w2, MAX_WORDS);
print_unique(w1, n1, w2, n2);
print_unique(w2, n2, w1, n1);
}
free(line1);
free(line2);
return 0;
}
/*
You'll need two
arrays of char pointers, one for each line of input. You'll split the
first line into the first array, and the second line into the second
array. Then you'll go through the two arrays of pointers, comparing
strings and counting only those that do not match any of the entries in
the other array. (What do you do if one input line itself contains
repeats โ The Lion, the Witch, and the Wardrobe for example? Also, do
you need to treat The as the same as the in that example?)
You can use strtok_r() or strtok_s() if you have them available; at a
pinch, you could use strtok(), but it is dangerous to use that in
library code. And you'll need to use strcmp() to compare the strings
โ plus macros/functions from <ctype.h> to handle case-conversion if
that's appropriate.
Also note that strtok() is destructive. If you've split string 1 with
it, you can't then search in string 1 when you split string 2. Also
note that strstr("then came a deluge", "the") matches, even though most
people would not regard the haystack string as containing the needle
word the.
*/
The algorithm used is quadratic in the number of words (it runs in O(N2) time); it compares each unique word in one list with every word in the other list. You can do things like sort the lists and eliminate duplicates (in O(N.log N) time), and then step through the two lists to find unique words in linear time. Being quadratic won't matter for tens of words, and probably not for hundreds of words, but would probably begin to matter after that.
Compilation:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
> -Wold-style-definition -Werror uniq_words.c -o uniq_words
$
Example run:
$ cat data
lihuayu zhangxuehui sunyunlei guolei fuwenxia
lihuayu lixin fuwenxia zhangxuehui
$ uniq_words < data
[sunyunlei]
[guolei]
[lixin]
$
The square brackets around the data reassure me that the strings contain what I think they should contain.
Like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **split(const char *str, const char *delimiter, size_t *len);
int cmp(const void *a, const void *b);
void find_diff(char **a1, char **a2);
void drop(char **a);
int main(void){
char *line1 = NULL, *line2 = NULL;
size_t size1 = 0, size2 = 0;
getline(&line1, &size1, stdin);
getline(&line2, &size2, stdin);
//(1)split
size_t len1, len2;
char **array1 = split(line1, " \t\n", &len1);
char **array2 = split(line2, " \t\n", &len2);
//(2)sort
qsort(array1, len1, sizeof(*array1), cmp);
qsort(array2, len2, sizeof(*array2), cmp);
//(3)compare
find_diff(array1, array2);
drop(array1);drop(array2);
free(line1);free(line2);
return 0;
}
char **split(const char *str, const char *delimiter, size_t *len){
char *text, *p, *first, **array, **ret;
size_t c;
*len = 0;
text = strdup(str);//make clone
if(text == NULL) return NULL;
for(c = 0, p = text; p = strtok(p, delimiter); p = NULL)
++c;//count elements
ret = malloc(sizeof(char*)*(c+1));//+1 for NULL
if(ret==NULL){
free(text);
return NULL;
}
strcpy(text, str);//restore
array=ret;
for(p = text; p = strtok(p, delimiter); p = NULL)
*array++ = strdup(p);
*array = NULL;
*len = c;
free(text);
return ret;
}
int cmp(const void *a, const void *b){
return strcmp(*(char **)a, *(char **)b);
}
void find_diff(char **a1, char **a2){//arguments has been sorted
while(*a1 || *a2){
if(*a1 && a1[1] && !strcmp(*a1, a1[1])){
++a1;//distinct
continue;
}
if(*a2 && a2[1] && !strcmp(*a2, a2[1])){
++a2;
continue;
}
if(*a1 == NULL){
puts(*a2++);
} else if(*a2 == NULL){
puts(*a1++);
} else {
int result;
if((result=strcmp(*a1, *a2)) < 0){
puts(*a1++);
} else if(result > 0){
puts(*a2++);
} else {
++a1;
++a2;
}
}
}
}
void drop(char **a){
char **tmp = a;
while(*a)
free(*a++);
free(tmp);
}
I'm not sure why my program will not compile right on vi. it only prints the first occurrence of the function show(var) and then exits and lists a segmentation fault and core dumped, however, it compiled without any errors on emacs and displayed all the strings after being quicksorted.
The program is supposed to read in data from a text file that I have stored in the same directory, and quicksort it using one of the 2 compare functions (which don't have to be meaningful, they just need to be functional) and then prints it out to the screen.
Thanks in advance.
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
void show(void *array[]){
int i = 0;
while(array[i]!=NULL){
printf("String %d : %s\n",i, array[i]);
i++;
}
printf("\n");
}
void *readData(void * lineArray[]){
static const char filename[] = "sampledata.txt";
FILE *file = fopen ( filename, "r" );
if ( file != NULL )
{
int i ;
char line [ 128 ]; /* or other suitable maximum line size */
void *lineadrs ;
i = 0;
lineadrs = malloc(sizeof(void) * 1024);
while ( fgets ( lineadrs, sizeof line, file ) != NULL ) /* read a line */
{
lineArray[i] = lineadrs;
lineadrs = malloc(sizeof(void) * 1024);
i++;
}
fclose ( file );
}
else {
perror ( filename );
return 0;
}
return lineArray ;
}
void swap(void *v[], int i, int j)
{
void *temp;
temp = v[i];
v[i] = v[j];
v[j]=temp;
}
//normal compare
int cmp1 (void *first_arg, void *second_arg)
{
if ( *(char*)first_arg < *(char*)second_arg )
{
return -1;
}
if ( *(char*)first_arg == *(char*)second_arg )
{
return 0;
}
else {
return 1;
}
}
//reverse the compare
int cmp2 (void * a, void * b)
{
char *ia = (char *)a; // casting pointer types
char *ib = (char *)b;
return *ib - *ia;
//return ( *(int *)b + *(int *)a );
}
void QSort(void *v[],int left, int right, int (*compare)(void *first, void *second))
{
int i, last;
void swap (void *v[],int ,int);
if(left >= right){
return;
}
swap(v,left,(left+right)/2);
last=left;
for(i=left+1;i<=right; i++){
if((*compare)(v[i],v[left])<0){
swap(v,++last,i);
}
}
swap(v,left,last);
QSort(v,left,last-1,compare);
QSort(v,last+1,right,compare);
}
int main(){
void * var[6];
readData(var);
printf("Original String:\n");
show(var);
QSort(var,0,4,cmp1);
printf("After cmp 1 which compares alphabetically.\n");
show(var);
QSort(var,0,4,cmp2);
printf("After cmp 2 which compares reverse alphabetically.\n");
show(var);
return 0;
}
The list of things wrong in this code is almost too numerous to mention
the line array is fixed. it should be dynamic. reading more than 4 lines of text will invoke undefined behavior by exceeding your input array length
the comparators are wrong for string content.
the memory leaks are numerous.
The code below is, I believe, what you're trying to do. I sincerely hope you take the time to learn from it. There are still several things that should be done, but the difference is night and day already. And I should warn you I wrote this online and have given no test-time to it, but it should be correct. Since I have no example data from you, this is the extent of what I can do. I wish you the best of luck.
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
// read data from a named file one line at a time, storing each
// in a ever-expanding line array. The return result is the
// number of lines allocated. The resulting line array is passed
// as an output parameter
int readData(const char filename[], void ***results)
{
// default answer: no lines, zero-length
void **lines = NULL;
int i=0;
FILE *file = fopen ( filename, "r" );
if ( file != NULL )
{
char line [ 128 ];
while ( fgets ( line, sizeof line, file ) != NULL )
{
// trim the newline from line buffer
size_t slen = strlen(line);
if (slen > 0 && line[slen-1] == '\n')
line[--slen] = 0;
// resize lines array
void **new_lines = realloc(lines, (i+1)*sizeof(*new_lines));
if (new_lines == NULL)
{
perror("Failed to realloc lines array.");
exit(EXIT_FAILURE);
}
// save new line entry, terminate with NULL;
lines = new_lines;
lines[i++] = strdup(line);
}
fclose ( file );
}
else
{
perror(filename);
exit(EXIT_FAILURE);
}
// setup output result and return value
*results = lines;
return i;
}
// display an array of a specified length
void show(void *array[], int len)
{
int i=0;
for (; i<len; ++i)
printf("String %d : %s\n", i, array[i]);
printf("\n");
}
//normal compare
int cmp1 (void *first_arg, void *second_arg)
{
return strcmp((const char*)first_arg, (const char*)second_arg);
}
//reverse the compare
int cmp2 (void *first_arg, void *second_arg)
{
return strcmp((const char*)second_arg, (const char*)first_arg);
}
// swap to void* by address
void swap(void **lhs, void **rhs)
{
void *tmp = *lhs;
*lhs = *rhs;
*rhs = tmp;
}
// the simplest quicksort I can fathom
void QSort(void *v[], int len, int (*compare)(void*, void*))
{
if (len < 2)
return;
// swap random element to last slot
swap(v+(rand() % len), v+(len-1));
// partition around the pivot value
int pvt=0,i;
for (i=0; i<len; ++i)
{
if (compare(v[i], v[len-1]) < 0)
swap(v+i, v+pvt++);
}
// swap pivot into place
swap(v+pvt, v+(len-1));
// recurse. note the pivot slot is skipped.
QSort(v, pvt++, compare);
QSort(v+pvt, len-pvt, compare);
}
int main()
{
static const char filename[] = "sampledata.txt";
srand((unsigned)time(NULL));
void **var = NULL;
int len = readData(filename, &var);
if (len > 0)
{
printf("Original String:\n");
show(var, len);
QSort(var, len, cmp1);
printf("After cmp 1 which compares alphabetically.\n");
show(var, len);
QSort(var, len, cmp2);
printf("After cmp 2 which compares reverse alphabetically.\n");
show(var, len);
// release lines when finished
while (len-- != 0)
free(var[len]);
free(var);
}
return 0;
}