why is free() adding weired character on a string pointer in c? - c

I'm new to C language, less than two months old, but i have been experiencing a problem with malloc, realloc and free. I was writting a code to print numbers on stdout, and my method was, converting it to a string first and then printing it. Here is my code;(count is for keeping record of char printed.)
int print_num(int num, int count)
{
int i = 0, len;
char last, *ptr2, *ptr = (char *)malloc(sizeof(char));
if (num == 0)
return (print_char('0', count));
if (num < 0)
count = print_char('-', count);
num = abs(num);
while (num != 0)
{
last = (num % 10) + '0';
if (i == 0)
*(ptr) = last;
else
{
ptr2 = (char *)realloc(ptr, i + 1);
*(ptr2 + i) = last;
ptr = ptr2;
}
num /= 10;
i++;
}
len = strlen(ptr);
for (i = len; i > 0; i--)
count = print_char(ptr[i - 1], count);
free(ptr);
return (count);
}
The problem is that, the code works fine without free(ptr)or free(ptr2). When i call the function more than once in another function, i get weired char at the end of the string pointer ptr.
Example when printing two numbers in a row
print_num(39, 0)
print_num(39, 0)
i get
Length:[39, U�39]
when i delete free(ptr), the code works fine, but their will be a memory leak.
How can i make this work?
int print_char(char c, int count)
{
write(1, &c, 1);
return (count + 1);
}

You're using strlen on an array of bytes that isn't a string.
A string in C is a null terminated sequence of characters. You build up an array of characters in the memory pointed to by ptr, but don't add a terminating null byte. This by itself isn't a problem, but then you call strlen on it which expects a null terminated string. This results in the function reading past the end of allocated memory, triggering undefined behavior.
You already have the length of the array stored in i, so there's no need to call strlen. Just use that.
len = i;

Related

C append chars into char array one by one

I have made up a function which returns some chars , all I want to do is to append all those returned chars into one string .
#include <stdio.h>
#include <string.h>
char func(int n);
int main()
{
int i;
char str[] = "";
size_t p = strlen(str);
for (i =0 ; i < 5; i++){
str[p++] = func(i);
str[p] = '\0';
p++;
}
printf("%s",str);
return 0;
}
char func(int n){
if (n == 0)
return '1';
if (n == 1)
return '2';
if (n > 1)
return '3';
}
//EDIT Output for this is 19
char func(n){
if (n == 0)
return '1';
if (n == 1)
return '2';
if (n > 1)
return '3';
}
You should always specify the type for variables.
Please use something like int n instead of just n.
It's also bad that all of your returns are conditional, it's better to have a return statement that's guaranteed to be executed no matter what *:
char func(int n) {
if (n == 0) return '1';
if (n == 1) return '2';
return '3';
}
* Because not returning a value from a function that should return a value is undefined behaviour.
Now that we have that out of the way, let's have a look at your main():
int main() {
int i;
char str[] = "";
size_t p = strlen(str);
for (i =0 ; i < 5; i++){
str[p++] = func(i);
str[p] = '\0';
p++;
}
printf("%s",str);
return 0;
}
str[] is not big enough to store all the characters you write to it, resulting in undefined behaviour.
Your loop body is written in a weird way, why are you incrementing p twice?
Here a very simple program that writes 5 characters into str:
#include <stdio.h>
char func(int n) {
if (n == 0) return '1';
if (n == 1) return '2';
return '3';
}
int main() {
int i;
// Allocate 6 bytes (5 characters) on the stack
char str[6] = "";
for (i = 0 ; i < 5; i++) {
str[i] = func(i);
}
// Strings *must* be NULL terminated in C
str[5] = 0;
printf("%s",str);
return 0;
}
The size of your str here is "0" (0 using the strlen and 1 using the sizeof operator because it counts the '\0' caracter) so you can not add more element to the str, and if you try, the program will crash. So you have two possibilies here, the first is to declare a fixed table size and the number n will be limited by the size, the second is a dynamic one using mallic. To intialize it to zeros you can just use the memset API.
Well short answer is everything you did would be right if you have in the array enough memory to hold those 5 characters and the \0 if you want to treat it as a string (NUL terminated char array).
"" is a string literal containing only the \0. Length of this string is 0. What about the array? Applying sizeof over it reveals that it is capable of holding one character. (Well it contained \0).
Now with your code you surely did access positions that are beyond the size of the array. This is undefined behavior - mentioned by the C standard.
Solution is to either have an array having size capable of holding the maximum character you would like to store someday. Or you can have a char* to which you can assign address of allocated chunk by using functions like malloc,realloc etc. Benefit of this, you can increase memory as much as you need on runtime depending on the number of characters you want to store.

Segmentation fault at base converting in C

trying to convert dec to 32-base, and then print it to a file.
const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
char* baseConverter(int num, int base)
{ char* res;
int i=0;
if (num == 0 || base == 10)
{
snprintf(res,"%03x",num);
return *res;
}
while( num > 0 )
{
*(res+i) = digits[num%base];
num=num/base;
}
return *res;
}
and then at the output code :
sprintf(line, "%03s", baseConverter(i, 32);
but I keep getting that Segmentation fault (core dumped) error at running.
There are several things going on here:
First an uninitialised local pointer has an indeterminate value; it doesn't point anywhere in particular. The NULL pointer doesn't point anywhere either, but at least you can test for a NULL pointer easily. Make a habit of initalising a pointer to make it point to valid memory or to make it explicitly null.
The pointer is supposed to point to a char buffer. The way your function looks like, you must allocate memory for that buffer on the heap with malloc. (You can't use local storage, because that would be invalidated immediately.)
Don't make base 10 a special case. (You're even doing it wrong by printing base 10 numbers as hex.)
Your method of printing is okay, but you print the number backwards. So determine the required klength first and then decrement the position you print at.
Here, you deal with the raw characters. Use res[i] rather than do complicated things with the standard library functions. In particular, don't build strings by concatenating or printing strings to themselves. That's very likely undefined behaviour.
A possible implementation of your function could look like:
int ndigits(int num, int base)
{
int n = 0;
while (num) {
n++;
num /= base;
}
if (n == 0) n++;
return n;
}
char* baseConverter(int num, int base)
{
if (num >= 0 && base > 1 && base <= 36) {
int n = ndigits(num, base);
char *res = malloc(n + 1);
int i = n;
res[n] = '\0';
if (num == 0) res[--i] = '0';
while (num) {
res[--i] = digits[num % base];
num /= base;
}
return res;
}
return NULL;
}
Note how an auxiliary function is used to determine the length of the string. The string is then filled backwards, staring with the null terminator. Also note how invalid cases are handled by returning NULL.
Your calling code must explicitly free the string after using it:
int n = rand() % 100000 + 1;
int m = rand() % 10 + 2;
char *p = baseConverter(n, m);
if (p) printf("%d#%d == %s\n", n, m, p);
free(p);
C has manual memory management and keeping track of allocated stuff is tedious. You can't, for example, call baseConverter from inside printf, because you'd lose the handle to the allocated string.
Another popular variant is to have the calling code allocate the memory and then pas a buffer and its size to the function to fill it. A prototype could then look like this:
void sbase(char buf, size_t buflen, int num, int base);
It would then be called like this:
char buf[33]; // Maximum, when base 2 is printed
sbase(buf, sizeof(buf), 5000, 13);
puts(buf);
Because buf is an automatic variable, no freeing is to be done. (How to implement thins and how to properly enforce that the buffer size isn't exceeded is left as an exercise. :))
The main errors have already been pointed out.
Here is another suggested routine (it doesn't require malloc)
The function sets the value of a pointer to the number of converted digits, to make it easy to print out the required digits.
#include <stdio.h>
/* function takes pointer to array, size of array + number/base
and pointer for number of digits in conversion */
void make32(int *res32, int len, int num, int base, int *rln);
int main()
{
int digits32[20]; // size according to max conversion number in base 32
int len32 = sizeof(digits32)/sizeof(digits32[0]);
int in32, resln, n;
/* convert this number */
in32 = 10000;
/* call function with pointer + size & number/base & ptr to # converted digits*/
make32(digits32, len32, in32, 32, &resln);
/* print out result - reverse order - use number of digits */
for(n = resln; n >= 0; n--) {
printf("%d ", digits32[n]);
}
printf("\n");
return (0);
}
void make32(int *res32, int len, int num, int base, int *rln)
{
int i = 0;
while( num > 0 && i <= len ) {
res32[i] = num % base;
num = num / base;
i++;
}
/* set the number of converted digits */
*rln = i - 1;
}

Creating a string in C of the form "1,2,3,4,5"

I'm having difficulty in generating a string of the form "1,2,3,4,5" to pass to a command line program.
Here's what I have tried:
int N=100;
char list[200];
for (i=0; i<2*N; i+=2) {
char tmp;
sprintf(tmp,'%d', i);
strcpy(list[i], tmp);
strcpy(list[i+1], ',');
}
Edit:
I don't feel this question is a duplicate as it is more to do with appending strings into a list and managing that memory and than literally just putting a comma between to integers.
The following code will do what you need.
#include <stdlib.h>
#include <stdio.h>
char* CommaSeparatedListOfIntegers(const int N)
{
if (N < 1)
return NULL;
char* result = malloc(1 + N*snprintf(NULL, 0, "%d,", N));
char* p = result;
for (int i = 1; i <= N; i++)
p += sprintf(p, "%d,", i);
*(p-1) = '\0';
return result;
}
Note that the function returns a heap allocated block of memory that the caller is responsible for clearing up.
Some points of note:
We put a crude upper bound on the length of each number when converted to text. This does mean that we will over allocate the block of memory, but not by a massive amount. If that is a problem for you then you can code a more accurate length. That would involve looping from 1 to N and calling snprintf for each value to determine the required length.
Note that we initially write out a comma after the final value, but then replace that with the null-terminator.
Let's forget about writing strings for the moment and write a function that just prints that list to the screen:
int range_print(int begin, int end, const char *sep)
{
int len = 0;
int i;
for (i = begin; i < end; i++) {
if (i > begin) {
len += printf("%s", sep);
}
len += printf("%d", i);
}
return len;
}
You can call it like this:
range_print(1, 6, ", ");
printf("\n");
The function does not write a new-line character, so we have to do that. It prints all numbers and a custom separator before each number after the first. The separator can be any string, so this function also works if you want to separate your numbers with slashes or tabs.
The function has printf semantics, because it returns the number of characters written. (That value is often ignored, but it can come in handy, as we'll see soon.) We also make the upper bound exclusive, so that in order to print (1, 2, 3, 4, 5) you have tp pass 1 and 6 as bounds.
We'll now adapt this function so that it writes to a string. There are several ways to do that. Let's look at a way that works similar to snprintf: It should tabe a pre-allocated char buffer, a maximum length and it should return the number of characters written or, if the output doesn't fit, the number of characters that would have been written had the buffer been big enough.
int range(char *buf, int n, int begin, int end, const char *sep)
{
int len = 0;
int m, i;
for (i = begin; i < end; i++) {
m = snprintf(buf, n, "%s%d",
(i > begin) ? sep : "", i);
len += m;
buf += m;
n -= m;
if (n < 0) n = 0;
}
return len;
}
This function is tricky because it has to keep track of the number of characters written and of the free buffer still available. It keeps printing after the buffer is full, which is a bit wasteful in terms of performace, but it is legal to call snprintf with a buffer size of zero, and that way we keep the semantics tidy.
You can call this function like this:
char buf[80];
range(buf, sizeof(buf), 1, 6, ", ");
printf("%s\n", buf);
That means that we need to define a buffer that is large enough. If the range of numbers is large, the string will be truncated. We might therefore want a function that allocates a string for us that is long enough:
char *range_new(int begin, int end, const char *sep, int *plen)
{
int len = (end - begin - 1) * strlen(sep) + 1;
char *str;
char *p;
int i;
for (i = begin; i < end; i++) {
len += snprintf(NULL, 0, "%d", i);
}
str = malloc(len);
if (str == NULL) return NULL;
p = str;
for (i = begin; i < end; i++) {
if (i > begin) p += sprintf(p, "%s", sep);
p += sprintf(p, "%d", i);
}
if (plen) *plen = len - 1;
return str;
}
This function needs two passes: in the first pass, we determine how much memory we need to store the list. Next, we allocate and fill the string. The function returns the allocated string, which the user has to free after use. Because the return value is already used, we lose the information on the string length. An additional argument, a pointer to int, may be given. If it is not NULL, the length will be stored.
This function can be called like this.
char *r;
int len;
r = range_new(1, 6, ", ", &len);
printf("%s (%d)\n", r, len);
free(r);
Note that the same can be achieved by calling our old range function twice:
char *r;
int len;
len = range(NULL, 0, 1, 6, ", ");
r = malloc(len + 1);
range(p, len + 1, 1, 6, ", ");
printf("%s (%d)\n", r, len);
free(r);
So, pick one. For short ranges, I recommend the simple range function with a fixed-size buffer.

C program using strcat keeps giving unexpected output at runtime

I am trying to create a program that is able to rotate at point k, defined as the "rotation requested."
Example: rotate("derp", 3) => pder
My code for this function is called rotate, as listed below. It takes in both a char pointer array, startString, as defined in my main, and the number of rotations (A long int because I use atol to get the integer from the command line).
int rotate(char *startString, long int rotations) {
char *doubleString = malloc((sizeof startString * 2) + sizeof(char));
strcat(doubleString, startString);
strcat(doubleString, startString);
long int stringSize = (sizeof startString - 1);
long int breakIndex = (rotations % stringSize);
char* rotatedString = malloc((sizeof startString + sizeof(char)));
int i;
for (i = 0; i < stringSize + 1; i++) {
char pushedCharacter = doubleString[(int)breakIndex + i];
strcat(rotatedString, &pushedCharacter);
}
printf("%s\n", rotatedString);
printf("%s\n", doubleString);
return 0;
}
But, when I output, if I use something like doghouse I get a weird ?4??? in front of the output for the rotatedString. It also completely doesn't work for derp, instead printing out pderp with the same ?4??? in front. Where is this runtime error being caused?
EDIT
The answer given was correct, but the goal was to be able to accept rotations greater than the length of the given string. That code is below:
void rotate(char * startString, long int rotations) {
long int stringSize = strlen(startString);
long int breakIndex = (rotations % stringSize);
char *rotatedString = malloc(stringSize + 1); //counting extra char for null terminator
strncpy(rotatedString, startString + breakIndex, stringSize - breakIndex);
strncpy(rotatedString + stringSize - breakIndex, startString, breakIndex);
rotatedString[stringSize] = '\0'; // for the ending null character of the char array
printf("Result: %s\n", rotatedString);
free(rotatedString);
}
Your doublestring initialization allocates too little memory because you're using sizeof(startstring), which is the size of a pointer, not strlen(startstring) + 1 which is the length of the string including the terminating NUL character. This means your code is overwriting the end of the buffer with hilarous results. Try the following:
void rotate(char * startString, int rotation) {
int len = strlen(startString);
if (len == 0 || len <= rotation)
return;
char *rotatedString = malloc(len + 1); /* One extra char for the terminating NUL */
strncpy(rotatedString, startString + rotation, len - rotation);
strncpy(rotatedString + len - rotation, startString, rotation);
rotatedString[len] = '\0';
printf("%s\n", rotatedString);
free(rotatedString); /* don't leak memory! */
}

Segmentation fault on strlen(char*) but char* IS terminated

I've got a very very simple function which simply converts a char to a char* which represents the binary value of the char with 0's and 1's as chars.
char* stringToBin(char symbol) {
int pos = 0;
int value = (int) symbol;
int rest;
char* result = (char*) malloc(sizeof(char) * 9);
while(value > 0) {
if(value % 2 == 0) {
result[7-pos] = '0';
}
else {
result[7-pos] = '1';
}
pos++;
value = value / 2;
}
while(pos < 8) {
result[7-pos] = '0';
pos++;
}
result[8] = '\0';
puts(result);
puts(strlen(result));
return result;
}
My problem is I can't print the length of the char*. Printing the whole char* works perfect but not calculating the size. I alway get a segmentation fault. I think the problem is pretty simple but I did not get it right now. So please give me the missing hint ;)
The problem is not with the NUL-termination of your string, that's fine. Instead,
puts(strlen(result));
is wrong. puts() expects a C string, and you're giving it a size_t. Write instead:
printf("%zu\n", strlen(result));
(This assumes that the C99 format specifier %zu for size_t is available. If it isn't, then use:
printf("%u\n", (unsigned)strlen(result));
instead.)

Resources