Why is this program crashing? - c

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]

Related

C programming recursion question generating segfault

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

Seg Fault occurs while malloc-ing

This function is a part of program which will gain statistics about books (amount of specific letters, words etc.). Thing is that segmentation fault appears when trying to malloc:
*wordArray[arrayIndex] = malloc(sizeof(***wordArray)*(wcslen(newWord)+1));
after reallocing whole array
*wordArray = realloc(*wordArray, (arrayIndex+1)*sizeof(**wordArray));
I know that realloc isn't really efficent but the most important thing at the moment is to understand why it doesn't work at all. Thanks a lot.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <wctype.h>
#include <wchar.h>
#define X 2
void wordManager(wchar_t ***, int **, wchar_t *);
int main(int argc, char **argv){
setlocale(LC_ALL, "");
wchar_t **wordArray;
int *wordAmount;
wchar_t word[50];
for(int i=0; i<X; i++){
scanf("%ls", word);
wordManager(&wordArray, &wordAmount, word);
}
for(int i=0; i<X; i++){
printf("%ls; %d times\n", wordArray[i], wordAmount[i]);
}
}
void wordManager(wchar_t ***wordArray, int **wordAmount, wchar_t *newWord){
static int isArrayInitialised = 0;
static int isArrayEmpty = 1;
static int arrayIndex = 0;
int wordLocation;
if(!isArrayInitialised){
*wordArray = malloc(sizeof(**wordArray)*1);
if(*wordArray==NULL){
printf("Error mallocing wordArray");
exit(EXIT_FAILURE);
}
*wordAmount = calloc(1, sizeof(*wordAmount));
if(*wordAmount==NULL){
printf("Error callocing wordAmount");
exit(EXIT_FAILURE);
}
isArrayInitialised = 1;
}
if(isArrayEmpty){
*wordArray[0] = malloc(sizeof(***wordArray)*(wcslen(newWord)+1));
wcscpy(*wordArray[0], newWord);
*wordAmount[0] = 1;
isArrayEmpty = 0;
}
else{
//Check if word is already in an array.
wordLocation = 0;
for(; wordLocation<arrayIndex+1; wordLocation++){
if(!wcscmp(*wordArray[wordLocation], newWord)) break;
}
printf("%d\n", wordLocation);
//Word hasn't been found. Then:
if(wordLocation==arrayIndex+1){
arrayIndex++; //Increase arrays' volume.
*wordArray = realloc(*wordArray, (arrayIndex+1)*sizeof(**wordArray));
if(*wordArray==NULL){
printf("Error reallocating wordArray memory.\n Array index: %d", arrayIndex);
exit(EXIT_FAILURE);
}
*wordAmount = realloc(*wordAmount, (arrayIndex+1)*sizeof(**wordAmount));
if(*wordAmount==NULL){
printf("Error reallocating wordAmount memory.\n Array index: %d", arrayIndex);
exit(EXIT_FAILURE);
}
*wordArray[arrayIndex] = malloc(sizeof(***wordArray)*(wcslen(newWord)+1));
wcscpy(*wordArray[arrayIndex], newWord);
*wordAmount[arrayIndex] = 1;
}
//Word has been found in an array.
else{
(*wordAmount[wordLocation])++;
}
}
}

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

vsprintf on OS X: EXC_BAD_ACCESS

I've discovered weird behavior of vsprintf on OSX.
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#if defined(WIN32)
#include <windows.h>
#define VSNPRINTF _vsnprintf
#elif defined(LINUX) || defined (DARWIN)
#define VSNPRINTF vsnprintf
#include <sys/types.h>
#include <unistd.h>
#endif
char *f(const char *fmt, ...)
{
char *out = NULL;
const int step = 32;
int n = -1, lout = step;
va_list arg;
if(fmt!=NULL)
{
va_start(arg, fmt);
do
{
if(!out)
{
free(out);
out = NULL;
}
out = (char*)malloc(lout + 1);
if(!out) break;
memset(out, 0, lout + 1);
n = VSNPRINTF(out, lout, fmt, arg);
if(n == -1 || n + 1 > lout)
{
lout += step;
n = -1;
}
}while(n == -1);
va_end(arg);
}
return out;
}
int main()
{
char *msg = NULL;
unsigned long x = 0xDEADBEEF;
msg = f("%X%X%X%X", x, x, x, x);
if(!msg) return -1;
puts(msg);
return 0;
}
The function shall return allocated string (char*) containing formatted text. It works correctly on Linux and Windows. It returns badly formatted text on OSX and sometimes it leads to Segmentation fault (EXC_BAD_ACCESS). Btw, I know that I can use vasprintf.
What can be the problem?
Your problem is most likely that you're calling vsnprintf with the same va_list multiple times. This doesn't work in some ABIs.
Look up the man page of va_copy. The short version is to do something like this:
va_list c;
va_copy(c, arg);
n = VSNPRINTF(out, lout, fmt, c);
va_end(c);

File handling using API thread in C

Im making an application that uses of API-threads in C, The program takes N-files (N>2) with names disordered,per each file is generated a thread of execution which sort the files using the function qsort, after being ordered files, each thread should create a file keeping the original file intact and displaying the sorted file to another file with the extension <.sorted>. The program sorts the numbers without problems, even if I put standard output displays the result on screen, but when I try to create the output file with extension .sorted the program breaks out.
this is my code file.c
#include <stdio.h> /* Standard buffered input/output */
#include <stdlib.h> /* Standard library functions */
#include <string.h> /* String operations */
#include <pthread.h> /* Thread related functions */
#include "pf1.h" /* Header specific to this app */
pthread_attr_t attr;
void *thread_worker(void *name_file)
{
FILE *entrada, *salida;
char* nombres = (char*)name_file;
int numero;
char temp [10000];
int i;
stats_t estadisticas;
printf ("File_name:%s\n", nombres);
entrada = fopen(nombres, "r");
salida = fopen (strcat(nombres, ".sorted"), "w");
while (!feof(entrada)){
fscanf (entrada, "%s\n",temp);
numero++;
}
char* lista[numero]; //array to sort the file
rewind (entrada);
for (i=0;i<numero;i++)
{
fscanf(entrada," %[^\n]", temp);
lista[i] = (char*)malloc((strlen(temp)+1)*sizeof(char));
strcpy(lista[i], temp);
}
size_t large = sizeof(lista) / sizeof(char *);
qsort(lista,large ,sizeof(char *) ,cstring_cmp );
printf ("Archivo Ordenado\n", i+1);
for (i=0;i<large;i++)
printf("%s\n",lista[i]);
pthread_exit(NULL);
}
int main(int argc, char *argv [])
{
stats_t **stats;
int i, rc;
pthread_t my_threads[argc-1];
pthread_attr_init(&attr);
if (argc <3) {
printf ("|files| > 2\n");
}else{
printf("files to sorted: %d\n", argc - 1);
for (i = 1; i < argc; i++){
//printf("%s%s\n", argv[i], (i < argc-1) ? " " : "");
rc = pthread_create(&my_threads[i], &attr, thread_worker, (void *)argv[i]);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n",rc);
return -1;
}
}
}
return 0;
} /*end main */
this is mi file.h
#ifndef PF1_H_
#define PF1_H_
typedef struct _stats_t
{
char *longest, *shortest;
unsigned int numlines;
} stats_t;
int cstring_cmp(const void *a, const void *b)
{
const char **ia = (const char **)a;
const char **ib = (const char **)b;
return -strcasecmp(*ia, *ib);
/* strcmp functions works exactly as expected from
comparison function */
}
void print_cstring_array(char **array, size_t len)
{
size_t i;
for(i=0; i<len; i++)
printf("%s | ", array[i]);
putchar('\n');
}
#endif /* PF1_1_H_ */
I would like some help with this problem because I can not see which is the fault ... thanks to all in advance and excuse my English
This line here may be your problem:
salida = fopen (strcat(nombres, ".sorted"), "w");
From what I can tell, that nombres variable is coming from argv. Since you're not the one allocating memory for argv, you don't know that there will be extra space for the ".sorted" (and there probably won't be). If you strcpy it to your own buffer with space for the ".sorted", you should be fine.
#define EXT_LEN 7
#define MAX_TOTAL_LEN 250
#define MAX_FILE_LEN 242 //MAX_TOTAL_LEN - EXT_LEN - 1
char *name_ptr;
char nombres[MAX_TOTAL_LEN];
int len;
name_ptr = (char*)name_file;
len = strlen(name_ptr);
if (len > MAX_FILE_LEN) {
len = MAX_FILE_LEN;
}
strncpy(nombres, name_ptr, len);
strcpy(nombres+len, ".sorted");
salida = fopen (nombres, "w");
I once had issues about not passing an int identifier while calling thread execution functions. Try building a struct with both an integer identifier and the filename, then pass it as a parameter to your thread_worker() function.

Resources