C programming recursion question generating segfault - c

trying to convert any number to any base in a recursion with C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* anybase(int n, int b)
{
char * s;
int len;
if(n==0) {strcpy(s,""); return s;}
s = anybase(n/b, b);
len=strlen(s);
s[len] = "0123456789ABCEDFGHIGKLMNOPQRSTUVWXYZ"[n%b];
s[len+1]='\0';
printf ("%s, %d, %d\n", s, n, b);
/* return s; */
}
int main(){
char *s;
s = anybase(900000, 18);
/*printf ("%s, %d, %d\n", anybase(90000, 18), 90000, 18);*/
}
is it the recursion having a problem? not sure why one can't return a value in the function call. what would be needed to call this recursion function and return a value instead of void.
Why is it generating seg fault each time running it? Thanks!

You were pretty much there, except you never allocated any memory for the string you're trying to produce. Here's a version which (apparently) runs correctly:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* anybase(int n, int b)
{
char *s;
int len;
if(n == 0)
{
s = malloc(200);
s[0] = '\0';
}
else
{
s = anybase(n/b, b);
len=strlen(s);
s[len] = "0123456789ABCEDFGHIGKLMNOPQRSTUVWXYZ"[n%b];
s[len+1]='\0';
}
return s;
}
int main()
{
char *result;
result = anybase(900000, 18);
printf("%s\n", result);
free(result);
}
Note that since the buffer returned by anybase is allocated dynamically (using the malloc library function) it must be free'd after use.

As others mentioned the issue is s is just a pointer that points to no where.
But instead of allocating memory for s inside of your anybase function a better approach is to allocate the memory in the main function. This avoids possible memory leaks when calling the function multiple times.
#include <stdio.h>
#include <string.h>
void anybase(int n, int b, char* s)
{
int len;
if(n==0) {strcpy(s,""); return;}
anybase(n/b, b, s);
len=strlen(s);
s[len] = "0123456789ABCEDFGHIGKLMNOPQRSTUVWXYZ"[n%b];
s[len+1]='\0';
printf ("%s, %d, %d\n", s, n, b);
printf("%d\n", len +1);
return;
}
int main(){
char s[33]; /* enough for all ints with base 2 */
anybase(90000, 18, s);
return 0;
}

The string buffer can be created statically in the main function but must then be passed to each recursive function call such that it can be written in to.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 200
const char *selection = "0123456789ABCEDFGHIGKLMNOPQRSTUVWXYZ";
void anybase(int n, int b, char *s)
{
if (n) {
anybase(n / b, b, s);
strncat(&s[strlen(s)], &selection[n % b], sizeof(char));
printf("%s, %d, %d\n", s, n, b);
}
}
int main()
{
char buf[BUFFER_SIZE];
memset(buf, 0, sizeof(char) * BUFFER_SIZE);
anybase(900000, 18, buf);
printf("Ouput: %s, N: %d, B: %d\n", buf, 90000, 18);
}

Related

Passing string variable by reference

I've this piece of code :
#include <stdio.h>
#include <string.h>
void b(char *in, char ** out);
int main()
{
char a[] = {'w','o','r','l','d','\0'};
char *d = nullptr;
b(a, &d);
printf("hello %s\n", d);
return 0;
}
void b(char *in, char ** out)
{
char tmp[10];
for(int i=0;i<6;i++)
tmp[i]=in[i];
*out=tmp;
printf("%s\n", *out);
}
I except to get theses printf :
world
hello world
But I get these :
world
hello
Why the d variable isn't fullfilled ? :(
Thanks for any clue about that !
Inside of b(), you are setting the char* referred by out to point at a local char[] array, which is NOT being null-terminated (thus breaking "%s" in printf()), but also WILL go out of scope when b() exits, thus the caller (ie main()) ends up with a dangling char* pointer to invalid memory.
You tagged your question as c++. C++ is not C. You should use std::string instead of char[] in this situation, eg:
#include <iostream>
#include <string>
void b(const std::string &in, std::string &out);
int main()
{
std::string a = "world";
std::string d;
b(a, d);
std::cout << "hello " << d << "\n";
return 0;
}
void b(const std::string &in, std::string &out)
{
std::string tmp = in.substr(0, 6);
out = tmp;
std::cout << out << "\n";
}
Otherwise, if you really want to use char*, in C or C++, you will need to use dynamic memory allocation, eg:
#include <stdio.h> // or <cstdio> in C++
#include <string.h> // or <cstring> in C++
void b(char *in, char ** out);
int main()
{
char a[] = "world";
char *d = nullptr;
b(a, &d);
printf("hello %s\n", d);
delete[] d; // or free() in C
return 0;
}
void b(char *in, char ** out)
{
char *tmp = new char[7]; // or malloc() in C
for(int i = 0; i < 6; ++i) {
tmp[i] = in[i];
}
tmp[6] = '\0';
*out = tmp;
printf("%s\n", *out);
}

Why is Segmentation fault when using GMP?

I am using the GMP. My program can build successfully, But run failed. The following is error things:
a=1231231231231231
res^n != a
Segment fault
All codes in my program is:
#include <gmp.h>
#include <stdio.h>
int main()
{
mpz_t a,res;
unsigned long int n = 123;
char str1[] = "1231231231231231";
mpz_init_set_str(a, str1, 10);
gmp_printf("a=%Zd\n",a);
mpz_init(res);
if(mpz_root(res, a, n)){
printf("res^n == a\n");
}
else{
printf("res^n != a\n");
}
mpz_clears(a,res);
return 0;
}
You have to call mpz_clears() like:
mpz_clears(a,res, NULL);
Here's what the documentation says:
Function: void mpz_clears (mpz_t x, ...)
Free the space occupied by a NULL-terminated list of mpz_t variables.

Why is this program crashing?

This function should return a string that contains string representations of the second and subsequent arguments, each to two decimal places and separated by commas. The first argument is a count of the number of arguments that follow. I did some research and found out about va_list and tried to work with it. Unfortunately the program is crashing and I have no idea why. I'm posting this hoping that someone could maybe spot an obvious mistake or something like that.
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
char *to_string(int count,...)
{
int i,x,k=0;
float tmp;
va_list valist;
va_start(valist, count+1);
char comma=',';
char buffer[count*6];
for(i=0;i<count;i++)
{
tmp=va_arg(valist, double)*100;
x=tmp/100.0;
k+=4;
snprintf(buffer + k, "%C",comma);
k++;
snprintf(buffer + 1, "%.2f", x);
}
va_end(valist);
printf("%s", buffer);
return buffer;
}
int main()
{
to_string(2,3.14876,6.123243);
}
As noted in the comments, you need to read the manual pages for va_start() and snprintf() in particular, and also pay attention to memory management (you cannot safely return a pointer to a local (non-static) variable).
Here's a revamped piece of code that cleans up the issues identified and that doesn't crash (for me on my Mac running macOS Sierra 10.12.1 and GCC 6.2.0).
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
static char *to_string(char *buffer, size_t buflen, int count, ...)
{
va_list valist;
va_start(valist, count);
char *data = buffer;
for (int i = 0; i < count; i++)
{
int x = va_arg(valist, double) * 100;
double tmp = x / 100.0 + 0.005;
int n = snprintf(data, buflen, ",%.2f", tmp);
if (n > (int)(buflen - 1))
{
fprintf(stderr, "%s: buffer not big enough\n", __func__);
break;
}
data += n;
buflen -= n;
}
va_end(valist);
printf("%s: [%s]\n", __func__, buffer);
return buffer;
}
int main(void)
{
char buffer[80];
printf("main: [%s]\n", to_string(buffer, sizeof(buffer), 2, 3.14876, 6.123243));
return 0;
}
Example output:
to_string: [,3.15,6.12]
main: [,3.15,6.12]
Note that there's the leading comma which you probably don't want. That can be fixed like this:
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
static char *to_string(char *buffer, size_t buflen, int count, ...)
{
va_list valist;
va_start(valist, count);
char *data = buffer;
const char *pad = "";
for (int i = 0; i < count; i++)
{
int x = va_arg(valist, double) * 100;
double tmp = x / 100.0 + 0.005;
int n = snprintf(data, buflen, "%s%.2f", pad, tmp);
if (n > (int)(buflen - 1))
{
fprintf(stderr, "%s: buffer not big enough\n", __func__);
break;
}
pad = ",";
data += n;
buflen -= n;
}
va_end(valist);
printf("%s: [%s]\n", __func__, buffer);
return buffer;
}
int main(void)
{
char buffer[80];
printf("main: [%s]\n", to_string(buffer, sizeof(buffer), 2, 3.14876, 6.123243));
printf("main: [%s]\n", to_string(buffer, sizeof(buffer), 20,
6.67, 0.04, 8.81, 8.49, 3.50, 1.20, 4.28, 0.67, 1.93, 5.63,
5.30, 8.43, 1.99, 4.62, 5.54, 7.21, 9.43, 2.02, 4.77, 0.29));
return 0;
}
Example output:
to_string: buffer not big enough
to_string: [3.15,6.12]
main: [3.15,6.12]
to_string: [6.67,0.04,8.82,8.50,3.50,1.20,4.29,0.68,1.93,5.63,5.30,8.44,1.99,4.62,5.54,7.21]
main: [6.67,0.04,8.82,8.50,3.50,1.20,4.29,0.68,1.93,5.63,5.30,8.44,1.99,4.62,5.54,7.21]

Right Justified Zero filled String in C

I want to right justify a string value with zero filled on left hand side. I have written following code but it prints white space instead of 0.
#include<stdio.h>
int main()
{
char s[4]="PJ";
printf("%04s",s);
}
Output: " PJ"
I need output as "00PJ".
You can do something like this :
#define MIN_LEN 4
if (strlen(s) < MIN_LEN) {
printf("%0*d%s", MIN_LEN-(int)strlen(s), 0, s);
}
else {
printf("%s", s);
}
Don't forget to include <string.h>
Edit :
To explain our discussion about buffer overflow, just try this piece of code :
int main()
{
struct
{
char s[4];
int i;
} test;
test.i = 0x12345678;
strcpy(test.s,"PJHA");
printf("Output =%s\nTest =%x",test.s,test.i);
}
Output :
Output =PJHA
Test =12345600
If you change the size to 5, the code is corrected and the stack following your string is not corrupted.
Here is the short line code answer for my question:-
This will take care of any length of input variable like s = "J", s="JH", s="JHA", s="PJHA"
and corresponding output will be "000J", "00JH", "0JHA", "PJHA" .
#include<stdio.h>
#include<string.h>
int main()
{
char s[4],s2[4];
strcpy(s,"JH");
sprintf(s2,"%04s",s);
memset(s2,'0',4-(int)strlen(s));
printf("Output =%s\n",s2);
}
Output =00JH
Appreciate the above simpler solution while giving an alternative more manual one:
#include<stdio.h>
#include<string.h>
void print(char *s, int ncount)
{
if(s == NULL) return;
int len = strlen(s);
if(len > ncount) printf("%s", s);
else {
for(int i = 0; i < ncount - len; ++i)
printf("0");
printf("%s", s);
}
}
int main()
{
char s[4]="PJ";
print(s, 4);
return 0;
}
#include <stdio.h>
#include <string.h>
int main(){
char s[5]="PJ";
char padding[sizeof(s)] = {0};
int width = sizeof(padding)-1;
memset(padding, '0', width);
width -= strlen(s);
//printf("%.*s%s\n", (int)(4-strlen(s)), "0000", s);
printf("%.*s%s\n", width, padding, s);
return 0;
}

Unable to sort a list of strings alphabetically in C

I wrote a program to accept 5 strings from user and then display them sorted alphabetically using bubble-sort algorithm. But, the strings are being displayed in the same order as they were entered. Please tell me what am I doing wrong here.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sSwap(char *s1, char *s2);
int main(){
char *sList[5],input[100],*p;
int i,j;
puts("Enter 5 strings");
for(i=0;i<5;i++){
gets(input);
sList[i] = (char *)malloc(strlen(input)+1);
strcpy(sList[i],input);
}
puts("");
for(i=3;i>=0;i--){
for(j=0;j<=i;j++){
if(strcmp(sList[j],sList[j+1])>0)
sSwap(sList[j],sList[j+1]);
}
}
for(i=0;i<5;i++)
puts(sList[i]);
return 0;
}
void sSwap(char *s1, char *s2){
char *temp;
temp = s1;
s1 = s2;
s2 = temp;
}
as you were told, your swap function getting values and swap them by value, meaning that when you leave the function the changes will not be saved and old values will return. try this
void sSwap(char **s1, char **s2);
int main(){
char *sList[5],input[100],*p;
int i,j;
puts("Enter 5 strings");
for(i=0;i<5;i++){
gets(input);
sList[i] = (char *)malloc(strlen(input)+1);
strcpy(sList[i],input);
}
puts("");
for(i=3;i>=0;i--){
for(j=0;j<=i;j++){
if(strcmp(sList[j],sList[j+1])>0)
sSwap(&sList[j],&sList[j+1]);
}
}
for(i=0;i<5;i++)
puts(sList[i]);
return 0;
}
void sSwap(char **s1, char **s2){
char *temp;
temp = *s1;
*s1 = *s2;
*s2 = temp;
}
One of your problem is that when you swap two strings, you doesn't check if you have to swap it with the new neighboors of this string.
So I would do a recursive function to solve this. Like if you swap, you call the function (let's say void sort(char **list, int index)) :
sort(sList, 0) //to start from beginning and check the new order
If the strings are equals or in the right order, like :
sort(sList, currentListIndex);
So you would have :
void sort(char **sList, int index) {
if (sList[index+1]) {
if (strcmp(sList[index],sList[index+1]) > 0){
sSwap(sList, index); // you can swap direclty on the tab
return sort(sList, 0);
}
return sort(sList, index+1);
}
return void;
}
sort(sList, 0);
It's been a while i didn't do C so maybe pointers are wrong, but it's the idea
The qsort function is in the stdlib.h
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
you define the number of elements in array
#define n_array sizeof(array)/sizeof(const char *)
and the comparison function
static int compare (const void * a, const void * b)
{
return strcmp (*(const char **) a, *(const char **) b);
}
and then in main you should use, replacing sSwap
qsort (array, n_array, sizeof (const char *), compare);

Resources