I'm writing a simple c program that reads lines from a text file into a char **. In my main function, I create the char * array, allocate memory for it, and pass a pointer to the array to another function to populate each index in the array with a char * representing the content of each line in the text file.
For some reason related to my memory management I'm guessing, I'm receiving a segmentation fault on the third iteration of my while loop, which copies the string into the array of strings. Why is this?
My code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void getRestaurants(char ***restaurantsArray) {
FILE *restaurantsFile = fopen("./restaurants.txt", "r");
char *restaurant = (char *)malloc(50 * sizeof(char));
char *restaurantCopy = restaurant;
//fopen will return null if it is unable to read the file
if (restaurantsFile == NULL) {
free(restaurant);
return;
}
int index = 0;
while (fgets(restaurantCopy, 50, restaurantsFile)) {
// segfault occurs the third time the following line is executed
*restaurantsArray[index] = (char*)malloc(50 * sizeof(char));
strcpy(*restaurantsArray[index], restaurantCopy);
printf("%s", restaurantCopy);
printf("%s", *restaurantsArray[index]);
index++;
}
fclose(restaurantsFile);
free(restaurant);
}
void main() {
char **restaurantsArray = (char **)malloc(100 * sizeof(char *));
char **restaurantsArrayCopy = restaurantsArray;
getRestaurants(&restaurantsArrayCopy);
}
Expected Result:
firstline
firstline
secondline
secondline
thirdline
thirdline
and so on, if the provided restaurants.txt file contains:
firstline
secondline
thirdline
In getRestaurants, restaurantsArray is declared as char ***Array. In the line *restaurantsArray[index] = …;, it takes restaurantsArray[index] and attempts to use it as a pointer (by applying the * operator). But restaurantsArray is merely a pointer to the restaurantsArrayCopy in main. restaurantsArrayCopy is merely a single object, not an array. It is just one char **. In getRestaurants, using restaurantsArray[index] with anything but zero for index uses some undefined thing.
There is no need to pass &restaurantsArrayCopy from main to getRestaurants. Just pass restaurantsArray. This is a pointer to allocated space.
Then, in getRestaurants, instead of *restaurantsArray[index] = …;, use restaurantsArray[index] = …;, without the *. This will assign a value to an element in restaurantsArray, which is what you want to do. Similarly, remove the * in the strcpy and the printf.
Related
I am using OpenGL, don't worry my problem is with C and not something related to OpenGL. In OpenGL, we have something called shaders. It is a text file. All I want to do is to read that text file and pass it to a function that accepts only const char * const*. (eg. func(&shaderSource) and shaderSource must be const char* shaderSource.). I just want this terminology with multiple files. Can I? I saw people doing this with C++, but I chose C over C++ in the project. Here is some of my failed attempts.
char vertexShaderContent[1000] = readfile("Shader/default.frag.txt");
const char *vertexShaderSource;
strcpy(vertexShaderSource, vertexShaderContent);
Here I tried to get a new variable (By the way this is in the main function) that executes the function and gets the return value of that function. Now I did copy that string (using strcat) to assign the value of vertexShaderContent to vertexShaderSource. By the way here is my readfile code:
char *readfile(const char* filename) {
char *res = malloc(sizeof(char *) * 100);
char *word = malloc(sizeof(char *));
FILE *file = fopen(filename, "r");
while (fgets(word, sizeof(word), file) != NULL) {
strcat(res, word);
}
strcat(res, "\n\0");
fclose(file);
return res;
}
Summary
All my problem is that I want to pass a char* to a function accepting const char*s. If I can't, is there is any way I can get this 'multiple' files to work?
Thanks.
In char vertexShaderContent[1000] = readfile("Shader/default.frag.txt");, readfile returns a pointer to char, but vertexShaderContent is an array of char. To initialize an array, one needs to provide values for each element to be initialized. A pointer to char is not a correct type for initializing char values.
What may work here is char *vertexShaderContent = readfile("Shader/default.frag.txt");. That defines vertexShaderContent to be a pointer to the memory returned by readfile. However, it is not clear what you want to do, because the code that follows it is confusing:
const char *vertexShaderSource;
strcpy(vertexShaderContent, vertexShaderSource);
This would overwrite the data at vertexShaderContent with new data, so it loses the data that readfile returned. And it attempts to copy from vertexShaderSource, but vertexShaderSource has not been set to point to anywhere. Its value is indeterminate. This strcpy cannot do anything useful. Since we do not know what you are trying to do here, we cannot recommend a solution.
These lines in readfile are incorrect:
char *res = malloc(sizeof(char *) * 100);
char *word = malloc(sizeof(char *));
The first allocates space for 100 char *. To allocate space for 100 char, use char *res = malloc(100 * sizeof *res);.
The second allocates space for one char *. But it looks like you want space for one “word”, which would likely be some varying number of characters. Maybe you would want to start with space for at least 100 characters:
char *word = malloc(100 * sizeof *word);
That could help get the code going at first, although a good eventual solution would ensure the allocated spacer could not be overflowed.
In strcat(res, word), the data pointed to by res has not yet been initialized. Before using strcat, you must have some string in the destination. That can be the empty string, which you can create by putting a null terminator character in res:
*res = '\0';
All my problem is that I want to pass a char* to a function accepting const char*s.
Nothing in the question shows any attempt to pass a char * for a const char * parameter that would not work, except for the issues noted above.
I am struggling to write a char* passed as an argument. I want to write some string to char* from the function write_char(). With the below code, I am getting a segmentation fault.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void write_char(char* c){
c = (char*)malloc(11*(sizeof(char)));
c = "some string";
}
int main(){
char* test_char;
write_char(test_char);
printf("%s", test_char);
return 0;
}
You have two problems (related to what you try to do, there are other problems as well):
Arguments in C are passed by value, which means that the argument variable (c in your write_char function) is a copy of the value from test_char in the main function. Modifying this copy (like assigning to it) will only change the local variables value and not the original variables value.
Assigning to a variable a second time overwrites the current value in the variable. If you do e.g.
int a;
a = 5;
a = 10;
you would (hopefully) not wonder why the value of a was changed to 10 in the second assignment. That a variable is a pointer doesn't change that semantic.
Now how to solve your problem... The first problem could be easily solved by making the function return a pointer instead. And the second problem could be solved by copying the string into the memory instead of reassigning the pointer.
So my suggestion is that you write the function something like
char *get_string(void)
{
char *ptr = malloc(strlen("some string") + 1); // Allocate memory, +1 for terminator
strcpy(ptr, "some string"); // Copy some data into the allocated memory
return ptr; // Return the pointer
}
This could then be used as
char *test_string = get_string();
printf("My string is %s\n", test_string);
free(test_string); // Remember to free the memory we have allocated
Within the function
void write_char(char* c){
c = (char*)malloc(11*(sizeof(char)));
c = "some string";
}
the parameter c is a local variable of the function. Changing it within the function does not influence on the original argument because it is passed by value. That is the function deals with a copy of the original argument.
You have to pass the argument by reference through pointer to it.
Also the function has a memory leak because at first the pointer was assigned with the address of the allocated memory and then reassigned with the address of the first character of the string literal "some string".
If you want to create a copy of a string literal then what you need is the following
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void write_char( char **s )
{
const char *literal = "some string";
*s = malloc( strlen( literal ) + 1 );
if ( *s ) strcpy( *s, literal );
}
int main( void )
{
char *test_char = NULL;
write_char( &test_char );
if ( test_char ) puts( test_char );
free( test_char );
}
The program output is
some string
Do not forget to allocate dynamically a character array that is large enough to store also the terminating zero of the string literal.
And you should free the allocated memory when the allocated array is not needed any more.
If you want just to initialize a pointer with the address of a string literal then there is no need to allocate dynamically memory.
You can write
#include <stdio.h>
void write_char( char **s )
{
*s = "some string";
}
int main( void )
{
char *test_char = NULL;
write_char( &test_char );
puts( test_char );
}
In C, you'll need to pass a pointer to a pointer. Your malloc call is trying to change the value of the variable that's being passed in, but it's actually only a copy. The real variable you pass in will not be changed.
Also, the way that you copy a string into a char* is not using assignment... Here's some revised code:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void write_char(char** c){
size_t len = strlen("some string");
*c = (char*)malloc(len + 1); // + 1 for null termination
strncpy(*c, "some string", len);
}
int main(){
char* test_char;
write_char(&test_char);
printf("%s", test_char);
return 0;
}
String assignment in C is very different from most modern languages. If you declare a char * and assign a string in the same statement, e.g.,
char *c = "some string";
that works fine, as the compiler can decide how much memory to allocate for that string. After that, though, you mostly shouldn't change the value of the string with =, as this use is mostly for a constant string. If you want to make that especially clear, declare it with const. You'll need to use strcpy. Even then, you'll want to stay away from declaring most strings with a set string, like I have above, if you're planning on changing it. Here is an example of this:
char *c;
c = malloc(16 * sizeof(char));
strcpy(c, "Hello, world\n");
If you're passing a pointer to a function that will reallocate it, or even malloc in the first place, you'll need a pointer to a pointer, otherwise the string in main will not get changed.
void myfunc(char **c) {
char *tmp = realloc(*c, 32 * sizeof(char));
if(tmp != NULL) {
*c = tmp;
}
}
char *c = malloc(16 * sizeof(char));
strcpy(c, "Hello, world\n");
myfunc(&c);
char* test_char="string"; // initialize string at the time of declaration
void write_char(char* c){
c = (char*)malloc(11*(sizeof(char)));
}
int main(){
char* test_char="strin";
write_char(test_char);
printf("%s", test_char);
return 0;
}
I am trying to create a program that populates a fixed-size argument array using the arguments passed through the terminal. My first step is trying to create and populate the array of default argument strings, which I have succeeded in doing. However, I am now trying to use malloc() to allocate space for this array, and cannot get it to compile. I've tried everything I can think of regarding the proper syntax. I've tried doing more research into malloc() and how to use it for two dimensional arrays, but I haven't found any information that helps me. I'm stuck and not sure what to do next. Here is the code:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define MAX_NUM_OF_ARGS 5
#define MAX_ARG_SIZE 256
int main(int argc, char **argv) {
printf("%s%d\n", "Length: ", argc); //for debug purposes
// Make sure we don't have more than five arguments
if(argc > MAX_NUM_OF_ARGS) {
printf("%s", "Too many arguments. Must enter fewer than 4.");
}
// Populate the array
else{
char defaultArgs[] = "defaultArgs"; //create default argument array
//allocate memory for default array
char argumentArray[MAX_NUM_OF_ARGS][MAX_ARG_SIZE] =
(char *)malloc(MAX_NUM_OF_ARGS * MAX_ARG_SIZE * sizeof(char));
//populate array with default arguments
for (int i = 0; i < MAX_NUM_OF_ARGS; i++) {
strcpy(argumentArray[i], defaultArgs);
printf("%s\n", argumentArray[i]);
}
free(argumentArray);
return 0;
}
}
When I try to compile I get an invalid initializer error at the (char*) cast for malloc(). I've tried casting it to (char**) and (char) and also changing the sizeof(char) to sizeof(char*) and sizeof(char**).
I am not really sure what I am doing wrong at this point and I am at a loss as far as what to even try next.
You've declared argumentArray as a two-dimensional array of char. The malloc function returns a pointer, so you can't assign a pointer to an element of this array.
You need a pointer to store what's being returned. Actually, in this case you need a pointer to a pointer, and you'll need to call malloc multiple times, once for an array of pointers for the arguments, then again in a loop for each argument:
char **argumentArray = malloc(MAX_NUM_OF_ARGS * sizeof(char *));
for (int i=0; i<MAX_NUM_OF_ARGS; i++) {
argumentArray[i] = malloc(MAX_ARG_SIZE);
strcpy(argumentArray[i], defaultArgs);
printf("%s\n", argumentArray[i]);
}
You cannot store an array of strings in C, as a string is a variable-length datastructure, not a simple type.
So, decide what you want:
An array of fixed-length buffers storing strings of fixed (maximum) length.
char (*p)[MAX_LEN] = malloc(n * sizeof *p);
// Store the strings at p[0], p[1], …, p[n - 1]
A buffer storing any number of strings consecutively.
char* p = malloc(sum_of_string_lengths + count_of_strings);
// Now fill in the strings one after the other, including Terminator
An array of pointers to strings.
char** p = malloc(n * sizeof *p);
p[0] = strdup(source[0]);
// ...
// p[n - 1] = ...
With strdup() the common utility-function defined like:
char* strdup(const char* s) {
size_t n = strlen(s) + 1;
char* r = malloc(n);
if (r)
memcpy(r, s, n);
return r;
}
Try thinking about it like this:
Strings are character pointers
You need an array of character pointers
Here is an example where I make an array of char *. Essentially the pointer returned by malloc points to an area where char * will reside. Here is an illustration of what is going on.
/*
malloc_ret_ptr ---> [ char * my_str1 | char * my_str2 | char * my_str3 ]
| | |
| | |
v v v
"Thank" "You" "Chicago"
*/
int main() {
char * my_string = "this is my string";
char ** my_string_array;
my_string_array = malloc(sizeof(char*)*10); //Create an array of character pointers
//Place char * inside of char * array
my_string_array[0] = my_string;
return 0;
}
I need to read some data from text file and store it in 2D-array.
This code works good:
#include <string.h>
#include <stdio.h>
int main() {
FILE *f = fopen("Read.txt", "r");
char buff[100][100];
char str[100];
int i = 0;
while(fgets(str, 100, f)) {
strcpy(buff[i], str);
i++;
}
return 0;
}
But why doesn't it work when I try to change buff definition in line 5 to:
char (*buff)[100];
I expected this definition to work too.
The error I get:
Run-Time Check Failure #3 - The variable 'buff' is being used without being defined
char (*buff)[100];
Here buff is a pointer to an array of 100 characters. So first you should make the pointer point to valid memory location before storing some value in it.
Presuming you want to go for dynamic memory allocation then you can have
char *buff[100];
Now in the fgets() loop allocate memory to each pointer individually like
buff[i] = malloc(100);
Note here buff is an array of 100 char pointers.
I have a function whichtakes a file, reads it line by line, puts every line in a *char[], puts this twodimensional array in a struct, and returns this struct:
wordlist.h:
#ifndef H_WORDLIST
#define H_WORDLIST
typedef struct {
char **chWordsList;
int listlen;
}Wordlist;
Wordlist getWordlistFromFile(char *chFilename);
char *getRandomWord();
#endif
The function (plus headers):
#include "wordlist.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define WORDSIZE 100
Wordlist getWordlistFromFile(char *chFilename){
FILE *file = fopen(chFilename,"r");
if (file == NULL){
printf("Unable to open file %s. Check if the file exists and can be read by this user.\n",chFilename);
exit(1);
}
char chWord[WORDSIZE];
int intFileSize = 0;
//First: coundt the amount of lines in the file
while((fgets(chWord,WORDSIZE,file) != NULL)){
++intFileSize;
}
rewind(file);
char *chWordList[intFileSize];
for (int count = 0; (fgets(chWord,WORDSIZE,file) != NULL); ++count){
chWordList[count] = malloc( strlen(chWord +1));
strcpy(chWordList[count],chWord);
chWordList[count][strlen(chWord) -1] = 0;
}
fclose(file);
Wordlist wordlist;
wordlist.chWordsList = chWordList;
wordlist.listlen = intFileSize;
for (int i = 0; i < wordlist.listlen; ++i){
printf("%s\n", wordlist.chWordsList[i]);
}
return wordlist;
}
So far this works great. The last for loop prints exactly every line of the given file, all fully expected behaviour, works perfect. Now, I actually want to use the function. So: in my main.c:
Wordlist list = getWordlistFromFile(strFilePath);
for (int i = 0; i < list.listlen; ++i){
printf("%s\n", list.chWordsList[i]);
}
This gives me the weirdest output:
abacus
wordlist
(null)
(null)
��Ⳏ
E����H�E
gasses
While the output should be:
abacus
amused
amours
arabic
cocain
cursor
gasses
It seems to me almost like some pointers get freed or something, while others stay intact. What is going on? Why is wordlist perfect before the return and broken after?
char *chWordList[intFileSize]
This array of strings is allocated on stack since it's declared as a local of getWordlistFromFile. Upon exiting the function the stack pointer is decreased and the array is no longer valid.
You should use the same approach used for the single string: allocate in on heap.
char **chWordList = malloc(intFileSize*sizeof(char*))
In this way the array will persist the scope of the function and you will be able to use it after the call to the function.
Because you are returning pointers to objects whose lifetime has expired. In particular, chWordsList inside the return value points to an object whose lifetime ends when the function returns. When you dereference that pointer you get undefined behavior (UB); therefore any result would not be surprising.
What you need to do is malloc memory for the chWordList instead of declaring it as a local array:
char **chWordList = malloc(intFileSize * sizeof(char*))
Change
char *chWordList[intFileSize];
to
char **chWordList = malloc(sizeof(char *) * intFileSize);
i.e allocated chwordList and set that in the WordList.
Your code is returning array variable chWordList allocated on stack, so it will not be valid once the function getWordlistFromFile() completes and returns to main().