Coding challenge in the C language [duplicate] - c

This question already has answers here:
What is going on with 'gets(stdin)' on the site coderbyte?
(3 answers)
Closed 3 years ago.
I am trying to do the following coding challenge in C:
Challenge:
Using the C language, have the function AlphabetSoup(str) take the str string parameter being passed and return the string with the letters in alphabetical order (ie. hello becomes ehllo). Assume numbers and punctuation symbols will not be included in the string.
Attempt:
#include <stdio.h>
#include <stdlib.h>
int cmpfunc(const void* val_1, const void* val_2){
return (*(char *)val_1 - *(char *)val_2);
}
int str_size(char* str[]){
int size = 0;
while(str[size] != '\0')
size++;
return size;
}
void AlphabetSoup(char * str[]) {
qsort(str,str_size(str), sizeof(char), cmpfunc);
printf("%s", str);
}
int main(void) {
// disable stdout buffering
setvbuf(stdout, NULL, _IONBF, 0);
// keep this function call here
AlphabetSoup(gets(stdin));
return 0;
}
I am not getting any output for this code. I think the problem is the cmpfunc function. I am not implementing it correctly. I neither understand how it works inside qsort. My understanding is that val_1 and val_2 are pointers to two chunks of memory in the array and somehow I have to cast these chunks to the right type.
I am also getting a non-zero status for the following code:
void AlphabetSoup(char * str[]) {
int str_size_ = str_size(str);
int int_rpr[str_size_];
int i;
for(i = 0; i < str_size; i++){
int_rpr[i] = (int)str[i];
}
printf("%i", str_size_);
//printf("%s", str);
//qsort(int_rpr,str_size_, sizeof(int), cmpfunc);
//for(i = 0; i < str_size; i++){
// printf("%c", str[i]);
// }
}
when I get rid of int_rpr[i] = (int)str[i];and replace it by any random statement like int b; b = 0; , it works.
coding challenge link: https://coderbyte.com/editor/Alphabet%20Soup:C

It was asked you parse an argument (not a string from stdin), so you need to use argc and argv. Also sizeof(char) is 1 by the C standard, so is superfluous.
Don't duplicate strlen either, we have libraries for a reason.
I'd do it this way (which I confirmed works on my system)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int char_cmp(const void *pa, const void *pb){
char a = *((char *) pa), b= *((char *) pb);
if (a < b){
return -1;
} else if (a > b){
return 1;
} else {
return 0;
}
}
int main(int argc, char *argv[]){
char *input= NULL;
if (2 != argc){
fprintf(stdout, "give one argument string\n");
return 1;
} else {
input = strdup(argv[1]);
if (NULL == input){
fprintf(stderr, "memory error\n");
return 2;
}
}
qsort(input, strlen(input), 1, char_cmp);
fprintf(stdout, "%s\n", input);
free(input);
return 0;
}

Related

Reversing a string with and without Dynamic Memory [duplicate]

This question already has answers here:
Why is this string reversal C code causing a segmentation fault? [duplicate]
(8 answers)
Why do I get a segmentation fault when writing to a "char *s" initialized with a string literal, but not "char s[]"?
(19 answers)
Closed 2 years ago.
int length(char *);
char* reverse(char *);
int main()
{
int a;
char p;
a=length("Computer");
printf("%d", a);
printf("\nReverse : %s", reverse("Computer"));
getch();
return 0;
}
int length(char *p)
{
int i;
for(i=0;*(p+i)!='\0'; i++);
return(i);
}
char* reverse(char *p)
{
int len, i;
char temp;
for(len=0; *(p+len)!='\0'; len++);
for(i=0; i<len/2; i++)
{
temp=*(p+i);
*(p+i)=*(p+len-1-i);
*(p+len-1-i)=temp;
}
return(p);
}
I am trying to print the length of the string inputted without using strlen() function and also creating a user defined function using pointer and function to reverse a string without using strrev() function. After compilation the program doesn't throws an error but it just does not display anything. The length is being printed correctly but the reverse section is not being printed and I can't figure out why? Help me out here people.
first of all, as user3121023 said, string constants (or literals) cannot be modified.
The problem was with indexes, pointer and at the end the piece of code that reverse the string. I adjust it in certain points and I'm gonna attach you here:
#include <stdio.h>
#include <stdlib.h>
int length(char *);
char * reverseWithDynamicMemory(char *, int);
char * reverseWithoutDynamicMemory(char *, int, char *);
int main() {
char *pWord = "Computer";
int wordLength = length(pWord);
char reverseWordWithouDynamicMemory[wordLength];
printf("Word Lenght: %d\n", wordLength);
printf("\nReverse with Dynamic Memory: %s\n", reverseWithDynamicMemory(pWord, wordLength));
printf("Reverse without Dynamic Memory: %s\n\n", reverseWithoutDynamicMemory(pWord, wordLength, reverseWordWithouDynamicMemory));
return 0;
}
int length(char *pWord) {
int i;
for (i = 0; *(pWord + i) != '\0'; i++);
return i;
}
char * reverseWithDynamicMemory(char *pWord, int length) {
int i = 0, end = length - 1;
char *reverseWord = (char *) malloc(sizeof(char) * length);
if(!reverseWord) {
printf("\nError allocating memory for reverseWord...\n");
exit(EXIT_FAILURE);
}
while (i < end || end >= 0) {
reverseWord[i] = pWord[end];
end--;
i++;
}
reverseWord[length] = '\0';
return reverseWord;
}
char * reverseWithoutDynamicMemory(char *pWord, int length, char *reverseWord) {
int i = 0, end = length - 1;
while (i < end || end >= 0) {
reverseWord[i] = pWord[end];
end--;
i++;
}
reverseWord[length] = '\0';
return reverseWord;
}
Some useful tips:
There was an implicit declaration of function 'getch' which is invalid in C99
Unused variable 'p'
Use more descriptive names
I've created a variable with dynamic memory inside the function reverse. Otherwise address of stack memory associated with local variable 'reverseWord' is returned.
Best regards,
Denny

how can I multiply strings in C like I do in python?

in python you can easily type:
str = "hi"
print(str * 10)
and the output would be hi printed 10 times. I'm currently learning how to code in C and I have to do this. Can someone teach me how I can do this kind of thing in C? Thanks in advance
Use for() loop:
Example:
#include <stdio.h>
int main() {
char* str = "hi";
for (int i = 0; i < 10; ++i) {
printf("%s", str);
}
}
And if you need to actually multiply the string (not just print n times) you can use the following mulstr(), just don't forget to test for NULL and to free():
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>
char* mulstr(char* str, size_t i) {
size_t len = strlen(str);
char* newstr = malloc(len * i + 1);
if (newstr) {
char* writer = newstr;
for (; i; --i) {
memcpy(writer, str, len);
writer += len;
}
*writer = 0;
} else {
perror("malloc");
}
return newstr;
}
int main() {
char* str = "hi";
char* newstr = mulstr(str, 10);
if (newstr) {
printf("%s", newstr);
free(newstr);
}
}
Using for-loop is the best way to implement this.
You can just create a customized print function which will do the same thing as python does. I am just giving a prototype here.
#include <stdio.h>
void print(char *string,int n)
{
int i;
for(i=0;i<n;i++)
{
printf("%s\n",string);
}
}
int main()
{
char *str="Hi";
print(str,2);
return 0;
}
Here second argument in the function n will tell you how many times you want to print the string.
The output will look like
Hi
Hi

strend function in C using pointers?

I have created a function for strend, which basically returns 1 if string t is present at the end of string s, however it never returns 1:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int strend(char *s, char *t) {
int p;
for (p = 0; p < strlen(s) - strlen(t); p++) {
*s++;
}
printf("%s\n%s\n", s, t);
if (s == t)
return 1;
return 0;
}
int main(void) {
int bool = strend("Hello", "ello");
printf("%i\n", bool);
return 0;
}
This gives me an output of:
ello
ello
0
So technically I should get 1. I assume the comparison using pointers is not used in this way?
You need to review your basic knowledge of C strings. There are lots of standard string functions in string.h that can help you with this test.
The basic problem is that the test s == t is valid, but you are comparing memory addresses here. You can see that is valid if you change the strings to test to
char test[] = "Hello";
int bool = strend_(test, test+1);
where test obviously is the same as your "Hello", and similarly, test+1 is the same as "ello" (try it by printing them). This correctly returns 1 with your routine.
In addition, I get two warnings:
on *s++; "warning: expression result unused [-Wunused-value]": you increment s but also ask what character is at that position through *s; and you don't use that information.
Fix by removing the * there.
on p < strlen(s) ..; "warning: comparison of integers of different signs: 'int' and 'unsigned long'", because strlen does not return a signed integer but an unsigned one (apparently, my header uses unsigned long).
Fix by declaring p as unsigned long, or even better, size_t.
Your entire routine can be condensed to a simple
int strend (char *s, char *t)
{
if (strlen(s) >= strlen(t) && !strcmp (s+strlen(s)-strlen(t),t))
return 1;
return 0;
}
It's not worth the trouble to cache the result of those four strlen calls into 2 temporary variables; a good compiler will work it out and do that for you. (A quick glance to the assembly output of the compiler I'm using – clang – shows it does, even with the default optimization settings.)
A slightly modified test, based on #M.M.'s comment:
int strend (char *s, char *t)
{
if (strlen(s) < strlen(t)) return 0;
return !strcmp (s+strlen(s)-strlen(t),t);
}
but attempting to optimize it this way is not as easy parsed as the routine above, and its assembly is ever so slightly "wordy" as well. Personally, I'd go for the more humanly readable version.
Use strcmp(3)
if (strcmp(s, t) == 0) return 1;
This actually compares the contents of the memory pointed to by s and t rather than their addresses.
Your code is broken in multiple ways:
The initial loop is a very cumbersome way to advance p by the difference of lengths if positive.
Once you have pointers at the same distance from the end of both strings, You should compare the characters with strcmp() (or memcmp() if you can first exclude the case of strlen(s) < strlen(t).
Comparing the pointers obtained after the loop will only work if t points inside the string pointed to by s, a special case that may or may not be produced by the compiler for the specific call in main: strend("Hello", "ello");.
Here is a modified version:
#include <string.h>
int strend(const char *str1, const char *str2) {
size_t len1 = strlen(str1);
size_t len2 = strlen(str2);
return len1 >= len2 && !memcmp(str1 + len1 - len2, str2, len2);
}
I corrected/modified your code, here is the code,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#pragma warning(disable:4996)
int strend(char *s, char *t)
{
int p,flag=0,count=0;//count will be the starting index for *t
p = strlen(s) - strlen(t);//this will be the starting index for *s
while(count<strlen(t))
{
if (*(s+p) == *(t+count))
{
flag = 1;
count++;
p++;
continue;
}
else
{
flag = 0;
break;
}
}
return flag;
}
int main(void)
{
int flag = strend("Hello", "ello");
printf("%i\n", flag);
return 0;
}
This code works too.
#include <stdio.h>
#include <string.h>
int strend (char *s1, char *s2);
void main ()
{
char str1[20] = "somethings";
char str2[20] = "things";
int f;
f = strend (str1,str2);
if (f==1)
printf ("1");
else
printf ("0");
}
int strend (char *str1, char *str2)
{
int l = strlen(str1) - strlen(str2);
str1 = str1 + l;
int d = strcmp(str1,str2);
if (d == 0)
return 1;
else
return 0;
}
this code works well.
int strend(char *s, char *t){
while(*t & *s){
if(*t == *s){
t++;
}
s++;
}
return *t==*s;
}

Program is causing a segmentation fault in VI but works fine in emacs

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

qsort segmentation fault

So I'm working on a program where the function reads in from stdio, and keeps reading in characters in chunks of n characters.
So far I've gotten it so that everything is stored in a character array called buffer. For the next step, I need to sort each chunk of n characters. For example the string cats/ndogs/n should be split as cats/n dogs/n if n =5, and then qsort() needs to alphabetize it. This is how I'm calling qsort():
qsort (buffer, (line-2)*n*(sizeof(char)),n,compare);
Where (line-2)*n*sizeof(char) gives the total number of items in the array buffer; 10 in this case.
This is my compare function:
int compare (const void * a, const void * b)
{
return (strcmp(*(char **)a, *(char **)b));
}
When I run this, however, I always get a seg fault in strcmp(). Any ideas why?
This is the loading code:
while (!feof(stdin))
{
for (i = 0; i < n; i++)
{
char l = getchar();
if (l != EOF)
{
if ((i == 0) && (line != 1))
{
success = (int *)realloc(buffer, line*n*(sizeof(char)));
}
buffer[(n*(line-1))+i] = l;
}
}
line = line + 1;
}
Silly question, but are your strings null terminated? You seem to only have a newline on the end.
Also, you probably only need "strcmp((char *)a, (char *)b)" as the extra *s look to be redundant to me.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char buffer[] ="333000222555111777888666999444";
int mycmp(void *l, void*r);
int main(void)
{
/* note: sizeof buffer is 31,
** but the integer division will round down
** , ignoring the extra nul-byte */
qsort(buffer, (sizeof buffer/3), 3, mycmp);
printf ("[%s]\n", buffer);
return 0;
}
int mycmp(void *l, void *r)
{
return memcmp(l,r,3);
}

Resources