Values of the same pointer are different depending where I call it - c

My program is using a main function to prompt the user to choose which function to use and then sending the reference to a char double pointer to the function they choose. In the function, I allocate memory dynamically for the number of strings. Then, for each string, I allocate memory depending on the incoming string length.
void readFile(char *** fileAsArray){
/* file name found, file opened, set to FILE *input */
int numWords = 0;
*fileAsArray = malloc(5000 * sizeof(**fileAsArray));
while(fgets(line, sizeof(line), input){
char *word = strtok(line, " \n");
while(word){
int wordSize = strlen(word);
int i;
(*fileAsArray)[numWords] = malloc(wordSize * sizeof((**fileAsArray)[numWords]));
(*fileAsArray)[numWords] = word;
printf("%s", (*fileAsArray)[numWords]); // CORRECT WHEN CALLED HERE
numWords++;
word = strtok(NULL, " \n");
}
}
printf("%s", (*fileAsArray)[0]); //INCORRECT WHEN CALLED HERE??
}

(*fileAsArray)[numWords] = malloc(wordSize * sizeof((**fileAsArray)[numWords]));
(*fileAsArray)[numWords] = word;
Is overwriting the pointer to allocated buffer by word and causing memory leak.
strcpy() should be used to copy strings.
Also you forgot to allocate for teminating null-character.
The part should be:
(*fileAsArray)[numWords] = malloc((wordSize + 1) * sizeof((**fileAsArray)[numWords]));
strcpy((*fileAsArray)[numWords], word);

Related

How can I keep an array of strings whose elements are added based on a parameter but don't change with every function call?

I have been trying to make a program which acts like a terminal, and has an array of filenames which are needed in functions acting like the Linux commands, touch(), cat(), etc.
I first attempted to define a char* file_names[1024] = {} in main().
int main(int argc, char** argv) {
char* file_names[1024] = {};
for (int i = 0; i < 1024; i++) {
file_names[i] = NULL;
}
read_cmds(file_names);
}
I pass this array along with char file1[] to touch() (both decaying to pointers).
int read_cmds(char* fnames[1024]) {
char buff[1024];
char cmd[1024];
char file1[1024];
// char file2[1024];
char txt[1024];
int num = 0;
while (fgets(buff, 1024, stdin) != NULL) {
if (!strncmp(buff, "touch", 5)) {
num = sscanf(buff, "%s %s %s\n", cmd, file1, txt);
tch(fnames, file1, txt);
}
}
}
I added the file name to the array.
void tch(char* fnames[1024], char* name, char* contents) {
char* file_name = name;
strcat(file_name, ".file");
int pos = next_empty(fnames);
char file_arr[1024];
strcpy(file_arr, file_name);
fnames[pos] = file_arr;
fclose(new_file);
}
However, since the array stores the memory address, it seems that with each function call to touch() I make with a different file name, the address of file_name and thus value in fnames[0] changes to the address of the new parameter.
touch j
fnames[0] at tch: (null)
touch j
fnames[0] at tch: j.file
The file provided already exists.
touch s
fnames[0] at tch: j.file
touch p
fnames[0] at tch: s.file
How do I get the array to not change values? Even if I strcpy to an array, it still stores the address and changes the value of fnames[0] later in the function. If I use an array of arrays, it still doesn't work and wouldn't the value allocated for the array be destroyed once the function ends?
If you wish to change a string without altering the original, you need to copy it to new memory.
Let's go over the issues in your code.
char* file_name = name;
strcat(file_name, ".file");
char* file_name = name; just copies the pointer so strcat(file_name, ".file") alters the same memory as name. And you need to make sure there is enough space to add the .file extension or you risk overwriting adjacent memory.
char file_arr[1024];
strcpy(file_arr, file_name);
fnames[pos] = file_arr;
char file_arr[1024] allocates memory on the stack, otherwise known as "automatic memory". It is "automatic" because it will automatically be deallocated when the function exits. So file_arr will point to invalid memory once tch returns.
Instead, allocate new memory with sufficient space for the existing string, plus the extension. This memory will last until it is freed.
// Allocate memory for the filename, extension, and null byte.
char *file_name = malloc(strlen(name) + strlen(".file") + 1);
// Copy the file name to the new memory.
strcpy(file_name, name);
// Add the extension.
strcat(file_name, ".file");
// Make fnames point at the new string.
int pos = next_empty(fnames);
fnames[pos] = file_name;
char* file_names[1024] = {};
for (int i = 0; i < 1024; i++) {
file_names[i] = NULL;
}
If you initialize an array with {NULL} it will set every element to NULL. So the above can be replaced with...
char* file_names[1024] = {NULL};
Instead of making tch responsible for changing the array, which has nothing to do with touching a file, return the new filename.
char *tch(const char* name const char *contents) {
char *file_name = malloc(strlen(name) + strlen(".file") + 1);
strcpy(file_name, name);
strcat(file_name, ".file");
// do something with file_name and contents
return file_name;
}
Then make the caller responsible for what to do with the result.
int i = 0;
while(fgets(buff, sizeof(buff), stdin) != NULL) {
if (!strncmp(buff, "touch", 5)) {
num = sscanf(buff, "%s %s %s\n", cmd, file1, txt);
fnames[i] = tch(file1, txt);
i++;
}
}

Where is the error? (C program won't print out the content of dynamic array)

The task was to read the first 20 lines from a specific file and format them to use only specific parts, the next step was to store those formatted strings in a dynamic array (char ** str | a pointer to a pointer), send it to a function and print it out with said function
Here is the main code:
int main(int argc, char* argv[]){
FILE* file = fopen("./passwd.txt", "r"); // open file
if (!file)
{
perror("Error opening file");
return 1;
}
char line [MAXCHARS];
int counter = 0;
char ** str;
str = malloc(20 * sizeof (char*));
while (fgets(line, MAXCHARS, file) && counter < 20) {
char * position;
if ((position = strchr(line,':'))){
char * end_char;
*position = 0; //setting here the value 0, will terminate the string line (first column)
if((position = strchr(++position,':')) && (end_char = strchr(++position,':'))){ //increment the position to skip the second column
*end_char = 0; //set the value 0 to end_char to terminate the string pointed by position
char * temp_str = "\0";
sprintf(temp_str, "{%d} - {%s}\n", atoi(position), line ); //concatenate line and userID into one string and store it into a temporary string
*(str + counter) = malloc(sizeof (char) * strlen(temp_str)); //set the memory space for the temp_string into the array
*(str + counter) = temp_str; //copy the string into the array
}
}
counter++;
}
printArray(str);
fclose(file);
if (line)
free(line);
return 0;
}
And here is the print function:
void printArray(char ** array){
for(int i = 0; i < 20; i++){
printf("%s",*(array+i));
free(*(array+i));
}
free(array);
}
I cannot find the error, the code compiles with
Process finished with exit code -1073741819 (0xC0000005)
So at least it compiles, and I think is just a problem in my pointers handling skills, but I'm not able to find the error.
Can someone help me?
there are 3 errors in your program :
use temp_str which haven't allocated.
char * temp_str = "\0";
sprintf(temp_str, "{%d} - {%s}\n", atoi(position), line );
save temp_str local pointer's address to str+counter and use the pointer after it went out of scope at printArray=> undefined behavior
line is not a pointer, can't use free
if (line)
{
free(line);
}
lets try this. https://godbolt.org/z/7KPfnTEMY I correct these points

Function to populate string array doesn't include the 0th element after called from main

I have the following function which takes in a pointer to an array and populates it:
void parse(char *path, char *array[]){
char *temp = malloc(sizeof(path));
strcpy(temp, path);
char *token = strtok(temp, "/");
int i = 0;
while(token != NULL){
array[i++] = token;
token = strtok(NULL, "/");
}
free(temp);
}
Which is called from main like so:
...
char *array[3];
path = argv[1];
parse(path, array);
...
However, When I print the elements of the array from inside the parse function before it returns, I get the correct output, i.e. if the path is one/two/three/, it will output:
one
two
three
But If I print the elements of the array from main after calling parse(), the output doesn't contain the element at array[0]:
two
three
The code used the print the elements is as follows:
for (int i = 0; i < 3; i++){
printf("%s \n", array[i]);
}
I figure there's something I'm missing related to C pointers or strings, since I don't understand why this is happening.
EDIT: commenting out the line free(temp) fixed this issue, though why would this specifically affect the first item of the array and not the whole array?
Here
char *temp = malloc(sizeof(path));
you're allocating the size of a pointer. Instead
char *temp = malloc(strlen(path)+1);
to allocate the size of the string pointed to by path (+1 for the trailing \0).
Reason: strcpy(temp, path) is likely to take more chars than the size of a pointer, which outcome in this case is undefined behavior.
Also, strtok returns pointers into temp, which is freed at the end of the function. Therefore, undefined behavior again.
So you better do the allocation of a temp string in main, then free it after use: in main()
char *array[3];
char *path = argv[1];
char *temp = malloc(strlen(path)+1);
strcpy(temp, path);
parse(temp, array);
for (int i = 0; i < 3; i++){
printf("%s \n", array[i]);
}
free(temp);
And parse()
void parse(char *path, char *array[]){
char *token = strtok(path, "/");
int i = 0;
while(token != NULL){
printf("%s\n",token);
array[i++] = token;
token = strtok(NULL, "/");
}
}
You could also
keep allocation of temp in parse()
have parse() return temp (without freeing it)
in main() you store that pointer in a variable char *tobefree = parse(...);
then do the operations with array
then free(tobefree);

Getting unlimited input in C?

So I'm trying to program a function which allows the user to enter an unlimited amount of chars. For example this:
char string[100]
limits the input to 100 characters.
The code i have so far is:
#include<stdio.h>
char* uinput(){
char *string, *current;
int counter = 0;
string = (char *) malloc(10 * sizeof(char));
do{
realloc(string, counter * sizeof(char));
current = string + counter;
*current = getchar();
counter++;
}while(*current != '\n');
return string;
}
int main(){
char *s;
s = uinput();
printf("\nYou entered: %s", *s);
return 0;
}
I'm new to pointers, so I'm not sure why this doesn't work(Program crashes). What I'm trying to do is keep reading a character and keep relocating the string pointer so the amount of bytes keeps increasing until the user presses enter ('\n').
Thanks
~Raf
Ok I think this is the problem
you are re-allocing
realloc(string, counter * sizeof(char));
The what will be the size of string in first iteration? It will be 0.
Now you are writing to a pointer which has 0 bytes allocated and hence segfault.
Changing it to a while loop can help to fix it. You can also change the initial value of counter to fix it
The approach is sane, but there are minor details that are wrong. If you compile with warnings enabled, you'd notice that you're missing <stdlib.h>; also you're giving the first character to printf instead of the pointer to the buffer.
Then there is the obvious bug that your size is reset to 0, and you're casting the return value of malloc, using char to store the result of getchar() which is also wrong because you cannot check against EOF. You're not saving the realloced pointer; and you're not terminating the string properly. On minor detail, you'd want to double the size of buffer in each realloc, because realloc needs to potentially copy the whole line, so it becomes slower and slower over time as the line grows in length.
Thus we get:
#include <stdio.h>
#include <stdlib.h>
char* uinput() {
char *string;
// number of characters in the buffer
size_t counter = 0;
// size of allocated buffer
size_t allocated = 16;
int c;
string = malloc(allocated); // sizeof(char) is 1
do {
c = getchar();
if (c == EOF) {
break;
}
// if our buffer is too small, double the allocation
if (counter + 2 <= allocated) {
size_t new_size = allocated * 2;
char *new_buffer = realloc(string, new_size);
if (! new_buffer) {
// out of memory? try smaller increment
new_size = allocated + 16;
new_buffer = realloc(string, new_size);
if (! new_buffer) {
// really out of memory: free old block
free(string);
return NULL;
}
}
allocated = new_size;
string = new_buffer;
}
// store the character
string[counter++] = c;
} while (c != '\n');
// terminate the buffer properly
string[counter - 1] = '\0';
return string;
}
int main() {
char *s = uinput();
if (!s) {
// possibly out of memory in uinput
perror("Error reading input");
exit(EXIT_FAILURE);
}
printf("\nYou entered: %s", s);
free(s);
return EXIT_SUCCESS;
}
You could try something like the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct person{
char *name;
}pers;
void addMem(void);
int main(void){
addMem();
printf("\nYour name is:> %s\n",pers.name);
free(pers.name);
pers.name = NULL;
return 0;
}
void addMem(void){
unsigned int length = 6;
size_t newLength = 0;
unsigned int newSize = 0;
unsigned int i =0;
char *name;
int c;
name = malloc(length);
if(name == NULL){
exit(1);
}
newSize = length;
printf("Enter your name:> ");
while ((c = getchar()) != '\n' && c!=EOF){
name[i++]=(char)c;
if(i == newSize){
newSize = i+length;
name = realloc(name, newSize);
}
}
name[i] = '\0';
newLength = strlen(name)+1;
pers.name = malloc(newLength);
memcpy(pers.name, name, newLength);
free(name);
name = NULL;
}
Another approach is to use fgets(), which gets a string into a sized buffer from the input stream; if it has the complete input then the string ends with \n; if it doesn't then it doesn't. So you can loop calling fgets until there is an EOL character at the end, then depending on what your program does with the input you can decide whether to keep realloc-ing or to process the input a bit at a time.
use getchar, malloc and realloc for reading the unlimited input string
Declare String type, you can also use char *
// String type
typedef char *String;
I write this function for joining the char in the end of string
/**
* Join the Char into end of String
*
* #param string - String
* #param c - joined char
*/
void String_joinChar(String *string, const char c)
{
const size_t length = strlen(*string);
(*string) = (String)realloc((*string), sizeof(char) * (length + 2));
(*string)[length] = c;
(*string)[length + 1] = '\0';
}
This function for inputting string, which read the char from keyboard by using getchar and join it in the end of current string.
/**
* Input String
*
* #return Inputed String
*/
String String_input()
{
String string = (String)malloc(sizeof(char));
strcpy(string, "");
char cursor;
fflush(stdin);
while ((cursor = getchar()) != '\n' && cursor != EOF)
{
String_joinChar(&string, cursor);
}
return string;
}
Cause of using char *, malloc and realloc, we must free it
/**
* Destroy String
*
* #param string - Destroyed String
*/
void String_destroy(String string)
{
free(string);
}
And now we just use it !!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
String string = String_input();
printf("\n%s\n", string);
String_destroy(string);
return 0;
}
Hope useful to you!

How to Dynamically Allocate a string within a struct with fscanf or fgets?

I'm trying to allocate a string within a struct with fscanf,
I tried this:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <Windows.h>
#include <string.h>
typedef struct _SPerson {
char *name;
char *surname;
char *id;
char *telephone;
}SPerson;
void main (void) {
unsigned int ne;
SPerson Archive[1000];
Load(Archive,&ne);
}
int Load(SPerson Archive[],unsigned int *ne) {
int k,i=0;
char s[4][20];
FILE *f;
f = fopen("archive.txt","r");
if(f==0) return 0;
while((k=fscanf(f,"%s %s %s %s",s[0],s[1],s[2],s[3]))==4) {
Archive[i].id = (char*) malloc( sizeof(char) *strlen(s[0]));
Archive[i].id =s[0];
Archive[i].name = (char*) malloc( sizeof(char) *strlen(s[1]));
Archive[i].name = s[1];
Archive[i].surname = (char*) malloc( sizeof(char) *strlen(s[2]));
Archive[i].surname = s[2];
Archive[i].telephone = (char*) malloc( sizeof(char) *strlen(s[3]));
Archive[i].telephone =s[3];
i++;
}
*ne = i;
fclose(f);
return 1;
}
Maybe in my brain it's correct, but something went wrong while loading the data, so is this the correct and clear method to read strings dynamically?
I thought to use fgets, but my string is separated by a space, so I need to implement another function, the split. Can Anyone help me?
while((k=fscanf(f,"%s %s %s %s",s[0],s[1],s[2],s[3]))==4) {
//your code
i++;
}
Instead of this use fgets to read complete data and then tokenize it using strtok -
char data[1024],*token;
int j=0;
while(fgets(data,sizeof data,f)!=NULL){ //read from file
token=strtok(data," "); //tokenize data using space as delimiter
while(token!=NULL && j<4){
j=0;
sprintf(s[j],"%s",token); //store it into s[i]
j++;
token=strtok(NULL," ");
}
Archive[i].id = malloc(sizeof *Archive[i].id * (strlen(s[0])+1)); //allocate memory
strcpy(Archive[i].id,s[i]); //copy at that allocated memory
//similar for all
i++;
}
This can be used instead of your loop.
Note - Do not do this -
Archive[i].id = (char*) malloc( sizeof(char) *(strlen(s[0])+1));
Archive[i].id =s[0]; <-- 2.
As after 2. statement you will lose reference to previous allocated memory and will not be able to free it — causing a memory leak.
This is same for all such following statements.
A couple of quick suggestions to improve:
1) void main (void) is really not a good prototype for main. Use:
int main(void);
Or:
int main(int argc, char **argv);
2) There is no need to cast the return of [m][c][re]alloc in C.
This line in your code:
Archive[i].id = (char*) malloc( sizeof(char) *strlen(s[0]));
^^^^^^^ ^^^^^^^^^^^^^^ //^^^ == remove
Should be written:
Archive[i].id = malloc( strlen(s[0]) + 1);//no cast, and sizeof(char) is always == 1
//"+ 1" for NULL termination
3) Suggest using fgets(), strtok() and strcpy() as a minimal method to read, parse and copy strings from file into struct members:
Note: there will be a number of calls to malloc() here, and
each will have to be freed at some point. To avoid all that, it would
be better if your struct contained members with hard coded stack
memory:
typedef struct
{
char name[80];
char surname[80];
char id[80];
char telephone[80];
}SPerson;
But assuming you have a reason to use heap memory, here is a way to do it using the struct as you have defined it:
char line[260];//line buffer (hardcoded length for quick demo)
char *tok={0};//for use with strtok()
int len = 0;//for use with strlen()
FILE *f;
f = fopen("archive.txt","r");//did not have example file for this demo
//therefore do not have delimiters, will guess
if(f==0) return 0;
i = 0;//initialize your index
while(fgets(line, 260, f))
{
tok = strtok(line, " ,\n\t");// will tokenize on space, newline, tab and comma
if(tok)
{
len = strlen(tok);
Archive[i].id = malloc(len + 1);//include space for NULL termination
strcpy(Archive[i].id, tok);//note correct way to assign string
//(Archive[i].id = tok is incorrect!!)
}
else {//handle error, free memory and return}
tok = strtok(NULL, " ,\n\t");//note NULL in first arg this time
if(tok)
{
len = strlen(tok);
Archive[i].name= malloc(len + 1);//include space for NULL termination
strcpy(Archive[i].name, tok);
}
else {//handle error, free memory and return}
//...And so on for rest of member assignments
//
i++;//increment index at bottom of while loop just before reading new line
}

Resources