Parse a URL in C - c

I am trying to parse several elements of a URL in C.
This is a prototype of a URL:
ftp://[< name>:< pass>#]< domain>/< url>";
The problem is that certain elements aren't being saved correctly, for example I try to save the ftp:// in here ftp[6]. However, when I print it I get something like this ftp:/d#. Which should not even be possible since the array does not have enough space for this.
int main()
{
char ftp[6];
char *name;
char *pass;
char *domain;
char *url;
char *var = "ftp://[coiso:pass#]teste/umgrandeurl";
int x;
int size_name;
int size_pass;
int size_domain;
int size_url;
int flag = 0;
for (x = 0; x < strlen(var); x++) {
if (x == 6) {
strncpy(ftp, var, 6);
if (strcmp(ftp, "ftp://") != 0) {
}
}
if (var[x] == ':' && x > 3) {
size_name = x - 7;
name = (char *)malloc(size_name + 1);
strncpy(name, &var[7], size_name);
}
if (var[x] == '#') {
size_pass = x - (8 + size_name);
pass = (char *)malloc(size_pass + 1);
strncpy(pass, &var[8 + size_name], size_pass);
}
if (var[x] == '/' && x > 6 && flag == 0) {
flag = 1;
size_domain = x - (10 + size_pass + size_name);
domain = (char *)malloc(size_domain + 1);
strncpy(domain, &var[10 + size_pass + size_name], size_domain);
}
if (x == strlen(var) - 1) {
size_url = x - (10 + size_pass + size_name + size_domain);
url = domain = (char *)malloc(size_url + 1);
strncpy(url, &var[11 + size_pass + size_name + size_domain], size_url);
printf("%d", size_url);
}
}
return 0;
}
EDIT: Well the same thing happens to me in the pass but it isn't because of the null char.

Instead of building your own url parser try UriParse

from the man page:
The strncpy() function is similar, except that at most n bytes of src are copied. Warning: If there is no null byte among the
first n bytes of src, the string placed in dest will not be null-terminated
size_url=x-(10+size_pass+size_name+size_domain);
url=domain =(char*) malloc( size_url+1);
strncpy(url,&var[11+size_pass+size_name+size_domain],size_url+1);
^^
... and similar for the other sizes / strncpy()s.

Related

How to convert char string into hex value

I have one situation where i am receiving characters serially, byte by byte in USB Tx mode.
Now I'm stuck at where I am receiving 7 and a and my objective is to create 0x7a data.
Please provide me some workaround.
void converttohex(int recsize) {
BYTE ccount = 0;
//BYTE *recptr = (BYTE*)calloc(CommOP_Rx.bDataLength, sizeof(BYTE));
*recptr = 88;
*(recptr + 1) = 16;
*(recptr + 2) = 1;
*(recptr + 3) = 224;
*(recptr + 4) = 1;
for (xp = 12, s = 5; xp < (CommOP_Rx.bDataLength - 4); xp++,s++) {
if (xp == 12) {
for (xp = 12; (*(recimage + xp)) != ','; xp++)
ccount++;
if (ccount == 1) {
xp = 12;
xq = (*(recimage + xp) - 48);
*(recptr+s) = xq;
xp++;
} else
if (ccount == 2) {
xp = 12;
xq = (*(recimage + xp) - 48) * 10;
xw = (*(recimage + (++xp)) - 48);
*(recptr + s) = xq + xw;
xp++;
} else
if (ccount == 3) {
xp = 12;
xq = (*(recimage + xp) - 48) * 100;
xw = (*(recimage + (++xp)) - 48) * 10;
xe = (*(recimage + (++xp)) - 48);
*(recptr+s) = xq + xw + xe;
xp++;
}
}
xp++;
if (((*(recimage + xp)) == 'a') || ((*(recimage + (++xp))) == 'a')) {
--xp;
if (((*(recimage + xp)) == 'a')) {
xq = (*(recimage + xp) - 48) * 10;
} else
xq = (*(recimage + xp) - 48);
xw = 'a';
*(recptr + s) = xq +xw;
}
xq = (*(recimage + xp) - 48) * 10;
xw = (*(recimage + (++xp)) - 48);
*(recptr + s) = xq + xw;
}
for (xp = 0; xp < (CommOP_Rx.bDataLength - 4); xp++) {
*(recimage + xp) = *(recptr + xp);
}
Basically here i am sampling some data, which is the array of image in hex, and storing it in my MCU array. But here i have implemented that when i will receive a two consecutive data in which which is an Integer 0-9, then i am subtracting 48 into it as all the bytes are in character encoding, upto this it is working fine, but after receiving A-F of hex, lets suppose i have received '7' & 'a' and it has to be value=0x7a , thus i need this conversion help!!
Store it in a null-terminated string and read from it.
// Assume N is a big number
char str[N] = "7A";
int ret;
sscanf(str, "%x", &ret);
printf("%d", ret); // Output: 122
To do it repetitively, let the program construct this array:
int i = 0;
while (read_data(&ch)){
// Assume ch is in "0123456789ABCDEFabcdef"
str[i++] = ch;
}
str[i] = 0;
// Now parse it
int ret;
sscanf(str, "%x", &ret);
You can store the hex digits in an array of char, null terminate this array an use sscanf() or strtol() to convert the string to a number.
Your code seems quite complicated for me to understand. Just giving a glimpse of what can be done to get hexadecimal value based on your question and not based on your code. Sorry for that.
If you process the two inputs as string then the below approach will suite.
char num1[] = "7";
char num2[] = "a";
char num[10];
strcpy (num, num1);
strcat (num, num2);
Now num has 7a as hexadecimal string
If you have the two inputs as integers then this logic will work
int num1,num2,num3;
num1=0x7;
num2=0xa;
num3=(num1<<4)|(num2);
sprintf(str,"0x%x",num3);

Efficiency of Cryptarithmetic Algorithm solver decomposition

The problem is the following: Given "ABC+DEF=GHI" format string, where A,B,C etc. represent unique digits, find the expression that gives maximum GHI. Ex: Input string is AAB+AAB=AAB, then there's no solution. If it is instead AAA + BBB = AAA, a solution is 999 + 000 = 999. Another example string: ABC + CBA = GGG, a result is => 543 + 345 = 888.
I have ruled out impossible cases easily. The algorithm I have in mind is a bruteforce, that simply tries maximizing the rhs first. However my problem was doing this fast, and also watching out for the unique digits. What's an efficient way to solve this problem?
Notes: I wish to solve this in a singlethreaded approach, and my current problem is detecting if a unique digit is used in "assign_value" function. Perhaps a better method to assign values is there?
EDIT: As per smci's suggestion, here's what I want to achieve, in the very end: ABRA + CADABRA + ABRA + CADABRA == HOUDINI ; 7457 + 1797457 + 7457 + 1797457 == 3609828 -- A system that can handle not only strings of the form I provided in the beginning (3 digit number + 3 digit number = 3 digit number) but also those. However it doesn't hurt to start simple and go with the solution of format I gave :)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_EXPRESSION_SIZE 11 + 1
#define MAX_VARIABLES 9
int variables_read[MAX_VARIABLES] = { 0 };
struct variable {
int coefficient;
int* ptr;
int side;
int canhavezero;
unsigned value_max;
};
typedef struct variable Variable;
struct equation {
Variable* variables[9]; // max
unsigned distinct_on_rhs;
unsigned var_count;
};
typedef struct equation Equation;
int int_pow(int n, int k) {
int res = 1;
for(int i = 0; i < k; ++i)
res *= n;
return res;
}
void AddVariable(Equation* E, Variable* V) {
E->variables[E->var_count++] = V;
}
int IsImpossible(char* expression) {
// if all letters are same or end letters are same, no solution
if(
(expression[0] == expression[4] && expression[0] == expression[8]) ||
(!strncmp(expression, expression + 4, 3) && !strncmp(expression, expression + 8, 3))
)
return 1;
return 0;
}
int assign_value(Equation* E, int pos, int* values) {
if(!E->variables[pos]->value_count) {
if(pos < 0)
return 2;
// if no possible values left, reset this, but take one value count from the closest variable
E->variables[pos - 1]->value_count--;
E->variables[pos]->value_count = E->variables[pos]->value_max;
return 0;
}
int i;
for(i = 9; i >= 0 && values[i] == -1; --i)
printf("Assigning %d to %c\n", E->variables[pos]->value_set[E->variables[pos]->value_count - 1], 'A' + (E->variables[pos]->ptr - E->variables[0]->ptr));
*(E->variables[pos]->ptr) = values[i];
values[i] = -1; // we have unique numbers
return 0;
}
int isSolved(Equation E) {
int sum = 0, coeff = 0;
printf("Trying...\n");
for(int i = 0; i < E.var_count; ++i) {
coeff = E.variables[i]->coefficient * (*E.variables[i]->ptr);
printf("%d ", *E.variables[i]->ptr);
if(E.variables[i]->side)
coeff *= -1;
sum += coeff;
}
printf("\nSum was %d\n", sum);
return !sum;
}
char* evaluate(char* expression) {
char* res;
// check for impossible cases first
if(IsImpossible(expression)) {
res = (char *) malloc(sizeof(char) * strlen("No Solution!"));
strcpy(res, "No Solution!");
return res;
}
res = (char *) malloc(sizeof(char) * MAX_EXPRESSION_SIZE);
// now try to find solutions, first describe the given characters as equations
Equation E;
E.var_count = 0;
E.distinct_on_rhs = 0;
int side_mode = 0, powcounter = 0;
int a = -1, b = -1, c = -1, d = -1, e = -1, f = -1, g = -1, h = -1, i = -1;
int* max_variables[MAX_VARIABLES] = { &a, &b, &c, &d, &e, &f, &g, &h, &i };
for(int j = 0; j < MAX_EXPRESSION_SIZE - 1; ++j) {
if(expression[j] == '+')
continue;
if(expression[j] == '=') {
side_mode = 1;
continue;
}
Variable* V = (Variable *) malloc(sizeof(Variable));
// we know we always get 3 digit numbers but we can easily change if we need to
V->coefficient = int_pow(10, 2 - (powcounter % 3));
V->ptr = max_variables[expression[j] - 'A'];
V->side = side_mode;
E.distinct_on_rhs += side_mode && !variables_read[expression[j] - 'A'];
if(!(powcounter % 3)) { // beginning of a number
V->value_count = 9;
V->value_max = 9;
V->canhavezero = 0;
}
else {
V->value_count = 10;
V->value_max = 10;
V->canhavezero = 1;
}
AddVariable(&E, V);
variables_read[expression[j] - 'A'] = 1;
++powcounter;
}
for(int j = 0; j < E.var_count; ++j)
printf("%d %c %d\n", E.variables[j]->coefficient, 'A' + (E.variables[j]->ptr - max_variables[0]), E.variables[j]->side);
// we got a representaion of the equation, now try to solve it
int solved = 0;
// O(9^N), where N is number of distinct variables.
// An optimization we can do is, we first assign possible max values to rhs number, then go down. We need max number.
printf("Distincts: %d\n", E.distinct_on_rhs);
do {
// try to assign values to all variables and try if it solves the equation
// but first try to assign rhs as max as possible
int values[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int temp = E.var_count - E.distinct_on_rhs;
while(temp < E.var_count) {
solved = assign_value(&E, temp, values);
++temp;
}
for(int j = E.var_count - 1 - E.distinct_on_rhs; j >= 0; --j)
solved = assign_value(&E, j, values);
if(solved) // can return no solution
break;
printf("Solving...\n");
solved = isSolved(E);
system("PAUSE");
} while(!solved);
if(solved == 2) {
res = (char *) malloc(sizeof(char) * strlen("No Solution!"));
strcpy(res, "No Solution!");
}
else {
}
return res;
}
int main() {
char expression[MAX_EXPRESSION_SIZE] = { 0 };
do {
printf("Enter the formula: ");
scanf("%s", expression);
char* res = evaluate(expression);
printf("%s\n", res);
free(res);
} while(expression[0] != '-');
return 0;
}
I would start with the result. There are not that many different cases:
AAA
AAB, ABA, BAA
ABC
All other cases can be reduced to these by renaming the variables. ABC + CBA = GGG would become DBC + CBD = AAA.
Then you have
10 possible solutions for the one-variable case AAA
90 (10*9) for the two variable cases
720 (10*9*8) for the three variable case
assuming that zero is allowed anywhere. If not, you can filter out those that are not allowed.
This sets the variables for the right side of the equation. Each variable that appears only on the left, adds possible solutions. B adds a factor of 9, C a factor of 8, D 7 and so forth.
The most "efficient" solution would take all knowledge of the task and simple print the result. So the question is how much of the conditions can be coded and where and what flexibility is needed.
An alternative is to view the generation of test cases and evaluation of them separately.
A simple recursion function can generate the 10! (362880) test cases of unique digits.
unsigned long long count = 0;
unsigned long long sol = 0;
void evaluate(int object[]) {
count++;
int ABC = object[0] * 100 + object[1] * 10 + object[2];
int DEF = object[3] * 100 + object[4] * 10 + object[5];
int GHI = object[6] * 100 + object[7] * 10 + object[8];
if (ABC + DEF == GHI) {
printf("%4llu %03d + %03d = %03d\n", ++sol, ABC,DEF,GHI);
}
}
void form_combos(int pool[], size_t pool_count, int object[],
size_t object_count, size_t object_count_max) {
if (object_count >= object_count_max) {
evaluate(object);
return;
}
assert(pool_count > 0);
int *pool_end = pool + pool_count - 1;
for (size_t p = 0; p < pool_count; p++) {
int sample = pool[p]; // take one out
pool[p] = *pool_end; // replace it with the end
object[object_count] = sample;
form_combos(pool, pool_count - 1, object, object_count + 1,
object_count_max);
pool[p] = sample; // restore pool item
}
}
int main() {
int pool[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
size_t pool_size = sizeof pool / sizeof pool[0];
#define object_count 9
int object[object_count];
form_combos(pool, pool_size, object, 0, object_count);
printf("Evaluate() iterations %llu\n", count);
}
Output
1 091 + 762 = 853
2 091 + 763 = 854
3 091 + 735 = 826
...
1726 874 + 061 = 935
1727 875 + 046 = 921
1728 876 + 045 = 921
Evaluate() iterations 3628800
What is nice about this approach is that if the task was now find
ABC*ABC + DEF*DEF == GHI*GHI
Changing only 2 lines of code:
if (ABC*ABC + DEF*DEF == GHI*GHI) {
printf("%4llu sqr(%03d) + sqr(%03d) = sqr(%03d)\n", ++sol, ABC,DEF,GHI);
}
results in
1 sqr(534) + sqr(712) = sqr(890)
2 sqr(546) + sqr(728) = sqr(910)
3 sqr(712) + sqr(534) = sqr(890)
4 sqr(728) + sqr(546) = sqr(910)
Evaluate() iterations 3628800
Ok, so for a trivial solution (a base to build a generalization on, so far it only works on the format <3 digit number> + <3 digit number> = <3 digit number>) inspired from #chux and #alain's suggestions is the following code. It truly runs on O(10^N) where N is the distinct number of digits present, or variables if you'd like to call them that. I'll see if I can generalize this even further.
Note that this is for the initial problem of finding the largest rhs. Take that into account as well.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_DIGITS 10
#define MAX_VARIABLES 9
#define MAX_EXPRESSION_SIZE 11
int IsImpossible(char* expression) {
// if all letters are same or end letters are same, no solution
if(
(expression[0] == expression[4] && expression[0] == expression[8]) ||
(!strncmp(expression, expression + 4, 3) && !strncmp(expression, expression + 8, 3))
)
return 1;
return 0;
}
int ArePointersAssigned(int*** pointers) {
for(int i = 0; i < MAX_VARIABLES; ++i) {
if(**pointers[i] == -1)
return 0;
}
return 1;
}
int evaluate(int*** pointers) {
int ABC = *(*pointers[0]) * 100 + *(*pointers[1]) * 10 + *(*pointers[2]);
int DEF = *(*pointers[3]) * 100 + *(*pointers[4]) * 10 + *(*pointers[5]);
int GHI = *(*pointers[6]) * 100 + *(*pointers[7]) * 10 + *(*pointers[8]);
if (ABC + DEF == GHI) { // since we use dfs, if this is a solution simply return it
//printf("%d + %d = %d\n", ABC, DEF, GHI);
return 1;
}
return 0;
}
// use the solved pointer to escape recursion early
// check_end checks if we reached 6 for the 2nd time, if it's first time we ignore (because it's start state)
void form_combos(int pool[], int pool_count, int object_count, int*** pointers, int* solved) {
if(object_count == MAX_DIGITS - 1)
object_count = 0;
if(*solved) // if a branch solved this, escape recursion
return;
if (ArePointersAssigned(pointers)) { // that means we got a full equation set
*solved = evaluate(pointers);
if(*solved)
return;
}
int *pool_end = pool + pool_count - 1;
for (int p = pool_count - 1; p >= 0 && !*solved; p--) {
int sample = pool[p]; // take one out
pool[p] = *pool_end; // replace it with the end
int temp = **pointers[object_count];
if(**pointers[object_count] == -1)
**pointers[object_count] = sample;
form_combos(pool, pool_count - 1, object_count + 1, pointers, solved);
pool[p] = sample; // restore pool item
if(!*solved)
**pointers[object_count] = temp;
}
}
int main() {
char expression[MAX_EXPRESSION_SIZE] = { 0 };
printf("Enter the formula: ");
scanf("%s", expression);
while(expression[0] != '-') {
if(IsImpossible(expression))
printf("No solution!\n");
else {
int digits[MAX_DIGITS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int object[MAX_VARIABLES] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 }; // stack for dfs
int *A = &object[0], *B = &object[1], *C = &object[2],
*D = &object[3], *E = &object[4], *F = &object[5],
*G = &object[6], *H = &object[7], *I = &object[8];
// set same pointers
int** pointers[MAX_VARIABLES] = { &A, &B, &C, &D, &E, &F, &G, &H, &I };
// analyze the equation
int var = 0;
for(int p = 0; p < MAX_EXPRESSION_SIZE; ++p) {
if(expression[p] >= 'A' && expression[p] <= 'I') {
*pointers[var++] = &object[expression[p] - 'A']; // link same pointers
}
}
int solved = 0, check_end = 0;
form_combos(digits, MAX_DIGITS, MAX_DIGITS - 4, pointers, &solved);
if(!solved) // it can be unsolvable still
printf("No solution!\n");
else
printf("%d%d%d + %d%d%d = %d%d%d\n", *A, *B, *C, *D, *E, *F, *G, *H, *I);
}
printf("Enter the formula: ");
scanf("%s", expression);
}
return 0;
}

sprintf replacement for embedded systems [duplicate]

I'm coding for a microcontroller-based application and I need to convert a float to a character string, but I do not need the heavy overhead associated with sprintf(). Is there any eloquent way to do this? I don't need too much. I only need 2 digits of precision.
Here's a version optimized for embedded systems that doesn't require any stdio or memset, and has low memory footprint. You're responsible for passing a char buffer initialized with zeros (with pointer p) where you want to store your string, and defining CHAR_BUFF_SIZE when you make said buffer (so the returned string will be null terminated).
static char * _float_to_char(float x, char *p) {
char *s = p + CHAR_BUFF_SIZE; // go to end of buffer
uint16_t decimals; // variable to store the decimals
int units; // variable to store the units (part to left of decimal place)
if (x < 0) { // take care of negative numbers
decimals = (int)(x * -100) % 100; // make 1000 for 3 decimals etc.
units = (int)(-1 * x);
} else { // positive numbers
decimals = (int)(x * 100) % 100;
units = (int)x;
}
*--s = (decimals % 10) + '0';
decimals /= 10; // repeat for as many decimal places as you need
*--s = (decimals % 10) + '0';
*--s = '.';
while (units > 0) {
*--s = (units % 10) + '0';
units /= 10;
}
if (x < 0) *--s = '-'; // unary minus sign for negative numbers
return s;
}
Tested on ARM Cortex M0 & M4. Rounds correctly.
Try this. It should be nice and small. I've output the string directly - doing a printf, rather than a sprintf. I'll leave it to you to allocate space for the return string, as well as copying the result into it.
// prints a number with 2 digits following the decimal place
// creates the string backwards, before printing it character-by-character from
// the end to the start
//
// Usage: myPrintf(270.458)
// Output: 270.45
void myPrintf(float fVal)
{
char result[100];
int dVal, dec, i;
fVal += 0.005; // added after a comment from Matt McNabb, see below.
dVal = fVal;
dec = (int)(fVal * 100) % 100;
memset(result, 0, 100);
result[0] = (dec % 10) + '0';
result[1] = (dec / 10) + '0';
result[2] = '.';
i = 3;
while (dVal > 0)
{
result[i] = (dVal % 10) + '0';
dVal /= 10;
i++;
}
for (i=strlen(result)-1; i>=0; i--)
putc(result[i], stdout);
}
// convert float to string one decimal digit at a time
// assumes float is < 65536 and ARRAYSIZE is big enough
// problem: it truncates numbers at size without rounding
// str is a char array to hold the result, float is the number to convert
// size is the number of decimal digits you want
void FloatToStringNew(char *str, float f, char size)
{
char pos; // position in string
char len; // length of decimal part of result
char* curr; // temp holder for next digit
int value; // decimal digit(s) to convert
pos = 0; // initialize pos, just to be sure
value = (int)f; // truncate the floating point number
itoa(value,str); // this is kinda dangerous depending on the length of str
// now str array has the digits before the decimal
if (f < 0 ) // handle negative numbers
{
f *= -1;
value *= -1;
}
len = strlen(str); // find out how big the integer part was
pos = len; // position the pointer to the end of the integer part
str[pos++] = '.'; // add decimal point to string
while(pos < (size + len + 1) ) // process remaining digits
{
f = f - (float)value; // hack off the whole part of the number
f *= 10; // move next digit over
value = (int)f; // get next digit
itoa(value, curr); // convert digit to string
str[pos++] = *curr; // add digit to result string and increment pointer
}
}
While you guys were answering I've come up with my own solution which that works better for my application and I figure I'd share. It doesn't convert the float to a string, but rather 8-bit integers. My range of numbers is very small (0-15) and always non-negative, so this will allow me to send the data over bluetooth to my android app.
//Assumes bytes* is at least 2-bytes long
void floatToBytes(byte_t* bytes, float flt)
{
bytes[1] = (byte_t) flt; //truncate whole numbers
flt = (flt - bytes[1])*100; //remove whole part of flt and shift 2 places over
bytes[0] = (byte_t) flt; //truncate the fractional part from the new "whole" part
}
//Example: 144.2345 -> bytes[1] = 144; -> bytes[0] = 23
I can't comment on enhzflep's response, but to handle negative numbers correctly (which the current version does not), you only need to add
if (fVal < 0) {
putc('-', stdout);
fVal = -fVal;
}
at the beginning of the function.
Its a Liitle large method, but It would work for both int and float, decimalPoint parameter is passed with zero value for Integer, Please let me know if you have smaller function than this.
void floatToStr(uint8_t *out, float x,int decimalPoint)
{
uint16_t absval = fabs(x);
uint16_t absvalcopy = absval;
int decimalcount = 0;
while(absvalcopy != 0)
{
absvalcopy /= 10;
decimalcount ++;
}
uint8_t *absbuffer = malloc(sizeof(uint8_t) * (decimalcount + decimalPoint + 1));
int absbufferindex = 0;
absvalcopy = absval;
uint8_t temp;
int i = 0;
for(i = decimalcount; i > 0; i--)
{
uint16_t frst1 = fabs((absvalcopy / pow(10.0, i-1)));
temp = (frst1 % 10) + 0x30;
*(absbuffer + absbufferindex) = temp;
absbufferindex++;
}
if(decimalPoint > 0)
{
*(absbuffer + absbufferindex) = '.';
absbufferindex ++;
//------------------- Decimal Extractor ---------------------//
for(i = 1; i < decimalPoint + 1; i++)
{
uint32_t valueFloat = (x - (float)absval)*pow(10,i);
*(absbuffer + absbufferindex) = ((valueFloat) % 10) + 0x30;
absbufferindex++;
}
}
for(i=0; i< (decimalcount + decimalPoint + 1); i++)
{
*(out + i) = *(absbuffer + i);
}
i=0;
if(decimalPoint > 0)
i = 1;
*(out + decimalcount + decimalPoint + i) = 0;
}

printf("%d\n", 1000000001) cause Segmentation fault?

I do not know why, gcc version 4.9.2 (Ubuntu 4.9.2-10ubuntu13 x86_64)
Breakpoint 1, convertToTitle (n=1000000001) at excel_sheet_column_title.c:14
14 printf("%d\n", n);
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400697 in convertToTitle (n=1000000001) at excel_sheet_column_title.c:14
14 printf("%d\n", n);
(gdb) p n
$1 = 1000000001
The complete code of the function, just called the function with 1000000001 in the main function:
char *convertToTitle(int n)
{
int mod, idx, last = n / 26 + 1;
char str[last], *title, *tp;
printf("%d\n", n);
idx = last;
while (n > 26) {
mod = n % 26;
if (mod > 0) {
str[--idx] = mod - 1 + 'A';
} else if (mod == 0) {
str[--idx] = 'Z';
n -= 1;
}
n /= 26;
}
if (n > 0) {
str[--idx] = n - 1 + 'A';
}
title = (char *)malloc((last - idx + 1) * sizeof(char));
tp = title;
for (; idx < last; idx++) {
*tp++ = str[idx];
}
*tp = '\0';
return title;
}
Your last is very large. Move it outside of local function (or mark it static) to avoid segfault.
As an alternative (and correct) solution, calculate correct value of last.
(I think you wanted log26n + 1)
26last >= nlast = log26n
last = ceil(log(n) / log(26)) + 1;
Weak calculation of needed buffer size for str[] resulted in an excessively large array size last of 1000000001/26 + 1. This array size was unsupportable as coded as a local variable.
What is needed is a much smaller array about log26(n).
There is little need to "right-size" the buffer per various values of int n. Simply use a constant size that works for INT_MAX.
As the bit size of an int is about log2(INT_MAX)+1,
#include <limits.h>
#define ABOUT_LOG2_26 4.7
#define BUF26_SIZE ((int)(sizeof(int)*CHAR_BIT/ABOUT_LOG2_26 + 2))
char *convertToTitle(int n) {
char str[BUF26_SIZE];
...
// Also cope with negative values of n
if (n < 0) Handle_Error();

Realloc segfault - invalid old size

I have a function in which the second pass gives me segfault every time and I have no idea how to fix it. Any advice would be appreciated.
char* testBefore(int k){
char* bin;
bin = calloc(1,1);
while(k > 0) {
bin = realloc(bin, strlen(bin)*sizeof(char)+1);
bin[strlen(bin) - 1] = (k % 2) + '0';
bin[strlen(bin)] = '\0';
k = k / 2;
}
printf("\n%s.", bin);
return bin;
}
strlen does not give the size of the array.
This will not enlarge the memory:
bin = realloc(bin, strlen(bin)*sizeof(char)+1); //0+1 == 1
And then calling strlen on that memory will produce undefined behavior since the result strlen(bin) - 1 will be negative:
bin[strlen(bin) - 1] = (k % 2) + '0'; //bin[0-1]
In you case you should use an extra variable that keeps the size of the allocated memory.
sample to fix.
char* testBefore(int k){
char* bin;
int i = 0;
bin = calloc(1,1);
while(k > 0) {
bin = realloc(bin, (i+1)*sizeof(char)+1);
bin[i++] = (k % 2) + '0';
k = k / 2;
}
bin[i] = '\0';
printf("\n%s.", bin);//reversed
return bin;
}
char* bin;
bin = calloc(1,1);
Now bin points to a 1-byte space containing 0.
while(k > 0) {
bin = realloc(bin, strlen(bin)*sizeof(char)+1);
Not sure about what k would be. Anyway, strlen(bin) == 0 since bin[0] == '\0'.
Afterward, bin points to another 1-byte space storing 0.
bin[strlen(bin) - 1] = (k % 2) + '0';
Here strlen(bin) returns 0 again, and accessing bin[0-1] is obviously out-of-bound and thus undefined behavior happened.

Resources