I'm new to C and trying to write a command line program with it. I'm trying to free a char array right before the program terminates. But I'm getting a "debug assertion failed" run-time error when it reaches the free command. Before it reaches that point, the program is removing characters in that array up until the first whitespace. I'm using the incrementing technique on the array since I read that was a way to remove chars one by one from an array. Here's that piece of code:
char command[140];
char * input = getInput(); //prompt function for user input
//get string up to first whitespace to separate the command and its parameters
for (i = 0; i < strlen(input); i++)
{
if (input[i] == ' ' || input[i] == '\0')
break;
command[i] = input[i];
}
for (j = 0; j <= i; j++) //removes command and space and leaves parameters
input++;
command[i] = '\0'; //null terminate char array
numParams = getNumParams(input);
free(input); //should've added this line earlier to avoid confusion.
My getInput() function does this:
char * getInput()
{
int n, size = 260;
char * input = (char*)malloc(size);
if (!input) //make sure memory allocation worked
return NULL;
do
{
printf("cmd> "); //prompt
fgets(input, 256, stdin); //get user input/commands
n = strlen(input);
} while (n <= 1);
if (input[n - 1] == '\n') //remove new line from input array
input[n - 1] = '\0';
return input;
}
So after the rest of the program ends I want to be able to free the memory that was allocated in the getInput() function. I'm thinking the way I have the input returning to a char pointer is messing that up. But I'm not sure how to fix it. Any help is appreciated.
You haven't posted the line that calls free. I am assuming that you are calling:
free(input);
I can see why that would be a problem.
You are changing the value of input in the lines:
for (j = 0; j <= i; j++)
input++;
When you call free, the value of the pointer must be what was returned by malloc, calloc, or realloc. If you use any other pointer value, the program is subject to undefined behavior.
Make sure that you keep the value that was returned, so you can call free using it.
char* input = getInput();
char* saved_ptr = input;
// ...
// Change input
// ...
// Deallocate memory using the original pointer
free(saved_ptr);
The problem is most likely these two lines:
for (j = 0; j <= i; j++) //removes command and space and leaves parameters
input++;
Here you modify the pointer, making you loose the original pointer that you should pass to free. You need to save the original pointer in a temporary variable, and pass that to free.
You get an error because you are modifying the input pointer here:
for (j = 0; j <= i; j++) //removes command and space and leaves parameters
input++;
After this operation, input no longer points to the start of memory, allocated by malloc. Thus giving you the error. Instead, copy input to another pointer variable.
Also, consider doing allocation outside of getInput() since it is considered a good practice to allocate and free the memory in the same function, if possible.
Related
#include <stdio.h>
#include <stdlib.h>
char *ptr;
int n;
int main()
{
ptr = (char *)calloc(n, sizeof(char));
// First ID
printf("Enter the length of your employ ID\n");
scanf("%d", &n);
for (int i = 0; i <= n; i++)
{
scanf("%c", &ptr[i]);
}
for (int i = 0; i <= n; i++)
{
printf("%c", ptr[i]);
}
// Second ID
printf("Enter the size of new ID\n");
scanf("%d", &n);
ptr = (char *)realloc(ptr, n * sizeof(char));
for (int i = 0; i <= n; i++)
{
scanf("%c", &ptr[i]);
}
for (int i = 0; i <= n; i++)
{
printf("%c", ptr[i]);
}
// Third ID
printf("Enter the size of new ID\n");
scanf("%d", &n);
ptr = (char *)realloc(ptr, n * sizeof(char));
for (int i =0; i <=n; i++)
{
scanf("%c", &ptr[i]);
}
for (int i = 0; i <= n; i++)
{
printf("%c", ptr[i]);
}
return 0;
}
I tried to Get Ids of three people but the program doesnt work and after taking the input once it just exits : ( . It works fine when I use realloc once but not twice can someone explain why ?
it takes the input and then exits
The statement:
int n;
declares n at file scope. Objects declared at file scope have static storage duration and are always initialised. In the absence of an explicit initialization, they are implicitly initialised to zero.
From the C standard C11 6.7.9/10:
"... If an object that has static or thread storage duration is not
initialized explicitly, then:
— if it has pointer type, it is initialized to a null pointer;
— if it has arithmetic type, it is initialized to (positive or
unsigned) zero;"
Accessing out of bounds memory:
Then:
ptr = (char *)calloc(n, sizeof(char));
allocates memory for 0 objects.
The calloc() function allocates memory for an array of nmemb elements
of size bytes each and returns a pointer to the allocated memory. The
memory is set to zero. If nmemb or size is 0, then calloc() returns
either NULL, or a unique pointer value that can later be successfully
passed to free().
On error, these functions return NULL. NULL may also be returned by a
successful call to malloc() with a size of zero, or by a successful
call to calloc() with nmemb or size equal to zero.
But you didn't check the return value of calloc.
Then, this statement:
scanf("%c", &ptr[i]);
tries to access memory that wasn't allocated, and thus invokes undefined Behaviour.
Off by one error:
You have allocated space for n elements, but the condition:
i <= n
tries to access n + 1 elements, which is memory out of bounds, memory you haven't allocated, memory that doesn't belong to you, and is thus undefined behaviour. (But that's irrelevant since you didn't allocate anything in the first place).
Regarding realloc:
The realloc() function returns a pointer to the newly allocated
memory, which is suitably aligned for any kind of variable and may be
different from ptr, or NULL if the request fails. If size was equal to
0, either NULL or a pointer suitable to be passed to free() is
returned. If realloc() fails the original block is left untouched; it
is not freed or moved.
Which means that if it fails and returns NULL, then ptr gets initialised with NULL and you lose all access to the original memory.
One solution is to use another pointer:
char *new = realloc(ptr, size);
if (!new) { /* if realloc failed */
/* deal with it however you wish */
}
/* If we got here, it means that we weren't bounded */
ptr = new;. /* Now ptr points to the new memory, if it didn't already */
new = 0; /* This avoids a dangling pointer */
/* some code relevant to ptr here */
free(ptr); /* For every allocation, there must be a call to free */
Side note: You shouldn't cast the result of malloc and family. It's redundant and may hide a bug. The void * returned by these functions is automatically promoted to the correct type.
Trailing newline:
scanf("%d", &n);
leaves a newline in the input buffer, which automatically gets read by subsequent calls to scanf, and you might never be prompted for input.
Instead of:
scanf("%c");
Use " %c" with a leading blank to skip optional white space:
scanf(" %c");
First of all, please note that you're using:
ptr = (char *)calloc(n, sizeof(char));
when n isn't explicitly initialized in file scope so it is automatically initialized to 0. So basically you overwrite a buffer of size 0 in:
for (int i = 0; i <= n; i++)
{
scanf("%c", &ptr[i]);
}
while exceeding the size allocated with i <= n which sould be i < n, that is probably why.
Second, you must free your memory allocation at the end using free and check allocation's success.
Third, when using strings, you might want to use scanf using %s, unless you have a specific reason.
A more clear and less error prone implementation may be:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int size, times, i;
char *ptr;
printf("Enter the number of IDs to enter\n");
scanf("%d", ×);
for (i = 0; i < times; ++i) {
printf("Enter the size of new ID\n");
scanf("%d", &size);
if (size < 0) {
printf("Entered value is negative\n");
return size; // or any other error
}
// note the '+ 1' so we have a NULL terminating string
ptr = (char *)calloc(size + 1, sizeof(char));
if (ptr == NULL) {
printf("Error allocating ptr\n");
return -1; // or any other error
}
printf("Enter your ID\n");
scanf("%s", ptr);
printf("Your ID is: %s\n", ptr);
free(ptr);
}
return 0;
}
Hopefully I answered everything and didn't miss a thing (:
I'm trying to write a program to take 10 words as input from the user, then store it an array, and then print out the length of each word.
Here's my code:
#include <stdio.h>
#include <string.h>
char *words[10];
char length[10];
int i, j;
int main()
{
printf("Input ten words: \n");
for(i = 0; i < 10; i++)
{
printf("Enter element %d \n", i + 1);
scanf("%s", &words[i]);
}
for(i = 0; i < 10; i++)
printf("%c", words[i]);
for(i = j = 0; j < 10; j++)
{
length[j] = strlen(words[i]);
i++;
}
for(j = 0; j < 10; j++)
printf("%c", length[j]);
return 0;
}
It should be noted that I have no idea why the array "words" is defined as a pointer, I only do it because if I don't I get some warning about making a pointer from integer without a cast.
When I run the program what happens is, I get prompted to input the 10 elements, that much works, but then when it's supposed to print the "words" array, the program just crashes.
Also the reason I coded it like this is because later on I also need to print the longest and shortest word - so I figured it would help if I had the lengths of all the strings in their own array.
Does anyone know what's wrong here?
Thanks
With the line char *words[10], you are declaring an array of 10 pointers. However, these pointers are uninitialized, which means they are wild pointers. Dereferencing a wild pointer causes undefined behavior (i.e. the program may crash). If you want to use these pointers in a meaningful way, you must make each pointer point to a valid memory location, for example to an address returned by the function malloc or to the address of a char array.
However, probably the easiest solution to your problem is to not use pointers at all, but to instead declare a two-dimensional char array, like this:
char words[10][100];
That way, you are allocating space for 10 words of up to 100 characters each (including the null terminating character).
Beware that a buffer overflow will occur if the user enters a word longer than 99 (1 byte is required for the terminating null character). Therefore, the scanf line should be changed to the following:
scanf("%99s", words[i]);
That way, scanf will never attempt to write more than 100 bytes (including the terminating null character).
I have also removed the & in the scanf line above, because the & is not necessary, since words[i] will automatically decay to &words[i][0].
Also, as a general rule, you should verify that the return value of scanf is 1 before attempting to use the value that scanf wrote. For example, if the user triggers end of file on the input stream (for example by pressing CTRL-D on Linux or CTRL-Z on Windows), then scanf will return -1 without writing anything into words[i]. In that case, by subsequently reading from words[i], your program will cause undefined behavior.
Additionally, the line
printf("%c", words[i]);
must be changed to:
printf("%s", words[i]);
The loop
for(i = j = 0; j < 10; j++)
{
length[j] = strlen(words[i]);
i++;
}
can be simplified to:
for(i = 0; i < 10; i++)
{
length[i] = strlen(words[i]);
}
The line
printf("%c", length[j]);
should probably be changed to
printf("%hhu", length[j]);
because length[j] does not represent the ASCII code of a character, but just a number.
In what way is the following code faulty or undefined behaviour?
I suggested this as a possibility to create an array of strings, if string number and size are unknown beforehand, and after a short discussion, it was suggested that I open a new question.
The following code produced the expected results when I compiled it with gcc, but that can happen in spite of undefined behaviour (it's undefined after all).
So, what is the mistake?
int n, i;
printf("How many strings? ");
scanf("%d", &n);
char *words[n];
for (i = 0; i < n; ++i) {
printf("Input %d. string: ", i + 1);
scanf("%s", &words[i]);
}
for (i = 0; i < n; ++i) {
printf("%s\n", &words[i]);
}
Edit:
I feel stupid now for missing this, I guess getting the correct answer back just made me miss my error. But that others may learn from my mistake:
I guess I got completely wrong what the & operator does. I thought it would give me where words points to, but of course it does the exact opposite. See the answers.
scanf("%s", &words[i]); and printf("%s\n", &words[i]); invokes *undefined behavior because data having wrong type are passed.
In both of scanf() and printf(), %s requires char* pointing at valid buffer but what is passed are char**.
Also don't forget to allocate buffer to store strings before reading.
Try this:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n, i;
printf("How many strings? ");
scanf("%d", &n);
char *words[n];
for (i = 0; i < n; ++i) {
printf("Input %d. string: ", i + 1);
words[i] = malloc(1024001); /* allocate enough buffer */
if (words[i] == NULL) {
perror("malloc");
return 1;
}
scanf("%1024000s", words[i]); /* limit length to read to avoid buffer overrun */
}
for (i = 0; i < n; ++i) {
printf("%s\n", words[i]);
}
for (i = 0; i < n; ++i) {
free(words[i]); /* clean what is allocated */
}
return 0;
}
char *words[n];
creates an array of uninitialized pointers
scanf("%s", foo);
writes values to the position foo is pointing to
it is not specified where the pointers of words are pointing to so they could point anywhere which could result in a segfault
next words is a char**
words[i] is a char *
&words[i] is a char **
%s expects a char* so it's again undefined behavior what happens
so you first have to initialize your words arrays using for example malloc and then write the values to words[i]
This:
char *word;
is a pointer, Before it is used as a container for say a string, it needs to point to memory sufficient for the string.
for example, this will work
word = malloc(80*sizeof(*word));
if(word)
{//success, continue
Similar to above, this:
char *word[n];
extension is an an array of n pointers. Before any of the pointers can be used as a container for say some strings, each needs to point to its own memory location. Assuming the value n has been scanned in, this will work:
for(int i=0;i<n;i++)
{
word[i] = malloc(80*sizeof(*word[i]));//80 for illustration
if(!word[i])
{//handle error...
Once the memory is allocated, the strings can be populated.
However, to ensure user input does not overflow the buffer defined by each instance of word, use a width specifier in the format string:
Change:
scanf("%s", &words[i]);
To:
scanf("%79s", words[i]);//note & is not needed as the symbol for a char array serves as the address
// ^^ ^
So basically, right now, this function can only take 9 words with 10 characters each. How do i make it so that it can take an arbitrary amount of words and characters and sort them accordingly in alphabetical order?
int sortText(){
char name[10][9], tname[10][9], temp[10];
int i, j, n;
printf("Enter the amount of words you want to sort (max 9):");
scanf("%d", &n);
printf("Enter %d words: ",n);
for (i = 0; i < n; i++)
{
scanf("%s", name[i]);
strcpy(tname[i], name[i]);
}
for (i = 0; i < n - 1 ; i++){
for (j = i + 1; j < n; j++){
if (strcmp(name[i], name[j]) > 0){
strcpy(temp, name[i]);
strcpy(name[i], name[j]);
strcpy(name[j], temp);
}
}
}
printf("\n------------------------------------------\n");
printf("%-3s %4s %11s\n", "Input","|", "Output");
printf("------------------------------------------\n");
for (i = 0; i < n; i++)
{
printf("%s\t\t%s\n", tname[i], name[i]);
}
printf("------------------------------------------\n");
}
You have two problems, that each needs to be solved separately, but they can still be solved in a similar way, namely using dynamic memory allocations and more importantly reallocation.
There are two important aspects to remember here, and the first is that a string is an array of characters (with a special terminating character) and that you can have a pointer to an array located anywhere in memory.
If we start with the data-types and how you should store your strings, what you want is an array of arrays, much like you have right now, but allocated dynamically which means you want an array of pointers (to the strings), but since the array of string also needs to be dynamic you need a pointer to an array which contains pointers to other arrays, i.e. a pointer to a pointer to char: char **.
Now when we know what data-type to use, lets think about how to allocate it. To allocate space for a single string in your array, you allocate one char * using the malloc function:
char **strings = malloc(1 * sizeof(char *));
That was the simple part. Now before we start reading the actual string, lets think about how to add a new string to your collection: This is done by reallocating the array of strings you have, using the realloc function:
char **temp_strings = realloc(strings, current_count + 1 * sizeof(char *));
if (temp_string == NULL)
{
// Allocation failed, handle error appropriately
}
strings = temp_strings;
++current_count;
Here the variable current_count is the current length of the array of strings, it should be initially initialized to 1 (as we only have a single string in the array).
Now for the reading of the actual strings, and this is a little more complicated since we actually can't read whole strings (since we don't know how long each line is). Instead we read one character at a time, and end when we hit a newline. We also need to reallocate the string for each character.
Maybe something like this:
int ch;
char *s = NULL;
size_t current_length = 0; // Current length of string
while ((c = fgetc(stdin)) != EOF)
{
if (c == '\n')
break; // Newline, done with the current string
if (s == NULL)
{
s = malloc(2); // Allocate two character: One for c and one for the terminator
}
else
{
// The current length is not including the terminator
// that's why we add two characters
char *temp_s = realloc(s, current_length + 2);
if (temp_s == NULL)
{
// Handle error
}
s = temp_s;
}
s[current_length++] = c;
s[current_length] = '\0'; // Terminate as a string
}
if (s != NULL)
{
// "Add" the string to the array of strings
strings[current_count] = s;
}
For C only you should use char pointer located dynamic.
You can make list by implement a linked list. Then strcmp still work well.
See about linked list here:
http://www.cprogramming.com/tutorial/c/lesson15.html
So I am doing something wrong with this program and would like someones help. I want to add spaces between the brackets and the words inside. For instance if the original string is if (x=5) then I want to make it if ( x=5 ). Simple task I know and here is the code I have:
char* addSpaces(char* line) {
int i,j;
char *result = line;
for (i = 0, j = 0; i<strlen(line); i++,j++)
{
if (line[i] == '[') {
result[j] = line[i];
j++;
result[j] = ' ';
}
else if (line[i] == ']') {
result[j] = ' ';
j++;
result[j] = line[i];
}
else result[j] = line[i];
}
result[j] = 0;
return result;
}
For some reason it freezes when I run the program. I don't get any errors. Any ideas?
Your algorithm can't work if the input and output strings point to the same buffer (which is how you have it set up). Since you're overwriting the input string with a longer string (at least in your example case), you end up overwriting the null terminator. That causes undefined behaviour the next time your loop condition calls strlen, and then all bets are off.
Instead of overwriting the input buffer, allocate a new larger buffer, do the copy, and then return a pointer to that new buffer.
There is no validation of input buffer, or do you just assume that input buffer is long enough to hold after spaces are added? Like Carl said, it's better to allocate memory inside the function (you may need to run through your string once to calculate how much you need to allocate) and then return the newly allocated buffer that is filled with new value.