C: strcmp error while finding longest repeated substring - c

I'm trying to create a program which returns the Longest repeated substring. I've almost got the solution, but for some reason my strcmp gives an error when he is busy to find the LRS. Could someone explain me why there is an error and how I solve this?
The code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NSTRINGS 4
char* searchLongestRepeatedSubstring(char* string);
char** makeSuffixArray(char* string);
void freeSuffixArray(char** suffixArray);
int cmp(const void*a, const void* b);
/* do not change this code */
int main(void)
{
char* strings[NSTRINGS] = {
"bananas",
"ask not what your country can do for you, but what you can do for your country",
"main",
"" };
char* result;
for (int i = 0; i < NSTRINGS; ++i)
{
result = searchLongestRepeatedSubstring(strings[i]);
if (result != NULL)
{
/* write out LRS */
printf("%s: \"%s\"\n", strings[i], result);
/* free() the result */
free(result);
result = NULL;
}
else
printf("Geen longest repeated substring.\n");
}
return 0;
}
/**
* Finds the LRS from a string using the function makeSuffixArray
*
* #param the given string
* #return the longest repeated substring
*/
char* searchLongestRepeatedSubstring(char* string)
{
char **p;
p = makeSuffixArray(string);
size_t length = strlen(string);
int max_sz = 0;
char max_word;
int curr_sz = 0;
int curr_word;
char* word1;
char* word2;
char s1, s2;
size_t length1;
size_t length2;
for (size_t i = 0; i < length; i++)
{
for (size_t j = i + 1; j < length; j++)
{
word1 = p[i];
word2 = p[j];
length1 = strlen(word1);
length2 = strlen(word1);
for (size_t x = 0; x < length1; x++)
{
s1 = word1[x];
for (size_t y = 0; y < length2; y++)
{
s2 = word2[y];
if (strcmp(s1, s2) == 0) {
curr_sz++;
strcat(curr_word, s1);
x++;
}
else
break;
}
}
if (curr_sz > max_sz) {
max_sz = curr_sz;
curr_sz = 0;
max_word = curr_word;
curr_word = "";
}
else {
curr_sz = 0;
curr_word = "";
}
}
}
return max_word;
}
/**
* Creates the suffix array of the given string
*
* #param the given string
* #return the suffix array
*/
char** makeSuffixArray(char* string)
{
size_t length = strlen(string);
char **p = (char**)malloc(length * sizeof(char*));
for (size_t i = 0; i < strlen(string); i++)
{
p[i] = &string[i];
puts(p[i]);
}
qsort(p, length, sizeof(char*), cmp);
return p;
}
int cmp(const void* a, const void* b)
{
char ** p = (char**)a;
char ** t = (char**)b;
return strcmp(*p, *t);
}
/**
* free() the memory allocated for the suffix array
*
* #param the given suffix array
*/
void freeSuffixArray(char** suffixArray)
{
free(suffixArray);
}

In your function char* searchLongestRepeatedSubstring-
if (strcmp(s1, s2) == 0) {
s1 and s2 are both char variables , and you pass them to strcmp which expects const char * as arguments , therefore, your compiler complaints .
You can compare them like this-
if(s1==s2)
Also this statement in same if block -
strcat(curr_word, s1);
instead you can do this -
size_t len=strlen(curr_word);
curr_word[len]=s1; // make sure curr_word is large enough
curr_word[len+1]='\0';

Related

Shortest and longest string in array

I have an assignment, I need to create a method that receives (char * * ch,site_t size).
ch is an array of addresses to char arrays, I need to make it so that the shortest element will be first (address and place) and longest will be last one (address and place). Here is what made so far although it doesn't work on array size 5 (tried only on size 4):
(Note: I used char * arr[] but I planned to changing it once I get the program working with this type of variable.)
void AdressSwitcher(char * arr[],size_t size){
char*shortest=arr[0];
char*shortestFollower=NULL;
char*longest=arr[1];
char*longestFollower=NULL;
for(size_t i=0;i<size;i++){
if(strlen(arr[i])<(strlen(shortest))){
shortest=arr[i];
arr[i]=arr[0];
}
arr[0]=shortest;
}
for(size_t i=1;i<size;i++){
if(strlen(arr[i])>(strlen(longest))){
longest=arr[i];
arr[i]=arr[size-1];
}
arr[size-1]=longest;
// }
for(size_t i=0;i<size;i++){
printf("%s %p", arr[i],arr[i]);
printf("\n");
}
}
Welcome to SO. This problem can be easily solved with the following method:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *escape_double_quotes(const char *s)
{
char *result = calloc((strlen(s) * 2) + 1, sizeof(char));
size_t resultIndex = 0;
for (size_t i = 0; s[i] != '\0'; i++)
{
if (s[i] == '"')
{
result[resultIndex] = '\\';
resultIndex++;
result[resultIndex] = '"';
resultIndex++;
continue;
}
result[resultIndex] = s[i];
resultIndex++;
}
return result;
}
void longestAndShortest(char **arr, const size_t size)
{
if (size <= 1)
return;
size_t shortIndex = 0;
size_t shortSize = strlen(arr[0]);
size_t longIndex;
size_t longSize = 0;
for (size_t i = 0; i < size; i++)
{
size_t b = strlen(arr[i]);
if (b > longSize)
{
longIndex = i;
longSize = b;
}
if (b < shortSize)
{
shortIndex = i;
shortSize = b;
}
}
printf("The shortest size of the array was %lu, the index of that being %lu and the contents of that being \"%s\".\n", shortSize, shortIndex, escape_double_quotes(arr[shortIndex]));
printf("The longest size of the array was %lu, the index of that being %lu and the contents of that being \"%s\".\n", longSize, longIndex, escape_double_quotes(arr[longIndex]));
return;
}
int main(void)
{
char **array = malloc(sizeof(char*) * 8);
array[0] = malloc(128);
strcpy(array[0], "World!");
array[1] = malloc(128);
strcpy(array[1], "Hello");
longestAndShortest(array, 2);
for (size_t i = 0; i < 2; i++)
free(array[i]);
free(array);
return 0;
}
From here you should be able to complete the rest.
Please work on writing more tidy code. Your future self will thank you.
Have a great day!

How to order split command line arguments in lexicographical order using a function?

I'm working on a program that takes command line arguments and splits them in half and then orders them in lexicographical order.
For example:
hello, world!
would turn into:
he
ld!
llo
wor
I have a main method that reads through the arguments, a function that splits the arguments, and finally a function that is supposed to order the halves in lexicographical order. I can't get this to run properly because of argument type errors in the lexicographicalSort method and an incompatible pointer type in the main method. I'm having issues to correct these syntax errors, how exactly would I correct them? Also, is there anything here that would cause logical errors? This is what I have so far:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int splitString(char arg[], int n)
{
int len = strlen(arg);
int len1 = len/2;
int len2 = len - len1; // Compensate for possible odd length
char *s1 = malloc(len1 + 1); // one for the null terminator
memcpy(s1, arg, len1);
s1[len1] = '\0';
char *s2 = malloc(len2 + 1); // one for the null terminator
memcpy(s2, arg + len1, len2);
s2[len2] = '\0';
printf("%s\n", s1);
printf("%s\n", s2);
free(s1);
free(s2);
return 0;
}
int lexicographicalSort(char *arg[], int n)
{
char temp[50];
for(int i = 0; i < n; ++i)
scanf("%s[^\n]",arg[i]);
for(int i = 0; i < n - 1; ++i)
for(int j = i + 1; j < n ; ++j)
{
if(strcmp(arg[i], arg[j]) > 0)
{
strcpy(temp, arg[i]);
strcpy(arg[i], arg[j]);
strcpy(arg[j], temp);
}
}
for(int i = 0; i < n; ++i)
{
puts(arg[i]);
}
return 0;
}
int main(int argc, char *argv[])
{
if (argc > 1)
{
for (int i = 1; i < argc; i++)
{
int j = 1;
int k = strlen(argv[i]);
splitString(argv[i], j);
lexicographicalSort(argv[i], j);
}
}
}
Basic scheme is simple. Make an array of tuples {start_pointer, length}. Do some programming on args to split the args. Fill in the array as appropriate. Make sorting with qsort, or any other sort of your choise.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
char *s = "hello, world! . hello.....";
char *pc;
int i, n, nargs;
struct pp{
char *p;
int l;
};
struct pp args[10], hargs[20];
struct pp *pargs;
int cmp(const void * v0, const void * v1) {
struct pp *pv0 = v0, *pv1 = v1;
return strncmp(pv0->p, pv1->p, pv0->l);
}
int main(void)
{
for(pc = s, i = 0; *pc; ++i){
sscanf(pc, "%*[^ ]%n", &n);
if(n > 0){
args[i].p = pc;
args[i].l = n;
}
for(pc += n, n = 0; isspace(*pc); ++pc);
}
for(nargs = i, i = 0; i < nargs; ++i)
printf("%d arg is: %.*s\n", i, args[i].l, args[i].p);
putchar('\n');
for(i = 0, pargs = hargs; i < nargs; ++i){
if(args[i].l == 1){
pargs->p = args[i].p;
pargs->l = 1;
pargs = pargs + 1;
}else {
pargs->p = args[i].p;
pargs->l = args[i].l / 2;
pargs = pargs + 1;
pargs->p = args[i].p + args[i].l / 2;
pargs->l = args[i].l - args[i].l / 2;
pargs = pargs + 1;
}
}
putchar('\n');
for(nargs = pargs - hargs, i = 0; i < nargs; ++i)
printf("%d arg is: %.*s\n", i, hargs[i].l, hargs[i].p);
qsort(hargs, nargs, sizeof(struct pp), cmp);
putchar('\n');
for(i = 0; i < nargs; ++i)
printf("%d arg is: %.*s\n", i, hargs[i].l, hargs[i].p);
return 0;
}
https://rextester.com/GSH22767
Upon splitting a C string, one needs one extra char to store extra null-terminator. There is one answer that bypasses this by storing the length. For completeness, this is closer to your original intention: allocating enough space to copy the programmes arguments. It probably works slower, but one is free to use the strings elsewhere in the programme.
#include <stdlib.h> /* malloc free EXIT qsort */
#include <stdio.h> /* fprintf */
#include <string.h> /* strlen memcpy */
#include <errno.h> /* errno */
static int strcompare(const void *a, const void *b) {
const char *a_str = *(const char *const*)a, *b_str = *(const char *const*)b;
return strcmp(a_str, b_str);
}
int main(int argc, char **argv) {
char *spacev = 0, **listv = 0;
size_t spacec = 0, listc = 0;
int is_done = 0;
do { /* "Try." */
int i;
char *sv;
size_t j;
/* This requires argc > 1. */
if(argc <= 1) { errno = EDOM; break; }
/* Allocate maximum space. */
for(i = 1; i < argc; i++) spacec += strlen(argv[i]) + 2;
if(!(spacev = malloc(spacec)) || !(listv = malloc(argc * 2))) break;
sv = spacev;
/* Copy and split the arguments. */
for(i = 1; i < argc; i++) {
const char *const word = argv[i];
const size_t word_len = strlen(word),
w0_len = word_len / 2, w1_len = word_len - w0_len;
if(w0_len) {
listv[listc++] = sv;
memcpy(sv, word, w0_len);
sv += w0_len;
*(sv++) = '\0';
}
if(w1_len) {
listv[listc++] = sv;
memcpy(sv, word + w0_len, w1_len);
sv += w1_len;
*(sv++) = '\0';
}
}
/* Sort. */
qsort(listv, listc, sizeof listv, &strcompare);
for(j = 0; j < listc; j++) printf("%s\n", listv[j]);
is_done = 1;
} while(0); if(!is_done) {
perror("split");
} {
free(spacev);
free(listv);
}
return is_done ? EXIT_SUCCESS : EXIT_FAILURE;
}
It is simpler than your original; instead of allocating each string individually, it counts the maximum number of chars needed (plus two for two null terminators) and allocates the block all at once (space.) The pointers to the new list also need allocating, the maximum is 2 * argc. Once you copy and modify the argument list, one has an actual array of strings that one can qsort.

Reversing String in C for loop error

I have an array of strings and am trying to reverse each string in the array to see if that string is a palindrome. I am using a for loop to increment an int i (the index). However after the I call the reverse function, the value of i becomes some really large number and I cant figure out why this is happening.
#include <stdio.h>
#include <string.h>
void revString(char *dest, const char *source);
int main() {
const char *strs[] = {
"racecar",
"radar",
"hello",
"world"
};
int i;
char res[] = "";
for (i = 0; i < strlen(*strs); i++) {
printf("i is %d\n", i);
revString(&res[0], strs[i]); //reversing string
printf("i is now %d\n", i);
//comparing string and reversed string
if (strcmp(res, strs[i]) == 0) {
printf("Is a palindrome");
} else {
printf("Not a palindrome");
}
}
return 0;
}
void revString(char *dest, const char *source) {
printf("%s\n", source);
int len = strlen(source);
printf("%d\n", len);
const char *p;
char s;
for (p = (source + (len - 1)); p >= source; p--) {
s = *p;
*(dest) = s;
dest += 1;
}
*dest = '\0';
}
This is the output showing the value of i before and after the revString function is called.
i is 0
i is now 1667588961
Illegal instruction: 4
There are multiple problems in your code:
You pass a destination array char res[] = ""; that is much too small for the strings you want to reverse. It's size is 1. This causes buffer overflow, resulting in undefined behavior.
Use char res[20]; instead.
You enumerate the array of string with an incorrect upper bound. Use this instead:
for (i = 0; i < sizeof(strs) / sizeof(*strs); i++)
The termination test for the loop in revString() is incorrect too: decrementing p when is equal to source has undefined behavior, although it is unlikely to have an consequences. You can simplify this function this way:
void revString(char *dest, const char *source) {
size_t len = strlen(source);
for (size_t i = 0; i < len; i++) {
dest[i] = source[len - i - 1];
}
dest[len] = '\0';
}
Here is the resulting code:
#include <stdio.h>
#include <string.h>
void revString(char *dest, const char *source) {
size_t len = strlen(source);
for (size_t i = 0; i < len; i++) {
dest[i] = source[len - i - 1];
}
dest[len] = '\0';
}
int main(void) {
const char *strs[] = { "racecar", "radar", "hello", "world" };
char res[20];
for (size_t i = 0; i < sizeof(strs) / sizeof(*strs); i++) {
revString(res, strs[i]);
//comparing string and reversed string
if (strcmp(res, strs[i]) == 0) {
printf("Is a palindrome\n");
} else {
printf("Not a palindrome\n");
}
}
return 0;
}
Here is Final Code with some change
#include <stdio.h>
#include <string.h>
void revString(char* dest, const char* source);
int main(){
const char* strs[] = {
"racecar",
"radar",
"hello",
"world"
};
static int i;
char res[] = "";
int length = (int) sizeof(strs)/sizeof(char*);
for(i = 0; i < length; i++)
{
printf("i is %d\n", i);
revString(&res[0], strs[i]); //reversing string
printf("i is now %d\n", i);
//comparing string and reversed string
if(strcmp(res, strs[i]) == 0){
printf("Is a palindrome");
}else{
printf("Not a palindrome");
}
}
return 0;
}
void revString(char* dest, const char* source){
printf("%s\n", source);
int len = (int) strlen(source);
printf("%d\n", len);
const char* p;
char s;
for(p = (source + (len - 1)); p >= source; p--){
s = *p;
*(dest) = s;
dest += 1;
}
*dest = '\0';
}
Change 1 :-
int i; to static int i; (Reason:- i is local variable you are calling
function so when function call the value of i will remove and after
that it will assign garbage value.)
change 2 :-
strlen(*strs) to length of array (because strlen(*strs) will give the
length of first string)

how to create a string from an array of strings C

I am learning about arrays and was wondering if someone can help me out. I have an array of strings and need to create a new string which is a concatenation of all the array elements. The problem I'm having is I'm only able to print the first string in my array, not all of them. I understand there is a null at the end of each string in my array so how would I work around that issue? Maybe 2d array? By the way I'm not allowed to use any string manipulation functions from string.h. Thank you.
#include <stdio.h>
#include <stdlib.h>
int findLength(char array[])
{
int i = 0;
for (i = 0; array[i] != '\0'; i++)
{
}
return i;
}
void arrayToString(char string[])
{
int n = 0;
int i = 0;
int l = findLength(string);
char *finalString;
finalString = malloc(l * sizeof(char));
for (i = 0; string[i] != '\0'; i++) {
finalString[n] = string[i];
n++;
}
for (i = 0; finalString[i] != '\0'; i++) {
printf("%c", finalString[i]);
}
}
int main(int argc, const char * argv[])
{
char *color[] = { "red", "blue", "red" };
arrayToString(*color);
return 0;
}
Change your function arrayToString to have two arguments.one of type char ** and the second of type size_t defining the number of strings.Also let its return value to be char * to return a pointer to the allocated memory.finally don't forget to free this memory.
#include <stdio.h>
#include <stdlib.h>
int findLength(char array[]) {
int i = 0;
for (i = 0; array[i] != '\0'; i++) {
}
return i;
}
char* arrayToString(char **string, size_t size) {
int bigSize = 0, len;
int i = 0, j, k;
for (j = 0; j < size; j++) {
bigSize += findLength(string[j]);
}
char *bigstring = (char *)malloc(bigSize + 1);
for (j = 0; j < size; j++) {
len = findLength(string[j]);
for (k = 0; k < len; k++) {
bigstring[i++] = string[j][k];
}
}
bigstring[i] = '\0';
return bigstring;
}
int main(int argc, const char * argv[])
{
char *color[] = { "red", "blue", "red" };
char *bigstring = arrayToString(color, 3);
printf("%s\n", bigstring);
free(bigstring);
return 0;
}
you have several problems in your code, here is the fixed version with comments:
size_t findLength(char* array[]) {
size_t l = 0;
while (char *t = *array++)
while (*t++)
l++;
return l;
}
void copyAll(char* array[], char* out) {
while (char *t = *array++)
while (*t)
*out++ = *t++; // copy every symbol from every line into out string
*out = '\0'; // append last null-terminator
}
void arrayToString(char* array[]) {
char* finalString = malloc((findLength(array) + 1) * sizeof(char)); // allocate + 1 symbol for null terminator
copyAll(array, finalString);
printf("%s", finalString);
free(finalString); // don't forget to release memory
}
int main(int argc, char* argv[]) {
char* color[] = { "red", "blue", "red", 0 }; // you should add array terminator as well
arrayToString(color);
return 0;
}

Showing an array of Doubles

I want to write a function to transform an array of n doubles to an string, a show function, something like:
struct vec { uint64_t n; double *x; };
char *show(struct vec *v) {...}
Notice that I don't want to print them, only do a serialization into a string.
How can I do this in C?
You can do something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define MAX_DOUBLE_LENGTH 15
typedef struct
{
size_t n;
double* x;
} DoubleArray;
int ShowArray(const DoubleArray* const doubleArrayPtr, char** const resultStringPtr)
{
int errorCode = 0;
char* tempStr = NULL;
char str[MAX_DOUBLE_LENGTH + 2]; /* 1 for trailing space and 1 for null-terminator */
size_t N = 0;
size_t i = 0;
if (doubleArrayPtr == NULL || resultStringPtr == NULL)
{
errorCode = 1;
}
else
{
if (doubleArrayPtr->n != 0)
{
/*
calculating max string length from:
str = <double01> <space> <double02> <space> <double03> <null-terminator>
ex.: str = '3.25 4.75 0.01 5.678\0'
*/
N = doubleArrayPtr->n * MAX_DOUBLE_LENGTH + doubleArrayPtr->n;
tempStr = malloc(N * sizeof(*tempStr));
if (tempStr == NULL)
{
errorCode = 1;
}
else
{
memset(tempStr, 0, N * sizeof(*tempStr));
for(i = 0; i < doubleArrayPtr->n; i++)
{
sprintf(str, "%.6f ", doubleArrayPtr->x[i]);
strcat(tempStr, str);
}
tempStr[strlen(tempStr) - 1] = '\0';
/* string formed -- allocating buffer for result */
(*resultStringPtr) = malloc((strlen(tempStr) + 1) * sizeof(**resultStringPtr));
if ((*resultStringPtr) == NULL)
{
errorCode = 1;
}
else
{
/* exporting result */
memcpy((*resultStringPtr), tempStr, strlen(tempStr) * sizeof(*tempStr));
(*resultStringPtr)[strlen(tempStr)] = '\0';
}
}
free(tempStr);
tempStr = NULL;
}
}
return errorCode;
}
int main(void)
{
/* test code part */
DoubleArray d;
char* s = NULL;
size_t i = 0;
srand(time(NULL));
d.n = rand() % 21;
d.x = malloc(d.n * sizeof(*d.x));
for(i = 0; i < d.n; i++)
{
d.x[i] = (rand() % 99999) / 100.0;
printf("[%d] = %f\n", i, d.x[i]);
}
ShowArray(&d, &s);
printf("str = '%s'\n", s);
free(d.x);
free(s);
return 0;
}

Resources