numCheck is number between 1-1000. This code gives me a segfault only when I collect the results of sprintf in charcheck. If I simply use sprintf without using the results, I don't get a seg fault. What's happening here?
char * numString;
int charcheck = sprintf(numString, "%d", numCheck);
You need to provide your own memory for sprintf. Also, don't use sprintf, but rather snprintf:
char buf[1000] = {0};
snprintf(buf, 999, ....);
Alternatively you can allocate memory dynamically:
char * buf = new char[BUFSIZE];
snprintf(buf, BUFSIZE-1, ...);
/* ... */
delete[] buf;
The pointer given as the first parameter to sprintf is expected to point to a memory location where sprintf should write the formatted string.
In this case you didn't initialize numString to point to some memory you allocated for the formatted string. Since numString isn't initialized it might point anywhere, and in your case trying to write the formatted output to that location results in a segmentation fault.
The first argument to sprintf must point to a valid buffer. You have a char* but it points to garbage.
Change your code to:
char numString[80] = { };
int charcheck = sprintf(numString, "%d", numCheck);
So that numString actually points to a valid buffer (of 80 characters in this example, all elements of which are initialised to 0).
It would also be good to use snprintf so you can pass the size of your buffer to it, which will help prevent buffer overflows:
const int bufsize = 80;
char numString[bufsize] = { };
int charcheck = snprintf(numString, bufsize - 1, "%d", numCheck);
Notice that you subtract one from the buffer size that you pass to snprintf because you don't want it to use the very last slot, which you want to make sure is NULL to denote the end of the string.
You need to allocate space for the result such as
char numString[50];
int charcheck = sprintf(numString, "%d", numCheck);
In your case the interal workings of sprintf are trying to reference NULL which is the default value for a pointer in your case.
The most straightforward thing to do is to use an array as above, e.g.,
char numString[80] = { };
suggested by Seth, Jesus and Kerrek.
I think the last answer from sth is a good explanation: "the first parameter to sprintf is expected to point to a memory location where sprintf should write the formatted string." So apart from using an array of characters, which would force the allocation of memory for the string, you can also use this:
char *numstring = (char*) malloc(80);
This should let you explicitly free the allocated memory when it is no longer needed.
Related
I am trying to write a function to convert a text file into a CSV file.
The input file has 3 lines with space-delimited entries. I have to find a way to read a line into a string and transform the three lines from the input file to three columns in a CSV file.
The files look like this :
Jake Ali Maria
24 23 43
Montreal Johannesburg Sydney
And I have to transform it into something like this:
Jake, 24, Montreal
...etc
I figured I could create a char **line variable that would hold three references to three separate char arrays, one for each of the three lines of the input file. I.e., my goal is to have *(line+i) store the i+1'th line of the file.
I wanted to avoid hardcoding char array sizes, such as
char line1 [999];
fgets(line1, 999, file);
so I wrote a while loop to fgets pieces of a line into a small buffer array of predetermined size, and then strcat and realloc memory as necessary to store the line as a string, with *(line+i) as as pointer to the string, where i is 0 for the first line, 1 for the second, etc.
Here is the problematic code:
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#define CHUNK 10
char** getLines (const char * filename){
FILE *file = fopen(filename, "rt");
char **lines = (char ** ) calloc(3, sizeof(char*));
char buffer[CHUNK];
for(int i = 0; i < 3; i++){
int lineLength = 0;
int bufferLength = 0;
*(lines+i) = NULL;
do{
fgets(buffer, CHUNK, file);
buffLength = strlen(buffer);
lineLength += buffLength;
*(lines+i) = (char*) realloc(*(lines+i), (lineLength +1)*sizeof(char));
strcat(*(lines+i), buffer);
}while(bufferLength ==CHUNK-1);
}
puts(*(lines+0));
puts(*(lines+1));
puts(*(lines+2));
fclose(file);
}
void load_and_convert(const char* filename){
char ** lines = getLines(filename);
}
int main(){
const char* filename = "demo.txt";
load_and_convert(filename);
}
This works as expected only for i=0. However, going through this with GDB, I see that I get a realloc(): invalid pointer error. The buffer loads fine, and it only crashes when I call 'realloc' in the for loop for i=1, when I get to the second line.
I managed to store the strings like I wanted in a small example I did to try to see what was going on, but the inputs were all on the same line. Maybe this has to do with fgets reading from a new line?
I would really appreciate some help with this, I've been stuck all day.
Thanks a lot!
***edit
I tried as suggested to use calloc instead of malloc to initialize the variable **lines, but I still have the same issue.I have added the modifications to the original code I uploaded.
***edit
After deleting the file and recompiling, the above now seems to work. Thank you to everyone for helping me out!
You allocate line (which is a misnomer since it's not a single line), which is a pointer to three char*s. You never initialize the contents of line (that is, you never make any of those three char*s point anywhere). Consequently, when you do realloc(*(line + i), ...), the first argument is uninitialized garbage.
To use realloc to do an initial memory allocation, its first argument must be a null pointer. You should explicitly initialize each element of line to NULL first.
Additionally, *(line+i) = (char *)realloc(*(line+i), ...) is still bad because if realloc fails to allocate memory, it will return a null pointer, clobber *(line + i), and leak the old pointer. You instead should split it into separate steps:
char* p = realloc(line[i], ...);
if (p == null) {
// Handle failure somehow.
exit(1);
}
line[i] = p;
A few more notes:
In C, you should avoid casting the result of malloc/realloc/calloc. It's not necessary since C allows implicit conversion from void* to other pointer types, and the explicit could mask an error where you accidentally omit #include <stdlib.h>.
sizeof(char) is, by definition, 1 byte.
When you're allocating memory, it's safer to get into a habit of using T* p = malloc(n * sizeof *p); instead of T* p = malloc(n * sizeof (T));. That way if the type of p ever changes, you won't silently be allocating the wrong amount of memory if you neglect to update the malloc (or realloc or calloc) call.
Here, you have to zero your array of pointers (for example by using calloc()),
char **line = (char**)malloc(sizeof(char*)*3); //allocate space for three char* pointers
otherwise the reallocs
*(line+i) = (char *)realloc(*(line+i), (inputLength+1)*sizeof(char)); //+1 for the empty character
use an uninitialized pointer, leading to undefined behaviour.
That it works with i=0 is pure coindicence and is a typical pitfall when encountering UB.
Furthermore, when using strcat(), you have to make sure that the first parameter is already a zero-terminated string! This is not the case here, since at the first iteration, realloc(NULL, ...); leaves you with an uninitialized buffer. This can lead to strcpy() writing past the end of your allocated buffer and lead to heap corruption. A possible fix is to use strcpy() instead of strcat() (this should even be more efficient here):
do{
fgets(buffer, CHUNK, file);
buffLength = strlen(buffer);
lines[i] = realloc(lines[i], (lineLength + buffLength + 1));
strcpy(lines[i]+lineLength, buffer);
lineLength += buffLength;
}while(bufferLength ==CHUNK-1);
The check bufferLength == CHUNK-1 will not do what you want if the line (including the newline) is exactly CHUNK-1 bytes long. A better check might be while (buffer[buffLength-1] != '\n').
Btw. line[i] is by far better readable than *(line+i) (which is semantically identical).
Sorry. I really tried to solve this myself. But i don't understand. The statements ran okay when i place them in main. But when i call them in a function from main, segmentation fault happens. Does it mean memory overflowed?
void displayTime(char state[]) {
time_t totalSec = time(NULL);//total no of secs since EPOCH
struct tm *currTime = localtime(&totalSec); //store local time in struct declared in time.h
char *result;
strftime(result, 20, "%Y:%m:%d %H:%M:%S", currTime); //E.g. 2017:11:12 12:30:48 Max is 20 characters including \0
printf("Program at %s\n", result );
}
int main() {
displayTime("started");
return 0;
}
Allocate memory in result that is what is causing problem.
In your case it will be
result = malloc(sizeof(char)*BUFFSIZE);
if( result == NULL ){
fprintf(stderr,"Error");
exit(1);
}
There must be a corresponding free call to the allocated memory, here it will be
free(result);
Also accessing uninitialized variable is undefined behavior.
Also without malloc you can simply do this
char result[20];
strftime(result,20, "%Y:%m:%d %H:%M:%S", currTime);
Also my earlier edit with state is not possible. (Didn't notice that it's literal string) Since string literals belong to the read only section of memory. Now here we were trying to edit or modify it. That is wrong.
Secondly, even if it was not read only it will still not have memory to hold the characters that you would write. Because the size would not be big enough for that.
Further Explanation
To clarify the problem, look at the result variable. It is type char*. It is supposed to contain address of a char variable. Now when you declare it. Then it contains an indeterminate value.
Does it point to anything meaningful? No.
Now when you pass the variable to the function it tries to write something to a location whose address is contained in result variable. But it is not something useful and you will try to access some memory which is not even meant for you.(not permitted).
Segfaults are caused by a program trying read or write an illegal memory location.
That's what happened in your case.
Does it mean memory overflowed?
No. It has nothing to do with overflow.
Also what is the purpose of the state in your code? You are not using it anywhere in the code. You can avoid it.
//char * result; // this is just a pointer with no memory to point to
char result[256] = {0,}; // now this will work
strftime(result, 20, "%Y:%m:%d %H:%M:%S", currTime);//E.g. 2017:11:12 12:30:48 Max is 20 characters including \0
alternatively
//char * result; // this is just a pointer with no memory to point to
char *result = malloc( 256 * sizeof(char));
if( result )
{
strftime(result, 20, "%Y:%m:%d %H:%M:%S", currTime);//E.g. 2017:11:12 12:30:48 Max is 20 characters including \0
}
I need to use sprintf in an string with a previously unknown size.
This works, but generates a warning/error in the console.
What is wrong here?
// request a dummy size
char* str = (char *)malloc(2);
// first pass, just to get the final size
int size = sprintf(str,"init_display(%d,%d,%d,%d,%s)",width,height,glwidth,glheight,title);
// realloc to correct size
str = (char *)realloc(str,sizeof(char)*size);
// second pass , get the full string
sprintf(str,"init_display(%d,%d,%d,%d,%s)",width,height,glwidth,glheight,title);
// free after use
free(str);
This generate 2 errors:
Error in "foo" realloc(): invalid next size: 0x00007f6dc8009b70 ***
Error in "foo" free(): invalid next size (fast): 0x00007f6dc8009b70 ***
There are actually two problems in your code. First of all, your fist call to sprintf writes to a memory region too small. Doing that invokes undefined behavior which means that anything can start misbehaving and it does. The second one is that after realloc call the memory region is still not large enough - there is no place for ending \0 character.
In order to fix that, use snprint, which is almost like sprintf but it takes one additional argument - size of allocated memory. It never writes more than this amount of characters to the buffer. It still, however, returns the number of characters that would be written if the buffer was large enough. Now, you can use realloc to resize the buffer to one more byte than the returned value.
Note that if you happen to use gcc and you don't care for portable code, you may use asprintf instead.
You can use snprintf() to find out how much space you need.
In Visual Studio there is _snprintf():
char* str;
// get the size
int size = _snprintf(NULL,0,"init_display(%d,%d,%d,%d,%s)",width,height,glwidth,glheight,title);
// allocate memory
str = (char *)malloc(size+1);
// get the string
sprintf(str,"init_display(%d,%d,%d,%d,%s)",width,height,glwidth,glheight,title);
// free after use
free(str);
sprintf(str,"init_display(%d,... over writes the 2 char allocation of str.
If one does not want to sprintf() twice, consider a buffer that is certainly over-sized, then realloc().
static const char format[] = "init_display(%d,%d,%d,%d,%s)";
size_t siz = sizeof(format) + 4*(sizeof(int)*CHAR_BIT/3 + 3) + strlen(title) + 1;
char *str = malloc(siz);
assert(str != NULL);
siz = sprintf(str, format, width, height, glwidth, glheight, title) + 1;
char *str2 = realloc(str, siz);
assert(str2);
str = str2;
// free after use
free(str);
#Krzysztof Adamski answer is less error prone as with this approach, code needs to absolutely correctly calculate the maximum buffer size.
I am not so clear on character pointer and how they work.
The program builds, but crashes when I run it.
char *ab = NULL;
//ab = "abc123"; // works fine
sprintf(ab, "abc%d", 123); // this line seems to crash the program
I don't get how this can be wrong, when sprintf takes in a (char * str) as a first argument.
Can anyone please explain this to me?
You have allocated no memory to use with ab.
The first assignment works because you are assigning to ab a string constant: "abc123". Memory for constant strings are provided by the compiler on your behalf: you don't need to allocate this memory.
Before you can use ab with e.g. sprintf, you'll need to allocate some memory using malloc, and assign that space to ab:
ab = malloc(sizeof(char) * (NUM_CHARS + 1));
Then your sprintf will work so long as you've made enough space using malloc. Note: the + 1 is for the null terminator.
Alternately you can make some memory for ab by declaring it as an array:
char ab[NUM_CHARS + 1];
Without allocating memory somehow for ab, the sprintf call will try to write to NULL, which is undefined behavior; this is the cause of your crash.
You can do this
char ab[10]; //allocate memory
sprintf(ab, "abc%d", 123);
You need to allocate memory for your data. Indeed sprintf takes char*, but it doesn't allocate memory for you.
The first line works fine because compiler automatically allocates data for constant tables of chars defined at compile time.
Unlike in Java or other higher level languages, many of the C library's string functions don't simply set a string reference, instead they operate on a block of pre-allocated memory called a character array.
Your first line is saying that ab points to a non-existent memory location.
You'd have more luck if, instead of char *ab = NULL; you did either:
char ab[12];
or:
char *ab = (char*)malloc(12);
"ab" is null and sprintf is trying to write to it, you have to allocate it first.
char ab[20];
sprintf(ab, "abc%d", 123); //
or
char * ab = malloc(20); // new, whatever
sprintf(ab, "abc%d", 123); //
There are several things to think about here. Your original example is below:
char *ab = NULL;
//ab = "abc123"; // works fine
sprintf(ab, "abc%d", 123); // this line seems to crash the program
char *ab = NULL; is a pointer to a character and is initialized to NULL;
I don't think ab = "abc123"; worked fine unless it looked like char *ab = "abc123";. That is because you initialized char *ab to a read-only string. The initialization probably took place at compile time.
Your sprintf(ab, "abc%d", 123); line failed, because you did not initialize any memory for the char *ab pointer ahead of time. In other words, you did not do something like:
ab = malloc((sizeof(char) * 3) + 1); /* + 1 allows for null string terminator. */
You can fix your problem one of two ways. Either allocate dynamic memory as shown above, or you can make the string an array of a fixed length, like char ab[25] = {0};. Usually, I create an array of a length like 1024, 256, or some number that will usually cover most of my string length cases. Then I use char pointers for functions that operate on the array.
Here is my code :
char *name, name_log="log-";
------getting 'name' from user-----
strcat(name_log, name);
char ext[] = ".log";
strcat(name_log, ext);
What i need to end up with is name_log = "log-'name'.log" but Im getting a segmentation fault error :((. What am I doing wrong and how can I fix it ? Thx
For a start, if this is your code:
char *name, name_log="log-";
then name_log is a char, not a char pointer.
Assuming that's a typo, you cannot append to string literals like that. Modifications to string literals are undefined behaviour.
For a variable sized string, as user appears to be, probably the safest option is to allocate another string large enough to hold the result, something like:
char *name, *name_log = "log-", *ext = ".log";
// Do something to allocate and populate name
char *buffer = malloc (strlen (name_log) + strlen (name) + strlen (ext) + 1);
if (buffer == NULL) {
// Out of memory.
} else {
strcpy (buffer, name_log);
strcat (buffer, name);
strcat (buffer, ext);
// Do something with buffer.
free (buffer);
}
The malloc ensures you have enough space to do all the string operations safely, enough characters for the three components plus a null terminator.
string literals get allocated a fixed amount of memory, generally in a read only section, you instead need to use a buffer.
char buffer[64] = "log-";
strncat(buffer,".log",32);
On a side note, strcat is generally unsafe, you need to use something that that checks the size of the buffer it uses or with limits on what it can concatenate, like strncat.
A completely different solution would be this:
const char *prefix = "log-";
const char *suffix = ".log";
// There's a "char *name" somewhere
int size_needed;
char *result;
size_needed = snprintf(NULL, 0, "%s%s%s", prefix, name, suffix);
result = malloc(size_needed + 1);
snprintf(result, size_needed + 1, "%s%s%s", prefix, name, suffix);
// "result" now contains the desired string.
The nice thing about snprintf is that it returns the number of characters it would write if there was enough space. This can be used by measuring upfront how much memory to allocate which makes complicated and error-prone calculations unnecessary.
If you happen to be on a system with asprintf, it's even easier:
char *result = NULL /* in case asprintf fails */;
asprintf(&result, "log-%s.log", name);
// "result" must be released with "free"
you need to allcocate memory. You cannot add to a string in this way as the string added goes to memory which hasnt been allocated.
you can do
char[20] strarray;
strcat(strarray, "log-");
strcat(strarray, "abcd");
the name_log is pointed at a static place: "log-", which means is could not be modified, while as the first parameter in strcat(), it must be modifiable.
try changing name_log's type char* into char[], e.g.
char[20] name_log = "log-";