Keeping the value of a String initialized into a function - c

I know my title isn't clear, It will be clearer with code + examples.
I want to initialize a char* ("motSecret" in the main, "mot" in my function) containing a word selected randomly into a file, doing this into a function. This array is made dynamic using memory allocation.
The variable in my function get well initialized, but when I print the value just after I exited the function, the value change and become something like "0#"
Here is the part concerned in the main :
int main()
{
FILE* dico =NULL;
char *motSecret, *motRes;
char lettre=' ';
int check=0, nbCoups=10, longueur=0, nbMots=0;
Bool erreur = TRUE;
srand(time(NULL));
nbMots = scanDico(dico);
getWord(dico, nbMots, motSecret);
printf("Mot : %s", motSecret);
The problem appears after the function getWord(). Here is the code of this function :
void getWord(FILE* dico, int nbLignes, char *mot)
{
int numMotChoisi=rand() % nbLignes, nbChar=0;
char charActuel=' ';
dico = fopen("dico.txt", "r");
rewind(dico);
if(dico != NULL)
{
while (numMotChoisi > 0)
{
charActuel = fgetc(dico);
if (charActuel == '\n')
numMotChoisi--;
}
charActuel = ' ';
while(charActuel != '\n')
{
charActuel = fgetc(dico);
nbChar++;
}
fseek(dico,-(nbChar)-1,SEEK_CUR);
mot = malloc(nbChar * sizeof(char));
if(mot == NULL)
{
printf("Probleme d'allocation memoire");
exit(0);
}
fgets(mot, SIZE, dico);
mot[strlen(mot) - 1] = '\0';
printf("Mot = %s ", mot);
}
fclose(dico);
}
The printf at the end of the function return a good value, and the printf just after the getWord() in the main show that the value changed in the function haven't been "saved"...
Other thing, that works fine without memory allocation.
I hope I'm clear enough. If I forgot to tell something or if you need more informations, please tell me.

C uses pass by value in function parameter passing.
You need a double pointer, something like void getWord(FILE* dico, int nbLignes, char **mot) if you want to allocate memory inside another function.
As a cascased effect, printf("Mot : %s", motSecret); is trying to access uninitialized memory, causing undefined behaviour.
Suggestions:
I see no reason to use FILE *dico as a parameter in getWord(). In can very well be a local.
instead of using double pointer, i would like to recommend returning the allocated pointer from getWord(), i.e., change void getWord() to char * getWord(), add return mot and use like motSecret = getWord(<params>)

char *motSecret;
motSecret is a local variable withing main() and it is not initilized.
By calling
getWord(dico, nbMots, motSecret);
You are passing some uninitialized pointer to a function getword().
Inside getword() you are assigning some memory to
char *mot;
and writing some data to this memory.
Now this memory is not known to motSecret You have to return this memory address to the uninitialized pointer in main()
char *motSecret = getWord(dico, nbMots);
Your getword() should be like,
char *getWord(dico, nbMots);
and inside this after performing everything do,
return mot;

Related

C - Unable to copy a string in a function

This function is to split string based on \n and see if the row number is selected. If the row number matched, this string should be copied and used by other function:
void selectDeparment(char* departments, int selectedNum, char* selectedDepartment){
char* copyOfDepartments = malloc(strlen(departments)+1);
strcpy(copyOfDepartments,departments);
char* sav1 = NULL;
char* token = strtok_s(copyOfDepartments,"\n",&sav1);
int counter = 0;
while(token != NULL){
if(counter == selectedNum){
selectedDepartment = malloc(strlen(token)+1);
strcpy(selectedDepartment,token);
}
++counter;
token = strtok_s(NULL, "\n", &sav1);
}
}
This function is called in main like:
char* selectedDepartment;
selectDeparment(recordsPtr[0], 1, selectedDepartment);
printf(selectedDepartment);
recordsPtr[0] contains four strings with \n at the end:
aDeparment
anotherDepartment
newDepartment
otherDepartment
In C, we are encouraged to use pointer to get a value from function instead of returning a string from a function. However, the prinft in main function gives random output
I believe there is some confusion in the way you are using pointers here. Let me clarify.
In the main function, the character pointer selectedDepartment holds a certain memory in the computer. But when a function call is made to void selectDeparment(char* departments, int selectedNum, char* selectedDepartment), a new copy of selectedDepartment is created. Henceforth any changes which are made to selectedDepartment are done only at the scope of the called function and does not impact the original pointer in the main function.
Thus one clear way to solve this problem will be to pass a pointer to the character pointer defined in the main function. This will then give the correct/expected results.
Here is the modified version of the function -
void selectDeparment(char* departments, int selectedNum, char** selectedDepartment){
char* copyOfDepartments = malloc(strlen(departments)+1);
strcpy(copyOfDepartments,departments);
char* sav1 = NULL;
char* token = strtok_s(copyOfDepartments,"\n",&sav1);
int counter = 0;
while(token != NULL){
if(counter == selectedNum){
(*selectedDepartment) = malloc(strlen(token)+1);
strcpy(*selectedDepartment,token);
}
++counter;
token = strtok_s(NULL, "\n", &sav1);
}
}
And this is how it is called from the main function -
int main() {
char* recordsPtr[] = {"aDeparment\nanotherDepartment\nnewDepartment\notherDepartment"};
char* selectedDepartment;
selectDeparment(recordsPtr[0], 1, &selectedDepartment);
printf(selectedDepartment);
}
I think you are getting confused with the "A Pointer To What?" you are supposed to return. In your selectDeparment() function, if I understand what is needed, is you simply need to return a pointer to the correct department within recordsPTR. You do not need to allocate or tokenize to do that. You already have the index for the department. So simply change the return-type to char * and return departments[selectedNum];.
For example, you can whittle-down your example to:
#include <stdio.h>
char *selectDeparment (char **departments, int selectedNum){
return departments[selectedNum];
}
int main (void) {
char *selectedDepartment = NULL;
char *recordsPTR[] = { "aDepartment\n",
"anotherDepartment\n",
"newDepartment\n",
"otherDepartment\n" };
selectedDepartment = selectDeparment (recordsPTR, 1);
fputs (selectedDepartment, stdout);
}
Note: the '*' generally goes with the variable name and not the type. Why? Because:
int* a, b, c;
certainly does NOT declare three-pointers to int,
int *a, b, c;
makes clear that you have declared a single-pointer to int and two integers.
Example Use/Output
Running the example above you would have:
$ ./bin/selectedDept
anotherDepartment
You will want to add array bounds protection to ensure the index passed does not attempt to read past the array bounds. That is left to you.
If You Must Use void
If you must use a void type function, then you can pass the Address Of the pointer to the function so the function receives the original address for the pointer in main(). You can then assign the correct department to the original pointer address so the change is visible back in main(). When you pass the Address Of the pointer, it will require one additional level of indirection, e.g.
#include <stdio.h>
void selectDeparment (char **departments, int selectedNum, char **selectedDeparment) {
*selectedDeparment = departments[selectedNum];
}
int main (void) {
char *selectedDepartment = NULL;
char *recordsPTR[] = { "aDepartment\n",
"anotherDepartment\n",
"newDepartment\n",
"otherDepartment\n" };
selectDeparment (recordsPTR, 1, &selectedDepartment);
fputs (selectedDepartment, stdout);
}
(same result, same comment on adding array bounds protection)
Look this over and let me know if I filled in the missing pieces correctly. If not, just drop a comment and I'm happy to help further.

read access violation variable

When i'm using char* pilih(char teks[]) in the int main() function, it's working. But when I used this function in the new function, it said read access violation. Please help me
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#define MAXARR 1000
char *hilangkan(char[]);
char *pilih(char[]);
char *loadFile(FILE *sumber);
int main(){
FILE *sumber;
sumber=fopen("kumpulan.txt","r");
char *teks=loadFile(sumber);
char *pilihan=pilih(teks);
printf("%s",pilihan);
printf("%s",hilangkan(pilihan));
}
char *hilangkan(char teks[]){
char *penghilangan;
strcpy(penghilangan,teks);
int y=strlen(penghilangan);
srand(time(NULL));
int c=48;
for(int i=0;i<y;i++){
int hilang=rand()%y+1;
penghilangan[hilang]='_';
}
return penghilangan;
}
char *loadFile(FILE *sumber){
char *teks;
if (sumber == NULL) {
printf("ERROR!!!");
system("pause");
return 0;
}
char h;
int count=0;
while (h = fgetc(sumber) != EOF) {
teks[count] = h;
count++;
}
fclose(sumber);
return teks;
}
char *pilih(char teks[]){
char *hasil;
srand(time(NULL));
int w = rand() % 47 + 1;
char cek[3];
itoa(w, cek, 10);
char *c=strstr(teks, cek);
int lokasi = c - teks + 1;
int pan = strlen(cek);
int i;
if (pan == 2)i = -1;
else i = 0;
while (teks[lokasi]!='\n') {
hasil[i] = teks[lokasi];
i++;
lokasi++;
}
hasil[i] = NULL;
return hasil;
}
On while(teks[lokasi]!='\n') it says read violation access. teks was 0x1110113
Links are highly discouraged and expectation from you is that, you should post the whole program in your question.
From the part of code that you have posted and the error information shared, it seems that the argument passed to pilih() function is not valid which in turn makes teks pointer pointing to some invalid memory. Actual cause of problem can only be given after looking at minimal, complete and verifiable program depicting the problematic behavior.
One confirm problem in your pilih() function is that you are returning a local variable hasil from it. The scope and life of local variable hasil is limited to pilih() function and it is no more valid once pilih() function exits.
Also, this statement
hasil[i] = NULL;
is not correct. Variable hasil is array of char and hasil[i] is a character at index i. You are assigning NULL to it which is not valid. I think you wanted to do this:
hasil[i] = '\0';
EDIT:
The full code has been posted in the question. Hence editing my answer and pointing out the problems in the OP's code.
There are several issues in your code. If you are using gcc compiler, try compiling your code with "-Wall -Wextra" options and check the warnings messages given by the compiler.
In the function loadFile(), look at this statement:
while (h = fgetc(sumber) != EOF) {
First of all, the return type of fgetc() function is int and not char [the fgetc() return type is int to accommodate for the special value EOF]. In the operator precedence table, the operator != comes before =, so you will not get the read character assigned to h but the result of fgetc(sumber) != EOF will be assigned to h. This should be
while ((h = fgetc(sumber)) != EOF) { // check the parenthesis added
^ ^
In this statement:
teks[count] = h;
You are accessing a pointer which is not initialized. Any variable which is not initialized has indeterminate value and same is true for pointers. They can point to any random indeterminate address. There is no default behavior. Only behavior is indeterminate and using indeterminate values results in Undefined behavior.
You should allocate memory to teks before using it, like this:
teks = malloc(100 * sizeof (char)); //this will allocate memory for 100 characters.
if (teks == NULL)
exit(EXIT_FAILURE);
Looks like you want to store the whole file content in teks. Make sure to allocate enough memory to teks and if you are not sure about the size of memory required then realloc is your friend.
Also, after while loop, you should add the terminating null character at the end of the content stored in teks, like this:
teks[count] = '\0';
The same error of accessing uninitialized pointer exists in hilangkan() and pilih() function. Check the variable penghilangan and hasil respectively.
strstr() can return NULL pointer. You should add check for it:
char *c=strstr(teks, cek);
if (c == NULL)
return NULL; // Or whatever the way you want to handle this case
// but you should not use c
You should check the parameter value before using it in every function. If it is pointer, check whether it is NULL or not. If it is not NULL then only use it.
Also, make sure to free the dynamically allocated memory once you are done with it.
I don't what exactly you are trying to do but somewhere I feel that there is lot of scope of improvements in your code.
Hope this help.

Why my code is behaving like this?

This is my first question here so i apologize if its not a useful question.
I have this project of a simulator where the user calls the program via command line with some parameters. Like, MYPROG [options] filename.
I need to make sure the filename is valid, where it is (directory) and get the name for further use.
Here is part of the code:
char* ExtrairNome(char* alvo){
char* teste = alvo;
char* nome = NULL;
int barras = 0;
while(strcmp(teste, "") != 0){ //look for "/"
if (teste[0] == '/') barras++;
teste++;
}
teste = alvo;
if (barras > 0){
while(barras > 0){ //remove everything leaving the "filename.ias"
if (teste[0] == '/') barras--;
teste++;
}
}
int i = 0;
char aux[strlen(teste) - 4];
while (strcmp(teste, ".ias")){ //remove the ".ias"
aux[i] = teste[0];
teste++;
i++;
}
printf("random %d\n", barras); //this line fixes the bug!!
aux[i] = '\0';
nome = aux;
return nome;
}
This function receives the string with the full filename and should return only the name, without extention or path. But it only works when i printf some variable before returning. If i remove that line the function returns nothing.
I think it has something to do with scope but i don't know for sure. How can i fix this?
nome is a pointer, so you can return the address of the solution.
Problem is aux, which is in the stack, and once you return, it doesn't exist anymore, so behaviour is unknown. You have two choices, declaring "aux" in a higher scope and pass it to your function, and passing a pointer to the buffer solution or allocate in the function(using malloc) and then free(when its not necessary).
i mean:
char name[100];
ExtrairNome(alvo, name);//pass a pointer to the function
void ExtrairNome(char * alvo, char * aux)
{
...;//everything is the same
//except you don't create aux here, you use the one you created in your main function
}
or
char * ExtrairNome(char * alvo, char * aux)
{
...;//everything is the same
char * aux = (char*)malloc((strlen(teste)-4 )* sizeof(char));
...;//everything the same
}
//remember to free() when you are done using it
You are returning a pointer to a local automatic (stack) variable - aux. That does not exist after the function returns. This is undefined behavior. The fact that it 'works' when you print a variable is one possibility for undefined behavior.

2D arrays passed through functions in c

I'm having a problem with my program. I need my program to read from a text file, the first consists of the dimensions of the 2d array the rest is the contents of the array. I have coded the readWord function which reads from textfiles and it works but when i do anything on the main function with the array it crashes. Please could you help.
int main()
{
int num_it, cols, rows;
char** myworld;
num_it = readWorld(myworld,&cols, &rows);
myworld[1][2]='x';/*it crashes when i make this statement*/
}
int readWorld(char** world, int* width,int* height)
{
int result=0,i,cols=0,rows=0;
char buff[25];
FILE* file = fopen ("world.txt", "r");
fscanf(file, "%d %d %d\n", width, height, &result);
/*Dynamic allocation*/
world = (char**)malloc(*(height)* sizeof(char*));
for(i=0;i<*height;i++)
{
world[i] = (char*)malloc(*width*sizeof(char));
}
/*store data in array*/
while(fgets(buff, sizeof buff, file) != NULL)
{
if (strlen(buff) >1){
for(cols=0; cols<=(strlen(buff)); ++cols)
{
world[rows][cols] = buff[cols];
}
++rows;
}
}
fclose(file);
return result;
}
You need to allocate the memory for myworld in the actual caller!
What's happening here is that you are passing the pointer by value to the function.
The pointer value is changed by the function but that's not going to adjust the one in the caller.
Two options: use a triple indirection (ie pass a pointer to the the pointer) or allocate in the main sub. I prefer the latter, mainly because you can control the memory deallocation in a more symmetrical manner; even if you fixed this problem your code still has the memory leak.
What you're experiencing is undefined behaviour as you are attempting to access memory your program does not own.
Your myworld variable in main is never initialized and points to junk, so when you try to access it bad things happen. Think about why: you are passing a copy of the variable to readWorld. You correctly allocate memory inside there, and make the copy point to it, but the original pointer (in main) still points to whatever random location it pointed to before.
If you want the memory for it to be allocated inside the readWorld function and made accessible via the myworld variable in main then you must pass a pointer to myworld to readWorld; in other words, you must pass a triple pointer.
Try this:
int readWorld(char*** world, int* width,int* height)
{
char **tempworld = malloc(...);
// do whatever
*world = tempworld;
return result;
}
int main()
{
char **myworld = NULL;
readWorld(&myworld, ...);
return 0;
}

C basics, string to pointer

I have project with 3 files.
Common header contain function declaration for check mysql connection:
int conn_check(char **m_error);
Main file calls function and expect some message in m_error in case of error:
if (!conn_check(&m_error)==0)
{
printf("%s\n", m_error);
}
And now function in which I have problem because weak knowing of pointers:
int conn_check(char **m_error)
{
int retval = 0;
char mysqlerror[255] = {0};
MYSQL *conn;
conn = mysql_init(NULL);
if (conn)
{
if (mysql_real_connect(conn, mysql_server, mysql_user_name, mysql_password, "", (ulong)mysql_serverport, mysql_socket, 0)==NULL)
{
sprintf(mysqlerror, "%u: %s", mysql_errno(conn), mysql_error(conn));
*m_error = mysqlerror; // Problem here
retval = -1;
}
} else retval = -2;
mysql_close(conn);
return retval;
}
Question is how to properly assign string mysqlerror to char pointer m_error so error message can be printed through printf in main.
char **m_error means you're passing a pointer to a pointer. Presumably this is because the function already returns an int and you want to also have the text of the error. As it is, you're assigning the address of a stack variable to the pointer which you can not do.
You would need to allocate memory, assign it to the pointer, then write to it:
*m_error = calloc(255, sizeof(char));
snprintf(*m_error, 255, "%u: %s", mysql_errno(conn), mysql_error(conn));
vasprintf() will do all of it for you:
vasprintf(m_error, "%u: %s", mysql_errno(conn), mysql_error(conn));
Note that you would then need to free() this back in the calling function.
You are returning a pointer to a local variable (char mysqlerror[255]). You should define mysqlerror in your main file and call your function like:
if (!conn_check(mysqlerror)==0)
and change the prototype:
int conn_check(char *mysqlerror)
and remove lines:
char mysqlerror[255] = {0};
*m_error = mysqlerror;
Here would be my solution:
char m_error[255];
if (!conn_check(&m_error)==0)
{
printf("%s\n", m_error);
}
int conn_check(char **m_error)
{
int retval = 0;
char mysqlerror[255];
MYSQL *conn;
...
sprintf(mysqlerror, "%u: %s", mysql_errno(conn), mysql_error(conn));
strcopy(*m_error, mysqlerror);
retval = -1;
...
}
Upon return from conn_check(), if you do the *m_error = mysqlerror; line, you'll end up with a quite possibly invalid pointer by then, as the local char array mysqlerror is not valid outside of the local function.
You'll need to pass in a pointer to a buffer and copy the string in, or duplicate the string using strdup to allocate some global memory to give you a valid pointer for returning (but if you do this, don't forget to free the memory in main() using free afterwards).
EDIT: If you choose to pass in a buffer, it's also good practice to pass in the max buffer size, so when you copy your string in, you don't overflow the buffer.
EDIT 2: A very hacky way of fixing your existing code with minimum code is of course to declare mysqlerror as static, so it is valid outside of the function. I wouldn't ever recommend doing that though, as it means the function wouldn't be thread-safe.

Resources