realloc missunderstanding - c

Can somebody explain to me, why this block of code does not work. I was looking through some of questions around but failed finding the answer. Probably because of (huge) lack of knowledge.
Thank you for any given help.
char** sentence = malloc(min);
char* temp = malloc(min2);
int i = 0;
while(i<5)
{
sentence = realloc(sentence, i+2);
scanf("%s", temp);
sentence[i] = malloc(strlen(temp));
strcpy(sentence[i], temp);
printf("%s\n", sentence[i]);
i++;
}

You forgot to account for the fact that strings have null terminators.

sentence[i] = malloc(strlen(temp));
Should be:
sentence[i] = malloc(strlen(temp)+1);
You need enough space both for the length of the string (strlen) AND also for its null-terminator.

sentence = realloc(sentence, (i+1) * sizeof(*sentence));
would make more sense: you're trying to store i+1 char*s, not i+2 bytes.
BTW, you can just replace the malloc/strlen/strcpy with:
sentence[i] = strdup(temp);
(that takes care of the nul terminator for you).

sentence = realloc(sentence, i+2);
is a common anti-pattern. If realloc returns NULL, you've just leaked sentence. Instead you need to write
temp = realloc(sentence, i+2);
if(temp == NULL)
// out of memory - do something here
sentence = temp;
To make life worse, you're using
using scanf which is a common cause of security errors
using strcpy which is a common cause of security errors
not checking the result of any of your mallocs to see if it returns NULL (if it doesn't you'll get a write-access violation)
Not adding +1 to the strlen() before calling malloc, and hence getting a 1-byte heap-overflow from the strcpy.
And using a while loop where a for loop would clearly be more appropriate.
Apart from those six security bugs, you're doing well though.

Related

Trouble \0 null terminating a string (C)

I seem to have some trouble getting my string to terminate with a \0. I'm not sure if this the problem, so I decided to make a post.
First of all, I declared my strings as:
char *input2[5];
Later in the program, I added this line of code to convert all remaining unused slots to become \0, changing them all to become null terminators. Could've done with a for loop, but yea.
while (c != 4) {
input2[c] = '\0';
c++;
}
In Eclipse when in debug mode, I see that the empty slots now contain 0x0, not \0. Are these the same things? The other string where I declared it as
char input[15] = "";
shows \000 when in debug mode though.
My problem is that I am getting segmentation faults (on Debian VM. Works on my Linux 12.04 though). My GUESS is that because the string hasn't really been terminated, the compiler doesn't know when it stops and thus continues to try to access memory in the array when it is clearly already out of bound.
Edit: I will try to answer all other questions soon, but when I change my string declaration to the other suggested one, my program crashes. There is a strtok() function, used to chop my fgets input into strings and then putting them into my input2 array.
So,
input1[0] = 'l'
input1[1] = 's'
input1[2] = '\n'
input2[0] = "ls".
This is a shell simulating program with fork and execvp. I will post more code soon.
Regarding the suggestion:
char *input2[5]; This is a perfectly legal declaration, but it
defined input2 as an array of pointers. To contain a string, it needs
to be an array of char.
I will try that change again. I did try that earlier, but I remember it giving me another run-time error (seg fault?). I think it is because of the way I implemented my strtok() function though. I will check it out again. Thanks!
EDIT 2: I added a response below to update my progress so far. Thanks for all the help!
It is here.
.
You code should rather look like this:
char input2[5];
for (int c=0; c < 4; c++) {
input2[c] = '\0';
}
0x0 and \0 are different representation of the same value 0;
Response 1:
Thanks for all the answers!
I made some changes from the responses, but I reverted the char suggestion (or correct string declaration) because like someone pointed out, I have a strtok function. Strtok requires me to send in a char *, so I reverted back to what I originally had (char * input[5]). I posted my code up to strtok below. My problem is that the program works fine in my Ubuntu 12.04, but gives me a segfault error when I try to run it on the Debian VM.
I am pretty confused as I originally thought the error was because the compiler was trying to access an array index that is already out of bound. That doesn't seem like the problem because a lot of people mentioned that 0x0 is just another way of writing \000. I have posted my debug window's variable section below. Everything seems right though as far as I can see.. hmm..
Input2[0] and input[0], input[1 ] are the focus points.
Here is my code up to the strtok function. The rest is just fork and then execvp call:
int flag = 0;
int i = 0;
int status;
char *s; //for strchr, strtok
char input[15] = "";
char *input2[5];
//char input2[5];
//Prompt
printf("Please enter prompt:\n");
//Reads in input
fgets(input, 100, stdin);
//Remove \n
int len = strlen(input);
if (len > 0 && input[len-1] == '\n')
input[len-1] = ' ';
//At end of string (numb of args), add \0
//Check for & via strchr
s = strchr (input, '&');
if (s != NULL) { //If there is a &
printf("'&' detected. Program not waiting.\n");
//printf ("'&' Found at %s\n", s);
flag = 1;
}
//Now for strtok
input2[i] = strtok(input, " "); //strtok: returns a pointer to the last token found in string, so must declare
//input2 as char * I believe
while(input2[i] != NULL)
{
input2[++i] = strtok( NULL, " ");
}
if (flag == 1) {
i = i - 1; //Removes & from total number of arguments
}
//Sets null terminator for unused slots. (Is this step necessary? Does the C compiler know when to stop?)
int c = i;
while (c < 5) {
input2[c] = '\0';
c++;
}
Q: Why didn't you declare your string char input[5];? Do you really need the extra level of indirection?
Q: while (c < 4) is safer. And be sure to initialize "c"!
And yes, "0x0" in the debugger and '\0' in your source code are "the same thing".
SUGGESTED CHANGE:
char input2[5];
...
c = 0;
while (c < 4) {
input2[c] = '\0';
c++;
}
This will almost certainly fix your segmentation violation.
char *input2[5];
This is a perfectly legal declaration, but it defined input2 as an array of pointers. To contain a string, it needs to be an array of char.
while (c != 4) {
input2[c] = '\0';
c++;
}
Again, this is legal, but since input2 is an array of pointers, input2[c] is a pointer (of type char*). The rules for null pointer constants are such that '\0' is a valid null pointer constant. The assignment is equivalent to:
input2[c] = NULL;
I don't know what you're trying to do with input2. If you pass it to a function expecting a char* that points to a string, your code won't compile -- or at least you'll get a warning.
But if you want input2 to hold a string, it needs to be defined as:
char input2[5];
It's just unfortunate that the error you made happens to be one that a C compiler doesn't necessarily diagnose. (There are too many different flavors of "zero" in C, and they're often quietly interchangeable.)

Why doesn't strcpy work?

char sentence2[10];
strncpy(sentence2, second, sizeof(sentence2)); //shouldn't I specify the sizeof(source) instead of sizeof(destination)?
sentence2[10] = '\0'; //Is this okay since strncpy does not provide the null character.
puts(sentence2);
//////////////////////////////////////////////////////////////
char *pointer = first;
for(int i =0; i < 500; i++) //Why does it crashes without this meaningless loop?!
{
printf("%c", *pointer);
if(*pointer == '\n')
putchar('\n');
pointer++;
}
So here's the problem. When I run the first part of this code, the program crashes.
However, when I add the for loop that just prints garbage values in memory locations, it does not crash but still won't strcpy properly.
Second, when using strncpy, shouldn't I specify the sizeof(source) instead of sizeof(destination) since I'm moving the bytes of the source ?
Third, It makes sense to me to add the the null terminating character after strncpy, since I've read that it doesn't add the null character on its own, but I get a warning that it's a possible out of bounds store from my pelles c IDE.
fourth and most importantly, why doesn't the simply strcpy work ?!?!
////////////////////////////////////////////////////////////////////////////////////
UPDATE:
#include <stdio.h>
#include <string.h>
void main3(void)
{
puts("\n\n-----main3 reporting for duty!------\n");
char *first = "Metal Gear";
char *second = "Suikoden";
printf("strcmp(first, first) = %d\n", strcmp(first, first)); //returns 0 when both strings are identical.
printf("strcmp(first, second) = %d\n", strcmp(first, second)); //returns a negative when the first differenet char is less in first string. (M=77 S=83)
printf("strcmp(second, first) = %d\n", strcmp(second, first)); //returns a positive when the first different char is greater in first string.(M=77 S=83)
char sentence1[10];
strcpy(sentence1, first);
puts(sentence1);
char sentence2[10];
strncpy(sentence2, second, 10); //shouldn't I specify the sizeof(source) instead of sizeof(destination).
sentence2[9] = '\0'; //Is this okay since strncpy does not provide the null character.
puts(sentence2);
char *pointer = first;
for(int i =0; i < 500; i++) //Why does it crashes without this nonsensical loop?!
{
printf("%c", *pointer);
if(*pointer == '\n')
putchar('\n');
pointer++;
}
}
This is how I teach myself to program. I write code and comment all I know about it so that
the next time I need to look up something, I just look at my own code in my files. In this one, I'm trying to learn the string library in c.
char *first = "Metal Gear";
char sentence1[10];
strcpy(sentence1, first);
This doesn't work because first has 11 characters: the ten in the string, plus the null terminator. So you would need char sentence1[11]; or more.
strncpy(sentence2, second, sizeof(sentence2));
//shouldn't I specify the sizeof(source) instead of sizeof(destination)?
No. The third argument to strncpy is supposed to be the size of the destination. The strncpy function will always write exactly that many bytes.
If you want to use strncpy you must also put a null terminator on (and there must be enough space for that terminator), unless you are sure that strlen(second) < sizeof sentence2.
Generally speaking, strncpy is almost never a good idea. If you want to put a null-terminated string into a buffer that might be too small, use snprintf.
This is how I teach myself to program.
Learning C by trial and error is not good. The problem is that if you write bad code, you may never know. It might appear to work , and then fail later on. For example it depends on what lies in memory after sentence1 as to whether your strcpy would step on any other variable's toes or not.
Learning from a book is by far and away the best idea. K&R 2 is a decent starting place if you don't have any other.
If you don't have a book, do look up online documentation for standard functions anyway. You could have learnt all this about strcpy and strncpy by reading their man pages, or their definitions in a C standard draft, etc.
Your problems start from here:
char sentence1[10];
strcpy(sentence1, first);
The number of characters in first, excluding the terminating null character, is 10. The space allocated for sentence1 has to be at least 11 for the program to behave in a predictable way. Since you have already used memory that you are not supposed to use, expecting anything to behave after that is not right.
You can fix this problem by changing
char sentence1[10];
to
char sentence1[N]; // where N > 10.
But then, you have to ask yourself. What are you trying to accomplish by allocating memory on the stack that's on the edge of being wrong? Are you trying to learn how things behave at the boundary of being wrong/right? If the answer to the second question is yes, hopefully you learned from it. If not, I hope you learned how to allocate adequate memory.
this is an array bounds write error. The indices are only 0-9
sentence2[10] = '\0';
it should be
sentence2[9] = '\0';
second, you're protecting the destination from buffer overflow, so specifying its size is appropriate.
EDIT:
Lastly, in this amazingly bad piece of code, which really isn't worth mentioning, is relevant to neither strcpy() nor strncpy(), yet seems to have earned me the disfavor of #nonsensicke, who seems to write very verbose and thoughtful posts... there are the following:
char *pointer = first;
for(int i =0; i < 500; i++)
{
printf("%c", *pointer);
if(*pointer == '\n')
putchar('\n');
pointer++;
}
Your use of int i=0 in the for loop is C99 specific. Depending on your compiler and compiler arguments, it can result in a compilation error.
for(int i =0; i < 500; i++)
better
int i = 0;
...
for(i=0;i<500;i++)
You neglect to check the return code of printf or indicate that you are deliberately ignoring it. I/O can fail after all...
printf("%c", *pointer);
better
int n = 0;
...
n = printf("%c", *pointer);
if(n!=1) { // error! }
or
(void) printf("%c", *pointer);
some folks will get onto you for not using {} with your if statements
if(*pointer == '\n') putchar('\n');
better
if(*pointer == '\n') {
putchar('\n');
}
but wait there's more... you didn't check the return code of putchar()... dang
better
unsigned char c = 0x00;
...
if(*pointer == '\n') {
c = putchar('\n');
if(c!=*pointer) // error
}
and lastly, with this nasty little loop you're basically romping through memory like a Kiwi in a Tulip field and lucky if you hit a newline. Depending on the OS (if you even have an OS), you might actually encounter some type of fault, e.g. outside your process space, maybe outside addressable RAM, etc. There's just not enough info provided to say actually, but it could happen.
My recommendation, beyond the absurdity of actually performing some type of detailed analysis on the rest of that code, would be to just remove it altogether.
Cheers!

Substring garbage in C

I want to make a program that cuts a string into 2 strings if the string contains a ?
For example,
Test1?Test2
should become
Test1 Test2
I am trying to do it dynamically but at the prints I get some garbage and I cannot figure out what I am doing wrong. Here is my code:
for(i=0;i<strlen(expression);i++){
if(expression[i]=='?' || expression[i]=='*'){
position=i; break;
}
}
printf("position=%d\n",position);
if(position!=0){
before = (char*) malloc(sizeof(char)*(position +1 ));
strncpy(before,expression,position);
before[strlen(before)]='\0';
}
if(position!=strlen(expression))
{
after = (char*) malloc(sizeof(char)*( strlen(expression)- position+1));
strncpy(after,expression+position+1,strlen(expression)-position+1);
after[strlen(after)]='\0';
}
printf("before:%s,after:%s\n",before,after);
Since it is illegal to take length of a string until it is null terminated, you cannot do this:
before[strlen(before)]='\0';
You need to do this instead:
before[pos]='\0';
Same goes for the after part - this is illegal:
after[strlen(after)]='\0';
You need to compute the length of after upfront, and then terminate the string using the pre-computed length.
You can use strsep
char* token;
while ((token = strsep(&string, "?")) != NULL)
{
printf("%s\n", token);
}
Instead of doing it manually, you can also make good use of strtok(). Check the details here.
for(i=0;i<strlen(expression);i++){
This is very inefficient. strlen(expression) gets computed at every loop (so you get an O(n2) complexity, unless the compiler is clever enough to prove that expression stays a constant string and then to move the computation of strlen(expression) before the loop.....). Should be
for (i=0; expression[i]; i++) {
(since expression[i] is zero only when you reached the terminating null byte; for readability reasons you could have coded that condition expression[i] != '\0' if you wanted to)
And as dasblinkenlight answered you should not compute the strlen on an uninitialized buffer.
You should compute once and for all the strlen(expression) i.e. start with:
size_t exprlen = strlen(expression);
and use exprlen everywhere else instead of strlen(expression).
At last, use strdup(3):
after = (char*) malloc(sizeof(char)*( strlen(expression)- position+1));
strncpy(after,expression+position+1,strlen(expression)-position+1);
after[strlen(after)]='\0';
should be
after = strdup(expression-position+1);
and you forgot a very important thing: always test against failure of memory allocation (and of other system functions); so
before = (char*) malloc(sizeof(char)*(position +1));
should really be (since sizeof(char) is always 1):
before = malloc(position+1);
if (!before) { perror("malloc of before"); exit(EXIT_FAILURE); };
Also, if the string pointed by expression is not used elsewhere you could simply clear the char at the found position (so it becomes a string terminator) like
if (position>=0) expression[position] = `\0`;
and set before=expression; after=expression+position+1;
At last, learn more about strtok(3), strchr(3), strstr(3), strpbrk(3), strsep(3), sscanf(3)
BTW, you should always enable all warnings and debugging info in the compiler (e.g. compile with gcc -Wall -g). Then use the debugger (like gdb) to step by step and understand what is happening... If a memory leak detector like valgrind is available, use it.

C - Array of strings (2D array) and memory allocation gets me unwanted characters

I have a tiny problem with my assignment. The whole program is about tree data structures but I do not have problems with that.
My problem is about some basic stuff: reading strings from user input and then storing them in an array list.
char str[1000];
fgets(str, 1000, stdin);
int x = 0;
int y = 0;
int z = 0;
char **list;
list = (char**)malloc((x+1)*sizeof(char));
list[x] = (char*)malloc((y+1)*sizeof(char));
while(str[z] != '\n')
{
list[x][y] = str[z];
z++;
if(str[z] == ',')
{
x++;
y = 0;
list = (char**)realloc(list, (x+1) * sizeof(char*));
list[x] = (char*)malloc((y + 1)*sizeof(char));
z++;
if(str[z] == ' ') // Skips space after the comma
{
z++;
}
}
else if(str[z] == '\n')
{
break;
}
else
{
y++;
list[x] = (char*)realloc(list[x], (y+1)*sizeof(char));
}
}
I pass this list array into another function.
As an example, inputs could be something like
Abcde, Fghijk, Lmnop, Qrstu
and I am trying to split each of these words into the array list.
Abcde
Fghijk
Lmnop
Qrstu
When I try to output the strings I sometimes get weird, excessive characters such as upside down question marks and numbers.
printf("%s ", list[some_number]);
gets me
Fghijk¿
or
Fghijk\200
All of my program works as expected except for this minor problem which I am having trouble solving. Even with the same exact inputs the bugs may or may not appear. I am guessing it has to do with memory allocation?
Thanks for your help!
You need to put '\0' at the end of your new string.
See most of the C library functions such as printf and strlen process strings assuming \0 as the end character of all. Otherwise, they keep on reading the memory out of bounds either making a memory violation or gets some where the value 0 and stops and all the bytes in between in the memory are interpreted to their extended ascii equivalent hence you are getting such a strange behaviour.
So, allocate an extra byte for \0 character and assign it to the last byte.
Either initialize your variables to null, or as tomato said, put a null character at the end of the new string.
C lacks many of the luxuries programmers now take for granted when it comes to memory management. You're on the right path with malloc but that function only allocates memory... it doesn't clear it out. As a result, your variables will have the correct amount of space (critical for reducing memory leaks and overflow errors), but will be filled with garbage. This garbage could be anything, and in your case, it's an upside down question mark. Appropriate, don't you think?
I could be mistaken since I can't run the code myself without more information, but after your
char **list;
list = (char**)malloc((x+1)*sizeof(char));
list[x] = (char*)malloc((y+1)*sizeof(char));
statements, you'll want to do something like this:
list = NULL;
and the like to clear out the garbage.
Furthermore, you may care to use the strlen() function (contained in string.h) to figure out just how many blocks of memory you need to allocate.
Clearing out the spaces you use for variables is a good practice to get into with C. Good to see you learning it as well.

C - reading past end of file with fgetc

I have the weirdest thing happening, and I'm not quite sure why it's happening. Basically what I need to do is use fgetc to get the contents of a simple ASCII file byte by byte. The weird part is it worked, but then I added a few more characters and all of a sudden it added a newline that wasn't there and read past the end of the file or something. Literally all I did was
do {
temp = (char*) checked_realloc (temp, n+1);
e = fgetc(get_next_byte_argument);
temp[n] = e;
if (e != EOF)
n++;
}
while (e != EOF);
And then to check I just printed each character out
temp_size = strlen(temp)-1;
for(debug_k = 0; debug_k < temp_size; debug_k++){
printf("%c", temp[debug_k]);
}
And it outputs everything correctly except it added an extra newline that wasn't in the file. Before that, I had
temp_size = strlen(temp);
But then it ended on some unknown byte (that printed gibberish). I tried strlen(temp)-2 just in case and it worked for that particular file, but then I added an extra "a" to the end and it broke again.
I'm honestly stumped. I have no idea why it's doing this.
EDIT: checked_realloc is just realloc but with a quick check to make sure I'm not out of memory. I realize this is not the most efficient way to do this, but I'm more worried about why I seem to be magically reading in extra bytes.
A safer way to write such operation is:
memset the memory bulk before use with zeros, if you are allocating memory prior to realloc.And every time you realloc, initialize it to zero.
If you are using a memory to access strings or use string functions on that memory always ensure you are terminating that memory with a NULL byte.
do{
temp = (char*) checked_realloc (temp, n+1);//I guess you are starting n with 0?
temp[n]=0;
e = fgetc(get_next_byte_argument);
temp[n] = e;
if (e != EOF)
n++;
} while (e != EOF);
temp[n]=0;
n=0;
I guess the above code change should fix your issue. You don't need strlen -1 anymore. :)
Cheers.
It sounds like you forgot to null terminate your string. Add temp[n] = 0; just after the while.

Resources