Dynamically allocating lines from stdin? - c

I'm trying to read a file of 10 lines of varying lengths (which will not exceed 349 characters), and store them in a dynamically allocated array in order to be able to manipulate them later on. I have the below code which gives me a "warning: passing argument 1 of âstrcpyâ makes pointer from integer without a cast" message.
What did I do wrong here? My logic was that addresses should be a pointer to an array of pointers, where each pointer in the array points to a line in the string, which I would try to make happen by using strcpy of that line to that point.
char buffer[350];
char** addresses;
int i = 0;
*addresses = malloc(sizeof(char*)*10); /* Let's start off with 10 addresses */
while(fgets(buffer, sizeof(buffer), stdin) != NULL)
{
strcpy(*addresses[i],buffer);
i++;
}

You've got couple of issues:
Syntax:
Use
strcpy(addresses[i],buffer);
instead of
strcpy(*addresses[i],buffer);
Memory:
You need to allocate memory for addresses[i] before you can copy the contents of buffer to it.
Add a line to allocate memory for addresses[i] before the call to strcpy.
addresses[i] = malloc(sizeof(buffer));

You have to give like this,
strcpy(addresses[i],buffer);
If you give like this,
strcpy(*addresses[i],buffer);
First argument will consider as a single character.
And while allocating the memory you have do like this,
address=malloc(sizeof(char)*10);
You have to allocate the memory for each pointer.
address[i]=malloc(strlen(buffer)+1);
Or else, you can use strdup function which will allocate the memory for given
string length.
address[i]=strdup(buffer);
The strdup() function returns a pointer to a new string which is a duplicate of the string s. Memory
for the new string is obtained with malloc(3), and can be freed with free(3).

addresses is a pointer to pointer so you need to allocate memory for your pointers first and later allocate memory to each pointers individually as shown below.
In 2D space if addresses is a pointer to a pointer then addresses[i] is a pointer.So allocate memory for it before writing to this location.
char** addresses;
addresses = malloc(sizeof(char*)*10);// Now you 10 character pointers
int i = 0;
while(fgets(buffer, sizeof(buffer), stdin) != NULL)
{
size_t n = strlen(buffer);
if(n>0 && buffer[n-1] == '\n')
buffer[n-1] = '\0';
if(i>=10)
break;
addresses[i] = malloc(strlen(buffer)+1);//Allocate memory to the pointer before writing to it
strcpy(addresses[i],buffer);
i++;
}
PS: fgets() comes with a newline character so I have added a check to replace a newline character with a null.

To quickly address the errors I see here:
You're dereferencing addresses (eg. *addresses or addresses[0]) without ensuring that addresses points somewhere valid. You need to assign to addresses before you dereference.
The type of *addresses[i] in strcpy(*addresses[i],buffer) is char, where it is expected that it be char *. This is what your compiler is complaining about. I suspect that you meant strcpy(addresses[i], buffer).
Even if you're to run this code in an embedded environment, your requirements seem simple enough that you shouldn't need malloc. In fact, introducing malloc complicates things... I tend avoid it unless absolutely necessary. Use automatic storage duration, instead. It'll make life easier, because you won't have as many error situations to handle (though as it is you aren't handling them anyway)...
#define nelem(array) (sizeof array / sizeof *array) /* number of elements in array */
int main(void)
{
char address[10][351] = { 0 };
size_t size = 0;
while (size < nelem(address) && fgets(address + size, sizeof *address, stdin))
{
address[size][strcspn(address[size], "\n")] = '\0';
size++;
}
}
Note that 10 and 351 only appear once here... Feel free to adjust them as you feel fit, within reason. If you can multiply them into the megabytes region, you might want to consider a different data structure depending on what you intend to do with this.

Related

in c why the dereference of the s point to string value not working?

why when i use the program it return s = null
the get_string function can have update to make the program work
it is : string s = malloc(sizeof(string));
but in the end of the function and after return s; i cant free(s);
or before return s; i will lose the data i stored
i tried to search more about dereference pointers but i got nothing.
#include <stdio.h>
typedef char* string;
string get_string(string q)
{
string s = NULL;
printf("%s",q);
scanf("%s",s);
return s;
}
int main(void)
{
string a = get_string("name : ");
printf("name is %s\n",a);
}
Here are two correct uses of scanf to read a string:
char s1[10];
scanf("%9s", s1);
char *s2 = malloc(100);
scanf("%99s", s2);
Notice that in both cases — s1 and s2 — I had to explicitly say how much memory I wanted for my string. Then, when I called scanf, I included that information — 1 less than the overall string size — in the %s format, so that I could tell scanf not to read a bigger string than my string variable could hold.
Notice, by contrast, that in your get_string function, you did not allocate any memory to hold your string at all. Your variable s was a null pointer, explicitly pointing to no memory at all.
This is something that's very easy to overlook at first: Most of the time, C does not allocate memory for strings for you. Most of the time, this is your responsibility.
Now, an additional concern is that even when you do allocate memory for a string, you have to think about how long that memory will stick around, and whether anyone has to explicitly deallocate it. And there are some additional mistakes that are easy to make. In particular, suppose you took my first example (s1) to heart, and tried to fix your get_string function like this:
char *get_string(char *q)
{
char s[100]; /* WRONG */
printf("%s",q);
scanf("%99s",s);
return s;
}
Here you have given scanf a proper array to read in to, but it's local to the get_string function, meaning that it will disappear after get_string returns, and it will be useless to the caller.
Another possibility is
#include <stdlib.h>
char *get_string(char *q)
{
char s = malloc(100); /* better */
if(s == NULL) {
fprintf(stderr, "out of memory!\n");
exit(1);
}
printf("%s",q);
scanf("%99s",s);
return s;
}
This will work just fine. Note that I have checked to see whether malloc succeeded. (If it fails, it returns a NULL pointer.) But now we have the issue that some memory has been allocated which might never be freed. That is, get_string returns a pointer to dynamically-allocated memory, and it's the caller's responsibility to free that memory when it's no longer needed. The caller doesn't have to, but if there end up being 1,000,000 calls to get_string, and if none of the allocated blocks ever gets freed, that's a lot of memory wasted.
First as other people have noted in the comments the Typedef in this case isn't very helpful as it hides the fact its a pointer. Also char* is vary commonly used and not a type complicated enough for a typedef IMO.
For your other issues the problem appears to be that you are thinking of the value as a C++ string instead of a char pointer. In C there aren't string objects but instead people use char* which can pointer blocks of chars and we determine the end of the string by putting a null character at the end of list of characters.
So the reason you can't print the NULL string is because it is undefined behavior to pass a NULL pointer to printf. When you change it to s = malloc(sizeof(string)); the pointer is no longer null but instead pointing to the start of a block of memory that is sizeof(string) bytes long. You should be doing malloc(sizeof(char)*strlen(q)); instead so you have a block of memory holding a string with the length of string q instead of just one character. More generally it would be malloc(sizeof(char)*NUM_CHARS);.
When it come to the free call. You can't call free(s) after return s; because no statements after return s; will occur because the function has returned and no longer executing. As for calling before, calling free(s) deallocates that block of memory that s is pointing too from the malloc(sizeof(string)) is pointing to. Here you have to remember that the function isn't returning the memory or the string but instead it returns the pointer to the string. So if you delete the memory the pointer is pointing to then you lose it once you return.

why couldn't use a pointer in gets in C? such as char *str replace char str[40] in gets(str)

#include <stdio.h>
int main ()
{
char str[40];
printf("Enter a string : \n");
gets(str);
printf("You entered: %s\n", str);
return 0;
};
in above code, if replace str to a pointer, char *str. Then NULL is out. Suppose gets defined by char *gets(char *str), it should use a pointer instead of array. All examples I saw are array not pointers. Thanks.
function gets() is depracted your libc/compiler might ignore it. try use fgets() instead.
#include <stdio.h>
int main ()
{
char str[40];
printf("Enter a string : \n");
if (fgets(str, sizeof(str), stdin) != NULL)
{
printf("You entered: %s\n", str);
}
return 0;
};
also if you want to don't use stack you need to give pointer that points allocated space. in code str also can be char *str = malloc(40); then change sizeof(str) to 40 since str is no longer stack.
Really interesting question, I have been asked this question a lot!
you should have a bit background of pointers and memory to understand what is happening.
first let's have a brief review about pointers and memory:
our computer have some memory and we can use it in programming, anything that we store (in runtime) for example an int, array of doubles, some complex struct and strings(that they are array of characters) should be somewhere in memory.
pointers contain address of somewhere in memory, some of them know about that memory (how to read/write value) some of them don't.
there is a special value for pointers (NULL) that means nowhere, if pointer is pointing to NULL, that pointer is pointing not nowhere (obviously nowhere is not a valid address in memory)
array is specific type of pointer, a const pointer that is pointing to already allocated memory in stack.
and about gets function: let's think we want to re-implement such function (namely my_gets) , how we suppose to do that? how to return a string (array of characters)?
these are options (as far as i know):
creating a local array in our function and fill it. then we should return it? no we cant! because that array is in stack of our function and after ending the function, our function data including this array will be popped automatically (handled by compiler).
although nobody forbid us from returning that array, but that would cause dangling pointer problem.
allocating some space rather than stack (heap) and fill that. this is perfectly fine and there is methods and do this! for example readline (not in ansi c, you can find it here) will do this. the drawback of this method is that you should take care of that memory and free it later, it also may be not to optimum way and you may should copy that string to your already allocated memory
the last way (and way that gets use) is getting a pointer that is already pointing to a valid memory and fill that memory. you already know that gets want a pointer as input, I add that, that pointer should point to a valid and accessible memory that gets can fill it. if pointer is pointing to NULL (or maybe uninitialized and pointing to some where random) gets will fail writing and cause undefined behavior (segmentation fault for example)
some final points:
array solution work because array name is pointer that pointing to valid memory (array in stack) so it's OK and easy to understand.
If we don't want to use array, we can point our pointer to a valid memory, we need to use malloc/calloc to allocate a block of memory. see this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int size = 40 * sizeof(char);
char* p = malloc(size);
printf("Enter a string : \n");
if (fgets(p, size, stdin) != NULL) {
printf("You entered: %s\n", p);
}
free(p);
return 0;
}
gets is not secure because it doesn't care how much memory we have, it writes until and string ends and it may cause buffer overflow, better option (as people said) is fgets because it care memory size and will not exceed that. but my answer doesn't care it's fgets or gets.

Is there a way to allocate memory in C and initialize during allocation process to value other than 0?

I wonder if there is a way to initialize a string array to a value I decide on during memory allocation, so it won't contain any garbage and the null character will be placed at the correct place. I know that using calloc the memory allocated is initialized to all zeros, but in this case involving strings it doesn't help.
I practice using pointers and allocation memory in C.
There is an exercise in which I wrote a function for copying a string to another string - In main(), I allocate memory using malloc for both strings based on the strings lengths the user provides, and then the user enters the first string.
At this point I send the pointer of the first string and second string (uninitialized) as parameters to strCopy(char* str1, char* str2). Inside that function I also use another basic function I wrote, to calculate the length of a string. but as you may guess, since the second string is full of garbage, it's length calculation inside the function is messed up.
void strCopy(char* str1, char* str2)
{
int str1len = str_len(str1); // basic length calculating function
int str2len = str_len(str2);
int i;
for (i = 0; i < str2len; i++)
{
str2[i] = str1[i];
}
str2[i] = '\0';
if (str2len < str1len)
printf("There wasn't enought space to copy the entire string. %s was
copied.\n", str2);
else
printf("The string %s has been copied.\n", str2);
}
Right now it works fine when initializing str2 in a loop in main(), but I am interested in other possible solutions.
Thank you very much for any help!
No, there is not. You have to manually initialize it.
If you want to copy a string while allocating memory, you can use strdup. Note that this is a POSIX function, which means this will only work on POSIX-compliant operating systems, Windows, and any other OSs that implement it.
Well, for this particular situation you can use memcpy. A simple way could be like this in your code instead of the for loop:
memcpy(str2, str1, str2len);
But your code is seriously flawed. I don't know how you have implemented str_len but there is absolutely no way (if you're not using non-standard, non-portable, dirty hacks) to get the size of the block that a pointer is pointing to.

pointers to structs in c

struct TokenizerT_ {
char* separators;
char* tks;
char* cur_pos;
char* next;
};
typedef struct TokenizerT_ TokenizerT;
TokenizerT *TKCreate(char *separators, char *ts)
{
TokenizerT *tokenizer;
tokenizer = (TokenizerT*)malloc(sizeof(TokenizerT));
//some manipulation here
tokenizer->tks = (char*) malloc (strlen(str)* sizeof(char));
tokenizer->tks=str;
printf("size of tokenizer->tks is %zu\n", strlen(tokenizer->tks)); //this prints out the correct number (e.g. 7)
return tokenizer;
}
int main(int argc, char **argv)
{
TokenizerT *tk = TKCreate(argv[1], argv[2]);
printf("tk->tks: %zu\n", strlen(tk->tks)); //HOWEVER, this prints out the wrong number (e.g. 1)
}
As seen from the above code, I'm working with pointers to structs. For some reason I am not receiving back the correct length for tk->tks. I cannot understand this because it should be the same size as tks in my TKCreate function. Can someone explain this please?
I suspect str, the definition of which is not shown in your code snippet, is a local variable defined in TKCreate(). If so, you're assigning tokenizer->tks to have the value of str, which points to a proper string inside the scope of TKCreate() but upon exiting TKCreate(), the stack contents (including parameters and local variables) are freed and wiped out so when you try to reference that pointer outside the scope of TKCreate() all bets are off.
One plausible fix is to allocate the storage for tokenizer->tks dynamically, so it persists after you exit TKCreate(). I see you do that with a call to malloc but then you overwrite that with an explicit assignment from str. Instead you should copy the contents of str (using strcpy) into the dynamically allocated memory via: strcpy(tokenizer->tks, str);
You should strcpy the contents of str to tokenizer->tks, because when you use the assign operator, you're losing the pointer malloc gave you, creating a memory leak and pointing tokenizer->tks to a local variable, which will be destroyed after the function's return.
So, the approach would be something like this:
tokenizer->tks = (char *)malloc ((strlen(str) + 1) * sizeof(char));
strcpy(tokenizer->tks, str);
Another thing:
Don't forget to free ->tks before you free tk itself.
So, after the printf, you should use:
free(tk->tks);
free(tk);
There's no problem in not freeing the structure and the string (which is in another memory location and not inside the structure's memory space, that's why you have to free they both), if your program is that small, because after it's executed, the program's memory will be wiped out anyways. But if you intend to implement this function on a fully-working and big program, freeing the memory is a good action.
It is not clear where str is defined, but if it is a local variable in the function, your problem is likely that it goes out of scope, so the data gets overwritten.
You're leaking memory because you've forgotten to use strcpy() or memcpy() or memmove() to copy the value in str over the allocated space, and you overwrite the only pointer to the newly allocated memory with the pointer str. If you copied, you would be writing out of bounds because you forgot to allocate enough space for the trailing null as well as the string. You should also check that the allocation succeeds.
Bogus code:
tokenizer->tks = (char*) malloc (strlen(str)* sizeof(char));
tokenizer->tks = str;
Fixed code:
size_t len = strlen(str) + 1;
tokenizer->tks = (char *)malloc(len);
if (tokenizer->tks == 0)
...error handling...
memmove(tokenizer->tks, str, len);
Using memmove() or memcpy() can outperform strcpy() handily (see Why is Python faster than C for some illustrations and timing). There are those who would excoriate you (and me) for using the cast on malloc(); I understand why they argue as they do, but I don't fully agree with them (and usually use the cast myself). Since sizeof(char) is 1 by definition, there's no particular need to multiply by it, though there's no harm done in doing so, either.

Issue with printing char *argv[n] after a function call in C

int readOptions(char *argv[]){
FILE * infile;
char line_buf[BUFSIZ];
int i = 0, j = 0 ;
infile = fopen("options","r");
if(!infile){
fprintf(stderr,"File Read failure\n");
exit(2);
}
while( i < 10 && fgets(line_buf,sizeof(line_buf),infile)!=0){
printf("Line buf : %s",line_buf);
argv[i] = line_buf;
i++;
}
}
int main(){
int j ;
char *options[10];
for(j = 0 ; j< 10 ; j++){
options[j] = malloc(len * sizeof (char));
}
readOptions(options);
for(j=0; j<10 ; j++)
printf("%s %d\n",options[j], j );
}
The problem is that I always see - the program print only the last line read in the file. Where is the mistake ? and am I missing any important pointer concept with this code ?
Every element of argv points to the same line_buf. Use strdup() to create new strings instead (which you will later have to free).
A char* is not a string. It is a pointer. In your loop, you set each char* in your char*[] to point at the beginning of the line_buf array. Thus, each refers to the same data (which, furthermore, is no longer available after returning from the function; you get undefined behaviour at this point and you're just "lucky" - actually very unlucky, because it makes it harder to diagnose the problem - that it seems to "work" as well as it does.)
There is no real string type in C. You must set up separate chunks of memory that will hold the characters, and point at those chunks. If you allocate them dynamically, you will also have to free them. If you want to be able to resize them, or in general handle things of unknown size, that's also on you.
You've written the code to allocate some space, but you don't copy the data into the space - instead, you repoint the pointers at the local buffer. As noted, we use strcpy to copy from one buffer to another. But there's no real point in doing that, if you're going to pass in allocated buffers and limit yourself to their sizes anyway; instead, just fgets directly into the buffers pointed at by the pointers in the argv array, instead of into a local one.
The argv[i]s are not strings in and of themselves, but pointers to areas of memory that contain text strings. That's what you're doing when you say options[j] = malloc(...) -- you're setting aside an area of memory for that pointer to point at. But that area of memory is just an area of memory, it doesn't have anything to do with the pointer, except that the pointer happens to be pointing at it.
So when you say argv[i] = line_buf, that doesn't mean copy the string itself. It means change the pointer, such that argv[i] now points to the same area of memory where line_buf[] starts. Then in the next iteration of your for loop, you overwrite that same area of memory. By the end of the loop, all ten of your pointers are pointing to line_buf, which contains the last line of your file, which is why you get ten copies of that line.
(What's also worth noting is that once readOptions() returns, that area of memory that all your pointers are pointing to is considered undefined, because line_buf[] only "exists" within the readOptions() function. It's only through luck that your program is printing the last line ten times, rather than printing garbage or crashing.)
Now, to copy a string from one place to another, you can use the strcpy() function, which can be added to your program by putting #include <string.h> at the top. You'd then write strcpy(argv[i], line_buf).
Here's what a simple version of strcpy() would look like, so you can see what it's doing:
char *strcpy(char *dest, char *source) {
int i = 0;
while (source[i] != '\0') { /* a zero (or "null") byte means end of string */
dest[i] = source[i];
i=i+1;
}
dest[i] = source[i];
return dest;
}
Notice that strcpy() doesn't have any way of knowing how much space there is to copy into! If you don't have enough space available, it will go right past the end of your space and into who knows what memory areas, which may cause your program to crash or behave strangely. This is called a buffer overrun, and it's one of the most common security errors. So make sure you have enough space before you call strcpy().

Resources