Shortest and longest string in array - arrays

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!

Related

How can I write the concatenated string to the given string pointer in C?

I am having trouble with the very last line in my function, where I am stilly learning the basics of C. I have the signature of this function given and am tasked to write a function to concatenate two strings. The commented line outputs the correct result.
#include <stdio.h>
#include <stdlib.h>
// 1) len = dst-len + max_dst_len
int strlcat(char *dst, const char *src, int max_dst_len) {
int len = 0;
while (dst[len] != '\0') {
len++;
}
int total_len = len + max_dst_len;
char *new_str = malloc(sizeof(char) * total_len);
for (int i = 0; i < len; i++) {
new_str[i] = dst[i];
}
for (int i = len; i < total_len; i++) {
new_str[i] = src[i - len];
}
new_str[total_len] = '\0';
//printf("%s <--\n", new_str);
dst = *new_str;
return total_len;
}
int main() {
char test1[] = "dst";
char test1src[] = "src";
printf("%s\n", test1);
printf("%d\n", strlcat(test1, test1src, 10));
printf("%s\n", test1);
}
You should not be adding max_dst_len to the length of dst. max_dst_len is the amount of memory that's already allocated in dst, you need to ensure that the concatenated string doesn't exceed this length.
So you need to subtract len from max_dst_len, and also subtract 1 to allow room for the null byte. This will tell you the maximum number of bytes you can copy from src to the end of dst.
In your main() code, you need to declare test1 to be at least 10 bytes if you pass 10 as the max_dst_len argument. When you omit the size in the array declaration, it sizes the array just big enough to hold the string you use to initialize it. It's best to use sizeof test1 as this argument, to ensure that it's correct for the string you're concatenating to.
#include <stdio.h>
int strlcat(char *dst, const char *src, int max_dst_len) {
int len = 0;
while (dst[len] != '\0') {
len++;
}
int len_to_copy = max_dst_len - len - 1;
int i;
for (i = 0; i < len_to_copy && src[i] != '\0'; i++) {
dst[len+i] = src[i];
}
dst[i] = '\0';
//printf("%s <--\n", new_str);
return i + len;
}
int main() {
char test1[6] = "dst";
char test1src[] = "src";
printf("%s\n", test1);
printf("%d\n", strlcat(test1, test1src, sizeof test1));
printf("%s\n", test1);
}

Where my code is leak? how i need to write free() function? C

This code scans number then he create array with malloc, then i scan strings, i put then inside the array with another malloc, then i sort the strings and print them. I build this code with mallocs and i put array inside array,i have leaks in this code, where i need to put free() function and how i put free()? I tried many times to solve this leaks but its not working.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sort(char** names, int length);
void print_array(char** names, int length);
int main()
{
int num_of_friends = 0;
int i = 0;
char name[50] = { 0 };
char** names = NULL;
printf("Enter number of friends: ");
scanf("%d", &num_of_friends);
getchar();
names = malloc(sizeof(char) * num_of_friends);
for ( i = 0; i < num_of_friends; i++)
{
printf("Enter name of friend %d: ", i + 1);
fgets(name, 50, stdin);
name[strcspn(name, "\n")] = 0;
names[i] = malloc(sizeof(char) * strlen(name));
strcpy(names[i], name);
}
sort(names, num_of_friends);
print_array(names, num_of_friends);
getchar();
return 0;
}
void sort(char** names, int length)
{
char temp[50] = { 0 };
int i = 0;
int j_min = 0;
int j = 0;
for ( i = 0; i < length - 1; i++)
{
j_min = i;
for ( j = i+1; j < length; j++)
{
if (strcmp(names[j], names[j_min]) < 0)
{
j_min = j;
}
}
if (j_min != i)
{
strcpy(temp, names[i]);
strcpy(names[i], names[j_min]);
strcpy(names[j_min], temp);
}
}
}
void print_array(char** names, int length)
{
int i = 0;
for (i = 0; i < length; i++)
{
printf("Friend %d: %s \n", i + 1, names[i]);
}
}
For names, you are allocating sizeof (char) times the user provided number of bytes. This is needs to be sizeof (char *), giving you enough room for each pointer value.
names = malloc(sizeof (char *) * num_of_friends);
You need to allocate one additional byte for the null terminating character ('\0'). sizeof (char) is guaranteed to be 1, making that statement redundant.
names[i] = malloc(strlen(name) + 1);
Before the end of main, you need to free each element of names, and then names itself.
sort(names, num_of_friends);
print_array(names, num_of_friends);
getchar();
for (i = 0; i < num_of_friends; i++)
free(names[i]);
free(names);
return 0;
Your sort function may attempt to copy strings between buffers of differing size. You need to swap pointers instead.
Example:
void swap(char **a, char **b) {
char *c = *a;
*a = *b;
*b = c;
}
void sort(char **names, size_t length) {
for (size_t i = 0; i < length - 1; i++)
for (size_t j = i + 1; j < length; j++)
if (strcmp(names[i], names[j]) > 0)
swap(names + i, names + j);
}

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.

Error freeing memory after sorting the array pointer

How will I be able to maintain the position of the allocated memory so that freeing memory of a sorted array will not be affected?
I am trying to sort the pointer array. I noticed that when I free the words double pointer variable it will give an error HEAP CORRUPTION DETECTED. The input I entered was "f ff 1".
Unsorted: f ff 1
Sorted: 1 f ff
I noticed that when I sort and free it will expect the same order which is "f ff 1". That is why I got some error.
Any suggestion on how will be able to free the sorted pointer array?
#include <stdio.h>
/*
A logical type
*/
typedef enum {
false,
true,
} bool;
/*
Bubble Sort
*/
void sort(char *myargv[], int n)
{
int i, j, cmp;
char tmp[256];
if (n <= 1)
return; // Already sorted
for (i = 0; i < n; i++)
{
for (j = 0; j < n-1; j++)
{
cmp = strcmp(myargv[j], myargv[j+1]);
if (cmp > 0)
{
strcpy(tmp, myargv[j+1]);
strcpy(myargv[j+1], myargv[j]);
strcpy(myargv[j], tmp);
}
}
}
}
void printArray(char *myargv[], int myargc)
{
int i = 0;
for (i = 0; i < myargc; ++i) {
printf("myargc[%d]: %s\n",i , myargv[i]);
}
}
int main (int argc, char *argv[])
{
char text[256];
char *myargv[256];
char *myargvTemp[256];
int myargc;
int i = 0;
int text_len;
bool new_word = false;
int index_start_word = 0;
char **words; //this will store the found word
int count = 0;
while(1){
printf( "Enter text:\n");
gets(text); //get the input
text_len = strlen(text); //get the length of the text
words = (char **) malloc(text_len * sizeof(char));
if (strlen(text) == 0 || text == '\0') exit(0); //exit if text is empty
for (i = 0; i < text_len ; ++i){
if(text[i] != ' '){ //if not space
if(new_word == false){
new_word = true;
index_start_word = i;
}
} else {
if (new_word == true) {
words[count] = (char *)malloc(i - index_start_word * sizeof(char)+1); //memory allocation
strncpy(words[count], text + index_start_word, i - index_start_word);
words[count][i - index_start_word] = '\0'; //place NULL after the word so no garbage
myargv[count] = words[count];
new_word = false;
count++;
}
}
if (new_word == true && i == text_len-1){
words[count] = (char *)malloc(i - index_start_word * sizeof(char)+2);
strncpy(words[count], text + index_start_word, (i+1) - index_start_word);
words[count][(i+1) - index_start_word] = '\0';
myargv[count] = words[count];
new_word = false;
count++;
}
}
myargc = count;
//not sorted
printf("myargc is: %d\n", myargc);
printArray(myargv, myargc);
//sorting happen
sort(&myargv, myargc);
printf("-----sorted-----\n");
printf("myargc is: %d\n", myargc);
printArray(myargv, myargc);
memset(myargv, 0, 255);
count = 0;
i = 0;
//free the memory of words
for (i=0; i<myargc; ++i) {
free(words[i]);
}
}
return 0;
}
There are at least 2 problems in your code:
you do not allocate enough space for the array of pointers: change the words = (char **) malloc(text_len * sizeof(char)); to this:
words = malloc(text_len * sizeof(char *));
This allocation is actually incorrect: you should compute the number of words and allocate the correct size for the pointer array, or use a fixed size array.
you swap the contents of the strings instead of swapping the pointers. This is incorrect as the various strings do not have the same lengths.
Here is a corrected version of the sorting function:
void sort(char *myargv[], int n) {
int i, j, cmp;
if (n <= 1)
return; // Already sorted
for (i = 0; i < n; i++) {
for (j = 0; j < n-1; j++) {
cmp = strcmp(myargv[j], myargv[j+1]);
if (cmp > 0) {
char *tmp = myargv[j+1];
myargv[j+1] = myargv[j];
myargv[j] = tmp;
}
}
}
}
You want words to hold pointers to char so you need to change
words = (char **) malloc(text_len * sizeof(char)); //will allocate array of single byte
to
words = (char **) malloc(text_len * sizeof(char *));// will allocate array of pointers

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)

Resources