How to copy char array to a double pointer in C - c

Im writing a fairly simple program to read a file line by line and store it into an array of lines, my program compiles fine but it crashes everytime I run it.
This is my code:
#include <stdio.h>
#include <string.h>
#define LINESIZE 512
typedef struct {
char **data;
size_t nused;
} lines_t;
lines_t readlines(FILE *fp);
int main(int argc,char* argv[]) {
FILE *fp;
(void)argc;
if((fp = fopen(argv[1],"r+")) == 0) {
perror("fopen");
}
readlines(fp);
return 0;
}
lines_t readlines(FILE *fp) {
lines_t line_data;
char line[LINESIZE];
char temp[20];
int num_lines = 0;
(*line_data.data) = (char *)malloc(LINESIZE);
while(fgets(line,LINESIZE,fp)) {
sscanf(line,"%s\n",temp);
strcpy(line_data.data[num_lines], temp); /* Program crashes here */
num_lines++;
}
return line_data;
}
The line where I try to copy my array is giving me trouble, So my question is, How do I copy my character array temp into the char **data inside struct lines_t if I am not doing it right?

You are dereferencing an invalid pointer here:
(*line_data.data) = (char *)malloc(15);
line_data.data is a char **. You are trying to deference it but it is not yet set to any meaningful value. You need to allocate memory for line_data.data before you allocate memory for *line_data.data.
(char *)malloc(15) is particularly suspicious also. Where does 15 come from and what are you actually allocating memory for? Casting the result of malloc is generally considered bad practice, and in your case, rightly so, because malloc is declared in stdlib.h and you aren't including that header. If you want to allocate enough space to hold 15 char *, then use malloc(15 * sizeof(char *)) or alternatively, malloc(15 * sizeof(*line_data.data)) (here it is safe to use *line_data.data even if it doesn't point to anything, because sizeof does not evaluate its operand).

You can try malloc line_data.data before strcpy.
lines_t readlines(FILE *fp) {
lines_t line_data;
line_data.data = malloc(LINESIZE);
*line_data.data = malloc(LINESIZE);
return line_data;
}

You first need to allocate memory.
You need to allocate both for the array of strings and string array. Here you need to have an upper limit while calling a malloc.
line_data = malloc(10* sizeof(char*)); // for example here the upper limit is 10
while(fgets(line,LINESIZE,fp)) {
sscanf(line,"%s\n",temp);
line_data.data[num_lines] = malloc(sizeof(char) * (strlen(temp)+1));
strcpy(line_data.data[num_lines], temp); /* Program crashes here */
num_lines++;
}

Related

How to dynamically allocate memory to a array of array in C?

I have the following C struct:
typedef struct {
char *name;
int nfollowers;
char *followers[];
} User;
There's a point in my code where I have to allocate memory for the last variable of the struct (followers) and I'm having issues on it.
I have tried this:
users[nusers].followers = (char **) realloc(users[nusers].followers, sizeof(char));
or this
users[nusers].followers = (char **) realloc(users[nusers].followers, sizeof(char *));
but the output I get after compiling is the following:
error: invalid use of flexible array member
How can I properly do this?
EDIT
Example of how my C file is structured:
User *users;
int i=0, n, nusers=0;
char aux, *str;
fd_in = open(argv[1], O_RDONLY);
if (fd_in >= 0) {
users = (User *) malloc(sizeof(User));
while (aux!='&') {
users[nusers].followers = (char **) realloc(users[nusers].followers, sizeof(char)); //Issue
while (aux != '#') {
...
}
}
}
As mentioned by tadman, instead of char *followers[]; use char **followers; to declare the field.
Also watch out that malloc does not initialize memory (though on linux the memory might be initialized to 0 if it has not been reused) so your use of realloc may result in corrupting the heap. Instead, just use malloc again (or use calloc to allocate the struct).

Proper way to return a string in C

I have the following code:
char* get_address_string(PACKAGE* pkg){
char *c;
sprintf(c, "%02x:%02x:%02x:%02x:%02x:%02x", pkg->address[0], pkg->address[1],
pkg->address[2], pkg->address[3], pkg->address[4], pkg->address[5]);
return c;
}
The code works fine. However, I know this is not the proper way to return a string in C. I am receiving the warning "c is used uninitialized in this function".
What is the proper way to write this function in C?
"Proper way to return a string in C" is not truly possible. In C, a string is a character array (up to and including the null character) and arrays, by themselves, cannot be returned from a function.
A function can return pointers. So the usual method of "return a string" it to:
Return a pointer. char *foo1(...) like char *strdup()
Pass in a pointer to a character array and modify its contents. void foo2(char *,...) like int sprintf(char *dest, const char *format, ...)
Combine 1 & 2 char *foo3(char *, ...) like char *strcpy(char *dest, char *src)
Pass the address of a pointer and update that. foo4(char **ptr) like ssize_t getline(char **lineptr, size_t *n, FILE *stream)
The key is that the memory associated with the pointer must be valid after the function is complete. Returning a pointer to a function's non-static memory is undefined behavior. Successful methods include having the calling code pass in the pointer, or the function providing it via memory allocation of pointer to some persistent value like a global variable or string constant.
What is the proper way to write this function in C?
Current design practice encourages functions like #2 & #3 above to also supply a size_t size so the function knowns the limitations of the memory available.
char *foo2(char *s, size_t size, const pkg_T *pkg) {
int result = snprintf(s, size, "%02x:%02x:%02x:%02x:%02x:%02x",
pkg->address[0], pkg->address[1], pkg->address[2],
pkg->address[3], pkg->address[4], pkg->address[5]);
// encoding error or not enough room
if (result < 0 || result >= size) return NULL;
return s;
}
Another method would allocate memory (I favor the above though). This obliges the calling code to free() the memory.
#define UINT_MAX_WIDTH (sizeof(unsigned)*CHAR_BIT/3 + 3)
char *foo2alloc(char *s, size_t size, const pkg_T *pkg) {
char buf[(UINT_MAX_WIDTH+3)*6 + 1];
int result = snprintf(buf, sizeof buf, "%02x:%02x:%02x:%02x:%02x:%02x",
pkg->address[0], pkg->address[1], pkg->address[2],
pkg->address[3], pkg->address[4], pkg->address[5]);
// encoding error or not enough room
if (result < 0 || result >= size) return NULL;
return strdup(buf);
}
c is a pointer, but no memory is allocated. The return value is ok, that's how it can be done in C.
But you need to allocate memory.
Since c is uninitialized, sprintf writes to an unknown memory location, which leads to unspecified behavior. It might crash immediately, it might not crash at all, or it might crash on some completely unrelated line of code.
You need to initialize the pointer by allocating memory to it with malloc.
char* get_address_string(PACKAGE* pkg){
char *c = malloc(20); // enough room for output as 00:11:22:33:44:55 plus null terminator
if (c == null) {
perror("malloc failed");
exit(1);
}
sprintf(c, "%02x:%02x:%02x:%02x:%02x:%02x", pkg->address[0], pkg->address[1], pkg->address[2], pkg->address[3], pkg->address[4], pkg->address[5]);
return c;
}
Note that even though you know ahead of time how much memory you need, you can't set it aside at compile time via an array. This is wrong:
char* get_address_string(PACKAGE* pkg){
char c[20]; // allocated on the stack, contents unspecified on return
sprintf(c, "%02x:%02x:%02x:%02x:%02x:%02x", pkg->address[0], pkg->address[1], pkg->address[2], pkg->address[3], pkg->address[4], pkg->address[5]);
return c;
}
As is this:
char* get_address_string(PACKAGE* pkg){
char c[20]; // allocated on the stack, contents unspecified on return
char *p = c;
sprintf(p, "%02x:%02x:%02x:%02x:%02x:%02x", pkg->address[0], pkg->address[1], pkg->address[2], pkg->address[3], pkg->address[4], pkg->address[5]);
return p;
}
Since c is allocated on the stack, when get_address_string returns the contents are unspecified, leading again to unspecified behavior.
I prefer allocating heap from the caller so that it's clear who should free it.
#include <stdio.h>
#include <malloc.h>
bool GetString(char ** retString, size_t size)
{
// use size to do range check
sprintf_s(*retString, size, "blah blah blah");
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
size_t size = 100;
char *data = (char *)malloc(size);
if (data)
{
GetString(&data, size);
free(data);
}
return 0;
}

Issue with assignment from incompatible pointer type

Hey so im trying to attempt to read in a file, store it in a hash and then copy it. However i get the incompatible pointer type
struct hash_struct {
int id;
char name[BUFFER_SIZE]; /* key (string WITHIN the structure */
UT_hash_handle hh; /* makes this structure hashable */
};
int main(int argc, char *argv[] )
{
char *lines[80];
FILE* fp = fopen("file.txt","r");
if(fgets(*lines, BUFFER_SIZE, fp) != NULL)
{
puts(*lines);
// do something
}
fclose(fp);
const char **n;
char *names[1024];
strcpy(*names, *lines);
struct hash_struct *s, *tmp, *users = NULL;
int i=0;
for (n = names; *n != NULL; n++)
{
s = (struct hash_struct*)malloc(sizeof(struct hash_struct));
strncpy(s->name, *n,10);
s->id = i++;
HASH_ADD_STR( users, name, s );
}
HASH_FIND_STR( users, "joe", s);
if (s) printf("joe's id is %d\n", s->id);
printf("Hash has %d entries\n",HASH_COUNT(users));
/* free the hash table contents */
HASH_ITER(hh, users, s, tmp) {
HASH_DEL(users, s);
free(s);
}
return 0;
}
The code works when i initialize const char **n, *names = {array elements here};
But it doesnt work with the code i have. Please help.
lines is declared to be an array of char pointers, but doesn't allocate any space for the strings they point to. In your working version, the compiler took care of allocating space for each string.
Plus, you can't use strcpy to copy an array of 80 pointers to an array of 1024 pointers.
Instead, each line you read in needs space to be allocated for it to be read into; then the addresses of each of those can be assigned to an element of names. In fact, as #BLUEPIXY suggests, line should be an array of 80 chars, not an array of 80 pointers-to-chars. Or you could just malloc the space for each new line, and put the address of that line into names.

I'm having trouble with allocating memory with strings

I am having trouble with the allocating memory part of my program. I am supposed to read in a file that contains a list of names then allocate memory for them and store them in the allocate memory. This is what I have so far, but I keep getting a segmentation fault when I run it.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_STRING_LEN 25
void allocate(char ***strings, int size);
int main(int argc, char* argv[]){
char **pointer;
int size = atoi(argv[1]);
allocate(&pointer, size);
}
/*Will allocate memory for an array of char
pointers and then allocate those char pointers with the size of MAX_STRING_LEN.*/
void allocate(char ***strings, int size){
**strings = malloc( sizeof (char) * MAX_STRING_LEN);
}
This is currently not working because I am given a seg fault. Thanks a lot for the help in advance.
void allocate(char ***strings, int size)
{
int i;
// Here you allocate "size" string pointers...
*strings = malloc( sizeof (char*) * size);
// for each of those "size" pointers allocated before, here you allocate
//space for a string of at most MAX_STRING_LEN chars...
for(i = 0; i < size; i++)
(*strings)[i] = malloc( sizeof(char) * MAX_STRING_LEN);
}
So, if you pass size as 10...
In your main you will have space for 10 strings (pointer[0] to pointer[9]).
And each of those strings can have up to 24 characters (don't forget the null terminator)...
Pointers are a little tricky but here is a trick to deal with them:
Lets say you have your main like this:
int main()
{
int ***my_variable;
}
and you know how to operate in my_variable inside main...
To use it in a function you do as following:
add an extra * in the parameter
void f(int ****my_param)
and whenever you want to use it inside the function, use the same way as you would use in main with this little change:
(*my_param) = //some code
by using (*my_param) is the same as if you were using to my_variable in main
You need
*strings = malloc(sizeof(char *) * 10); // Here is the array
(*strings)[0] = malloc(MAX_STRING_LEN);
strcpy((*strings)[0], "The first person");
printf("First person is %s\n", (*strings)[0]);
Dunno where size comes in

Pointers and strings, failing on EOF

Code rewritten to be more clear
void indexe(char * line, unsigned ref) {
unsigned i = 0;
char word[128]; //(1)
//char * word; //(2)
while(*line) {
if(isalpha(*line))
word[i++] = *line; //(1)
//*word++ = *line; //(2)
*line++;
}
}
int main(int argc, const char * argv[]) {
char line[128];
FILE * f = fopen(argv[1], "r");
unsigned x = 0;
while (fgets(line, 128, f)){
indexe(line, ++x);
}
fclose(f);
return 0;
}
Hello, I have tried the two above combinations:
word[] -> word[i++]
*word -> *word++
The whole thing works flawlessly, except when reaching EOF, in which case the pointers syntax fails with a segmentation fault, but not the array syntax.
I am a C total beginner, could someone explain in beginner terms what happens here, and maybe suggest a solution to fix the pointer syntax? (But mostly explain, please)
This version, as posted, is fine:
void indexe(char * line, unsigned ref) {
unsigned i = 0;
char word[128]; //(1)
//char * word; //(2)
while(*line) {
if(isalpha(*line))
word[i++] = *line; //(1)
//*word++ = *line; //(2)
*line++;
}
}
However, if you recomment the code to use the lines marked //(2) instead, you have this:
char * word; //(2
*word++ = *line; //(2)
Which is simply a case of writing to a pointer you haven't initialised with allocated memory. This isn't allowed. You need to keep it as an array, or use something like malloc to reserve storage. If you want to write the function without using an array at all, the code would be:
char *word = malloc(128); // reserve 128 bytes
if (word == NULL) { // these checks are important
fprintf(stderr, "Cannot allocate memory!");
exit(EXIT_FAILURE);
}
...other stuff...
free(word);
Note also that:
*line++;
increments line, but dereferences it (before it's incremented) for no reason.
The pointer syntax fails because you have defined a pointer char * word; but you have not set it to point to any data - the memory you are pointing to can be anywhere. So, when you execute the following statement:
*word++ = *line;
You are storing the value pointed to by line in the value pointed to by word. Unfortunately, you do not know where word is pointing. As #teppic pointed out, you're writing to a pointer that has not been initialized to allocated memory.
You could malloc that memory as #teppic previously pointed out. You could also do the following:
char reserve[128];
char * word = reserve; // could also have used &reserve[0]
Hope that helps!

Resources