In the following code, I ask the user to give me some strings. I make a 2-D pointer char array, so that I read the input with pointer string which points to the start of a string of length 50. My problem is that I keep crashing after the input of the first string.. and I assume that my problem has to do with the realloc. I am not used to it.. can you please help to figure out what is happening?? I tried to debug with netbeans, but didn't manage to see anything interesting, since it doesn't give feedback for the new addresses made from realloc!!
Here is the code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char *str,**string,buffer[50],temp[2];
int i,j,q,size,counter;
size=10;
string=(char**) calloc(size,sizeof(char*));
for (i=0; i<size; i++) string[i]=(char*) malloc(50*sizeof(char));
printf("\nGimme strings, terminate input with x");
i=0;
gets(string[i]);
temp[0]=120;//x
temp[1]='\0';
size=0;
while(strcmp(string[i],temp)!=0)
{
string=realloc(string,size*sizeof(char**));
i++;
gets(string[i]);
size++;
counter++;
}
return 0;
}
I want to make the table of pointers bigger with this realloc.
string=realloc(string,size*sizeof(char**));
i++;
gets(string[i]);
size++;
After you call realloc to enlarge string, the new portion contains no valid pointers. So when you call gets, you're passing it a pointer you failed to initialize.
Also, that size=0; is totally broken.
realloc does not initialize the allocated memory with zeros, in addition you forgot to initialize the newly allocated string pointers.
Consider to move up i++ and size++ within the while loop.
Code Review
initialize all your variables
char *str = NULL,**string = NULL,buffer[50] = {0},temp[2] = {0};
int i = 0,j = 0,q = 0,size = 10,counter = 0;
do not cast what is returned from malloc/calloc and use {} when possible for clarity
string=calloc(size,sizeof(char*));
for (i=0; i<size; i++)
{
string[i]=malloc(50*sizeof(char));
}
When reading from the keyboard do not use gets, use fgets() since you can specify the max size to read.
printf("\nGimme strings, terminate input with x");
char input[256];
fgets(input,sizeof(input),stdin); // another varname, will explain below
With newer compilers you can declare variables where you need them instead of decl at top of function.
char temp={'x','\0'}; // 120;//x
setting size=0 here seems a bit strange
size=0;
it is better to keep what the user inputs in a separate buffer (input)
then if it is not "x" copy it into your string array so instead of
while(strcmp(string[i],temp)!=0)
{
string=realloc(string,size*sizeof(char**));
i++;
gets(string[i]);
size++;
counter++;
}
e.g.
while (fgets(input,sizeof(input),stdin) != NULL && input[0] != 'x')
{
string[i] = calloc(1,strlen(input)+1); // add a byte for \0
strncpy(string[i],input,strlen(input)-1); // not copying ending \n
if ( ++i == size ) // a new chunk needed
{
char *newstring = realloc((size + 10)*sizeof(char*), string );
if ( newstring != NULL )
{
string = newstring;
size += 10;
}
}
}
Related
How should I return an empty string from a function? I tried using lcp[i] = ' ' but it creates an error. Then I used lcp[i] = 0 and it returned an empty string. However, I do not know if it's right.
Also, is it necessary to use free(lcp) in the caller function? Since I could not free and return at the same time.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 50
char *find_LCP(char str1[], char str2[]);
char *find_LCP(char str1[], char str2[]){
char * lcp = malloc(MAX_LEN * sizeof(char));
int a = strlen(str1);
int b = strlen(str2);
int min = a < b ? a : b;
for(int i = 0; i < min; i++){
if(str1[i] == str2[i])
lcp[i] = str1[i];
else
lcp[i] = 0;
}
return lcp;
}
int main()
{
char str1[MAX_LEN], str2[MAX_LEN];
char * lcp;
printf("Enter first word > ");
scanf("%s", str1);
printf("Enter second word > ");
scanf("%s", str2);
lcp = find_LCP(str1, str2);
printf("\nLongest common prefix: '%s'\n", lcp);
free(lcp);
return 0;
}
An "empty" string is just a string with the first byte zero, so you can write:
s[0] = 0;
However, it is not clear what you are trying to do. The LCP of "foo" and "fob" is "fo", not the empty string.
You can also return as soon as you find the first non-matching character, no need to go until the end.
Further, you can simply pass the output string as a parameter and have lcp be an array. That way you avoid both malloc and free:
char lcp[MAX_LEN];
...
find_LCP(lcp, str1, str2);
If you want to empty a string without using a for loop then you can do
lcp[0] = 0
but for emptying a string it was right the way you did using a for loop.
There are plenty other ways of emptying the string word by word using for loop:
lcp[i] = '\0';
and it's the right way to make string empty as letter by letter you trying to do using for loop
But if you are not using some loops and simply empty a string then you can do this.
memset(buffer,0,strlen(buffer));
but this will only work for zeroing up to the first NULL character.
If the string is a static array, you can use:
memset(buffer,0,sizeof(buffer));
Your program has a bug: If you supply two identical strings, lcp[i] = 0; never executes which means that your function will return a string which is not NUL-terminated. This will cause undefined behvaior when you use that string in your printf in main.
The fix for this is easy, NUL-terminate the string after the loop:
int i;
for (i = 0; i < min; i++){
if(str1[i] == str2[i])
lcp[i] = str1[i];
else
break;
}
lcp[i] = 0;
As for the answer to the question, an empty string is one which has the NUL-terminator right at the start. We've already handled that as we've NUL-terminated the string outside the loop.
Also, is it necessary to use free(lcp) in the caller function?
In this case, it is not required as the allocated memory will get freed when the program exits, but I'd recommend keeping it because it is good practice.
As the comments say, you can use calloc instead of malloc which fills the allocated memory with zeros so you don't have to worry about NUL-terminating.
In the spirit of code golf. No need to calculate string lengths. Pick any string and iterate through it until the current character either null or differs from the corresponding character in the other string. Store the index, then copy appropriate number of bytes.
char *getlcp(const char *s1, const char *s2) {
int i = 0;
while (s1[i] == s2[i] && s1[i] != '\0') ++i;
char *lcp = calloc((i + 1), sizeof(*lcp));
memcpy(lcp, s1, i);
return lcp;
}
P.S. If you don't care about preserving one of input strings then you can simplify the code even further and just return the index (the position of the last character of the common prefix) from the function, then put '\0' at that index into one of the strings.
I am writing a simple Shell for school assignment and stuck with a segmentation problem. Initially, my shell parses the user input to remove whitespaces and endofline character, and seperate the words inside the input line to store them in a char **args array. I can seperate the words and can print them without any problem, but when storing the words into a char **args array, and if argument number is greater than 1 and is odd, I get a segmentation error.
I know the problem is absurd, but I stuck with it. Please help me.
This is my parser code and the problem occurs in it:
char **parseInput(char *input){
int idx = 0;
char **parsed = NULL;
int parsed_idx = 0;
while(input[idx]){
if(input[idx] == '\n'){
break;
}
else if(input[idx] == ' '){
idx++;
}
else{
char *word = (char*) malloc(sizeof(char*));
int widx = 0; // Word index
word[widx] = input[idx];
idx++;
widx++;
while(input[idx] && input[idx] != '\n' && input[idx] != ' '){
word = (char*)realloc(word, (widx+1)*sizeof(char*));
word[widx] = input[idx];
idx++;
widx++;
}
word = (char*)realloc(word, (widx+1)*sizeof(char*));
word[widx] = '\0';
printf("Word[%d] --> %s\n", parsed_idx, word);
if(parsed == NULL){
parsed = (char**) malloc(sizeof(char**));
parsed[parsed_idx] = word;
parsed_idx++;
}else{
parsed = (char**) realloc(parsed, (parsed_idx+1)*sizeof(char**));
parsed[parsed_idx] = word;
parsed_idx++;
}
}
}
int i = 0;
while(parsed[i] != NULL){
printf("Parsed[%d] --> %s\n", i, parsed[i]);
i++;
}
return parsed;
}
In your code you have the loop
while(parsed[i] != NULL) { ... }
The problem is that the code never sets any elements of parsed to be a NULL pointer.
That means the loop will go out of bounds, and you will have undefined behavior.
You need to explicitly set the last element of parsed to be a NULL pointer after you parsed the input:
while(input[idx]){
// ...
}
parsed[parsed_idx] = NULL;
On another couple of notes:
Don't assign back to the same pointer you pass to realloc. If realloc fails it will return a NULL pointer, but not free the old memory. If you assign back to the pointer you will loose it and have a memory leak. You also need to be able to handle this case where realloc fails.
A loop like
int i = 0;
while (parsed[i] != NULL)
{
// ...
i++;
}
is almost exactly the same as
for (int i = 0; parsed[i] != NULL; i++)
{
// ...
}
Please use a for loop instead, it's usually easier to read and follow. Also for a for loop the "index" variable (i in your code) will be in a separate scope, and not available outside of the loop. Tighter scope for variables leads to less possible problems.
In C you shouldn't really cast the result of malloc (or realloc) (or really any function returning void *). If you forget to #include <stdlib.h> it could lead to hard to diagnose problems.
Also, a beginner might find the -pedantic switch helpful on your call to the compiler. That switch would have pointed up most of the other suggestions made here. I personally am also a fan of -Wall, though many find it annoying instead of helpful.
This question already has answers here:
Return char[]/string from a function [duplicate]
(5 answers)
Closed 8 years ago.
I am writing a program that returns a string from stdin, but i am getting warning that it returns an adress of local wariable. How can i return the string?
thanks in advance
#include <stdio.h>
char* readLine()
{
int i;
char input[1024];
for(i=0;i<1024;i++)
{
input[i]=fgetc(stdin);
if(input[i]=='\n')
{
break;
}
}
return input;
}
int main()
{
printf("%s",readLine());
return 0;
}
This should work for you:
You can pass input from main as reference:
#include <stdio.h>
char * readLine(char * input, int length) {
int i;
for(i = 0; i < length; i++) {
input[i] = fgetc(stdin);
input[length] = '\0';
if(input[i] == '\n')
break;
}
return input;
}
int main() {
int length = 1024;
char input[length+1];
printf("%s", readLine(input, length));
return 0;
}
Try to do something like that instead:
#include <stdio.h>
char* readLine()
{
int i;
char *input;
if ((input = malloc(sizeof(char) * 1024)) == NULL)
return (NULL);
for(i=0;i<1024;i++)
{
input[i]=fgetc(stdin);
if(input[i]=='\n')
{
input[i] = '\0';
break;
}
}
return input;
}
int main()
{
char *str;
if (str = readLine()) != NULL) {
printf("%s\n", str);
free(str);
}
return 0;
}
}
There is nothing wrong here - that is just a WARNING because usually it is a common mistake of new programmers. I used to run into problems with this usage all the time.
The first thing... this "string" is not null-terminated. You'll want to put at the end of that function something like *(input + i) = '\0'; and make either the array size 1025 or the condition i < 1023 (so that the null character isn't assigned beyond the end of the buffer), because at the moment using this array in a function that expects null termination will cause it to possibly continue past the end of the array, resulting in a memory access violation. Alternately, you could use memset(input,0,1024);, just still make sure that the condition is something like i < 1023 so that the standard input you receive doesn't end up writing all the way to the last null character in the array.
The other problem is that this memory is local, as in it "belongs" to this function. And for the usage you have here, it is probably just fine to use the same memory... if you plan to call the function, do something with the result, and then call the function again, do something with the result... But if you want to keep what's given to you by it, you'll have to either (1) copy the string to another buffer that isn't going to be written to again when the function is called in the future, or (2) make the function allocate a new buffer each time it runs, and then be sure to delete that memory when you're done with it. For example, instead of char input [1024]; (which by the way would have the same pointer for the life of the program, so it's not really necessary to return it each time) you could write char* input = malloc(1024); and later, when the caller is done with the string, you should free(input);. (Of course, the name might not be input in this case since you would probably not want to free the memory in the function whose purpose is to allocate it.)
I will edit this later with code showing changes.
The goal of my assignment (ONLY C, NO C#,CPP ect...) was to get strings from the user, then trim the matrix to fit the exact data. This is my code:
void main(){
char** text=Q1();
int i;
printf("Lines entered:\n");
for(i=0;i<sizeof(text)/sizeof(char*);i++)
printf("%s\n",text[i]);
}
char** Q1(){
char OOM[]="Out of memory! exiting.";
char **buf=(char**)calloc(BUFFER,sizeof(char*)),**text;
int i,j;
if(buf==NULL){
printf(OOM);
exit(0);
}
for(i=0;i<BUFFER;i++){
buf[i]=(char*)calloc(BUFFER,sizeof(char));
if(buf[i]==NULL){
printf(OOM);
exit(0);
}
}
i=0;
do{
i++;
printf("Enter string #%d:\n",i);
gets(buf[i-1]);
}while(strlen(buf[i-1])>0 && i-1<BUFFER);
text=(char**)calloc(i,sizeof(char*));
if(text==NULL){
printf(OOM);
exit(0);
}
for(j=0;j<i;j++){
text[j]=(char*)calloc(strlen(buf[j]),sizeof(char));
if(text[j]==NULL){
printf(OOM);
exit(0);
}
strcpy(text[j],buf[j]);
}
free(buf);
return text;
}
Now I know this could be done with realloc (which I am not quite familiar with just yet).
I want to test that my allocations are okay and print the strings I saved in text.
What is the most intuitive way of doing that?
Thanks in advance!
First, this code:
for(i=0;i<sizeof(text)/sizeof(char*);i++)
printf("%s\n",text[i]);
Will not work.
sizeof(text) will return the size of a pointer since text is a char**. You'd want something like:
for (int i=0; i<BUFFER && text[i]!=0; i++)
printf("%s\n",text[i]);
But this requires that the last entry in text is a null pointer so you would need to allocate 1 more entry than required and set it to NULL.
Otherwise, you'll need to find some other way to return the size.
Next:
i=0;
do{
i++;
printf("Enter string #%d:\n",i);
gets(buf[i-1]);
}while(strlen(buf[i-1])>0 && i-1<BUFFER);
i will be 1 more than the number of entries. For example, if the user presses ENTER on the first try, i will be set to 1.
Why not?
for (i=0; i<BUFFER; i++) {
printf("Enter string #%d:\n",i+1);
gets(buf[i]);
if (strlen(buf[i])==0) {
break;
}
}
This way i is set to the number of entries.
Assuming you make the change above then:
text=(char**)calloc(i,sizeof(char*));
Will need to be changed to:
text=(char**)calloc(i+1,sizeof(char*)); // Include an extra entry for the sentinel
text[i] = 0; // Add sentinel to indicate last entry
Also, when you allocate the space for the strings, you need to add 1 to the size to leave room for the terminating null character. So
text[j]=(char*)calloc(strlen(buf[j]),sizeof(char));
becomes
text[j]=(char*)calloc(strlen(buf[j])+1,sizeof(char));
And you forgot to free buf[0] to buf[BUFFER-1]
For the real question. I'm not sure what's expected your approach looks OK to me.
I'm attempting to write a simple shell like interface, that takes in a users input (by char) and stores it via a pointer to a pointer* (exactly how argv works). Here's my code:
char input[100];
char **argvInput;
char ch;
int charLoop = 0;
int wordCount = 0;
argvInput = malloc(25 * sizeof(char *));
while((ch = getc(stdin))) {
if ((ch == ' ' || ch == '\n') && charLoop != 0) {
input[charLoop] = '\0';
argvInput[wordCount] = malloc((charLoop + 1) * sizeof(char));
argvInput[wordCount] = input;
charLoop = 0;
wordCount++;
if (ch == '\n') {
break;
}
} else if (ch != ' ' && ch != '\n') {
input[charLoop] = ch;
charLoop++;
} else {
break;
}
}
If I loop through argvInput via:
int i = 0;
for (i = 0; i < wordCount; i++)
printf("Word %i: %s\n", i, argvInput[i]);
All of the values of argvInput[i] are whatever the last input assignment was. So if I type:
"happy days are coming soon", the output of the loop is:
Word 0: soon
Word 1: soon
Word 2: soon
Word 3: soon
Word 4: soon
I'm at a loss. Clearly each loop is overwriting the previous value, but I'm staring at the screen, unable to figure out why...
This line is your bane:
argvInput[wordCount] = input;
Doesn't matter that you allocate new space, if you're going to replace the pointer to it with another one (i.e. input).
Rather, use strncpy to extract parts of the input into argvInput[wordCount].
argvInput[wordCount] = input; is only making the pointer of argvInput[wordCount] point to the memory of input instead of copy the content of input into the new allocated memory. You should use memcpy or strcpy to correct your program.
After the pointer assignment the memory status looks like the image below. The memory allocated by malloc((charLoop + 1) * sizeof(char));, which are the grey ones in the graph, could not be accessed by your program anymore and this will lead to some memory leak issue. Please take care of that.
I suggest printing your argvInput pointers with %p, instead of %s, to identify this problem: printf("Word %i: %p\n", i, (void *) argvInput[i]);
What do you notice about the values it prints? How does this differ from the behaviour of argv? Try printing the pointers of argv: for (size_t x = 0; x < argc; x++) { printf("Word %zu: %p\n", x, (void *) argv[x]); }
Now that you've observed the problem, explaining it might become easier.
This code allocates memory, and stores a pointer to that memory in argvInput[wordCount]: argvInput[wordCount] = malloc((charLoop + 1) * sizeof(char)); (by the way, sizeof char is always 1 in C, so you're multiplying by 1 unnecessarily).
This code replaces that pointer to allocated memory with a pointer to input: argvInput[wordCount] = input; ... Hence, all of your items contain a pointer to the same array: input, and your allocated memory leaks because you lose reference to it. Clearly, this is the problematic line; It doesn't do what you initially thought it does.
It has been suggested that you replace your malloc call with a strdup call, and remove the problematic line. I don't like this suggestion, because strdup isn't in the C standard, and so it isn't required to exist.
strncpy will work, but it's unnecessarily complex. strcpy is guaranteed to work just as well because the destination array is allocated to be large enough to store the string. Hence, I recommend replacing the problematic line with strcpy(argvInput[wordCount], input);.
Another option that hasn't been explained in detail is strtok. It seems this is best left unexplored for now, because it would require too much modification to your code.
I have a bone to pick with this code: char ch; ch = getc(stdin); is wrong. getc returns an int for a reason: Any successful character read will be returned in the form of an unsigned char value, which can't possibly be negative. If getc encounters EOF or an error, it'll return a negative value. Once you assign the return value to ch, how do you differentiate between an error and a success?
Have you given any thought as to what happens if the first character is ' '? Currently, your code would break out of the loop. This seems like a bug, if your code is to mimic common argv parsing behaviours. Adapting this code to solve your problem might be a good idea:
for (int c = getc(stdin); c >= 0; c = getc(stdin)) {
if (c == '\n') {
/* Terminate your argv array and break out of the loop */
}
else if (c != ' ') {
/* Copy c into input */
}
else if (charLoop != 0) {
/* Allocate argvInput[wordCount] and copy input into it,
* reset charLoop and increment wordCount */
}
}