Pointers and local arrays in C - c

Why doesn't my function printTable print the content of my array? For example, from the whole word 'oui' stored in my array mysteryword it prints only 'o'?
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#define libraryDimension 12
char* getFirstElementPointerOfMysteryWord(void);
char getCarac(void);
void printTable(char*ptr,int dimension);
/* Main program*/
int main() {
//getCarac();
char *pointerForFirstElement = getFirstElementPointerOfMysteryWord();
int tableDimension = 3;
printTable(pointerForFirstElement, tableDimension);
return 0;
}
This function is intended to provide a choice of words it has no parameters and it returns the address of the first element of my word's array.
char *getFirstElementPointerOfMysteryWord(void) {
int randomNumbers[3] = {0};
char mysteryWord[4];
char wordLibrary[libraryDimension];
wordLibrary[0] = '#';
wordLibrary[1] = 'n';
wordLibrary[2] = 'o';
wordLibrary[3] = 'n';
wordLibrary[4] = '#';
wordLibrary[5] = 'o';
wordLibrary[6] = 'u';
wordLibrary[7] = 'i';
wordLibrary[8] = '#';
wordLibrary[9] = 'q';
wordLibrary[10] = 'u';
wordLibrary[11] = 'i';
wordLibrary[12] = '\0';
int j=0;
for (int i = 0; i<libraryDimension; i++) {
if(wordLibrary[i] == '#') {
randomNumbers[j] = i;
j++;
}
}
srand(time(NULL));
int index = rand() % 3;
int randomNumber = randomNumbers[index];
int k=0;
for (int i = randomNumber ; i< libraryDimension-1 ; i++) {
if(wordLibrary[randomNumber+k+1] == '#'){
break;
}
else{
mysteryWord[k] = wordLibrary[randomNumber+1+k];
k++;
}
}
return mysteryWord;
}
This is the part where my code doesn't work properly.
void printTable(char *ptr,int dimension) {
for (int i = 0; i <dimension ; i++) {
printf("%c",*(ptr+i));
}
}
char getCarac(void){
char carac;
carac = getchar();
return carac;
}

When you declare a variable in a function, it is allocated on the stack. When the variable goes out of scope i.e. the function ends, the variable disappears (stack is local for the function) so by returning the address of the array you are returning an address that no longer exists.
Instead either allocate storage on the heap using malloc
char *mysteryWord = malloc(4);
or better, have it declared outside the function and then pass it to the function to fill.
void getFirstElementPointerOfMysteryWord(char* mysterword, size_t maxLen)

The problem is right here
char *getFirstElementPointerOfMysteryWord(void)
{
char mysteryWord[4];
/* other stuff */
return mysteryWord;
}
mysteryWord ceases to exist when the function returns. Any dereferencing of it by the caller (e.g. examining its content) or passing it to another function that dereferences (which your code does) gives undefined behaviour.
You need to ensure whatever pointer the caller receives, it continues to point at something that will exist for the caller. That can be done in various ways, each with different trade-offs. Probably the easiest is for the caller to PASS an array with 4 elements as an argument to this function (if the caller owns it, it will not cease to exist until the current scope within the caller ends)

Related

Why can't I Iterate over a string that is returned in C?

When I iterate through a string in a void function like this it doesn't give me any problem and iterates through the string I input.
#include <stdio.h>
#include <string.h>
void iter_string (void){
char source[30];
scanf(" %[^\n]s",source );;
int length = (int)strlen(source); //sizeof(source)=sizeof(char *) = 4 on a 32 bit implementation
for (int i = 0; i < length; i++)
{
printf("%c\n", source[i]);
}
//return 0;
}
int main(void)
{
iter_string();
return 0;
}
However, problems arise when I modify the function to return the input value and store it in a value in the main function. It gives me an error called segmentation fault:11. Why is this?
const char* iter_string (void){
char source[30];
scanf(" %[^\n]s",source );;
int length = (int)strlen(source); //sizeof(source)=sizeof(char *) = 4 on a 32 bit implementation
for (int i = 0; i < length; i++)
{
printf("%c\n", source[i]);
}
return *source;
}
int main(void)
{
char author[30];
strcpy(author,iter_string());
printf("%s\n",author );
return 0;
}
Because you are returning a reference to a memory that no longer exists once the function finishes executing.
You have to declare it dinamically if you want to return that pointer:
char *source = malloc(30);
// Do your processing here...
return source; // No asterisk here
Then in main, to do a proper cleaning on the memory allocated inside the function you should free the stuff you malloc'ed:
char * temp = iter_string();
strcpy(author, temp);
free(temp);
Other alternativa would be to pass author as parameter and alter it inside.

array value not updating

I have a strtok implementation (sort of), but it doesn't print the token!
char *tokenizer(char s[], const char *delimiter) {
char *p; //return value of function
int i = 0;
while(s[i] != *delimiter) //to get the size of array just right
i++;
char arr[i+1];
p = arr; //can't return an array, so assigned to a
//pointer
int j = 0;
i = 0;
while(s[i]!=*delimiter) {
arr[j] = s[i];
i++;
j++;
}
arr[j] = '\0';
printf("%s\n",p); //this statement works, but if excluded
//main prints nothing.
return p;
}
This function is being called as following, from the main:
char s[] = "tab-tab";
const char del[2] = "-";
char *p;
p = tokenizer(s, del);
printf("%s\n", p); //prints nothing without the printf in
//tokenizer
I tried debugging with gdb, and inspected the values of local variable after each line. p is updated with arr[j] inside tokenizer but goes to zero as soon as tokenizer finishes and frame shifts back to main.
The value ofp in main doesn't become NULL, it becomes an empty string, and prints that!
However, p in main prints the token if printf in tokenizer is included.
This already includes work-around. I know this can't possibly be the way strtok is implemented. I started with a more sophisticated, "expertish" version which had pointers, but couldn't get it to work, so settled for this "beginner" version.
It's because your pointer is pointing to a memory address in the stack, once your function is returned the memory address being pointed to no longer exists, you need to create dynamically allocated memory to access the variable outside of the function. The beauty of C
char *tokenizer(char s[], const char *delimiter) {
char *arr;
int i = 0;
while(s[i] != *delimiter)
i++;
// Initialize variable in the heap
if (!(arr = malloc(sizeof(char *) * (i+1))))
return NULL;
// Clear the array
bzero(arr, (i+1));
int j = 0;
i = 0;
while(s[i]!=*delimiter) {
arr[j] = s[i];
i++;
j++;
}
arr[j] = '\0';
// return pointer
return arr;
}
You should make sure to free the memory in the main to prevent memory leaks.

Why do I get the segmentation fault message at run time? (2-dimensional array of struct) [duplicate]

I was playing with double pointers in C and was wondering if I create a function that initializes the table, it crashes on going back to main when I try to make use of the memory allocated by InitStringTable. I believe a simple fix is to make strTable global and then I believe its OK, but I prefer not to do so as this is more of a learning exercise for me in passing the table around for modification i.e. I should be able to modify strTable from main or another function modifyTable after InitStringTable.
Thanks for any help you can give.
int main()
{
char** strTable;
// Allocates memory for string table.
InitStringTable(strTable);
// Below lines should be able to copy strings into newly allocated table.
// Below lines cause crash however.
strcpy(strTable[0], "abcdef");
strcpy(strTable[1], "xy");
}
// Allocates memory for the string table. This function should create a table
// of size 10 strings with each string 50 chars long. The code compiles fine.
void InitStringTable(char** table)
{
int i = 0;
table = (char**)malloc(sizeof(char)*10);
for(i = 0; i < 10; i++)
{
table[i] = (char*)malloc(sizeof(char)*50);
}
for(i = 0; i < 10; i++)
{
memset(table[i], 0, 50);
}
strcpy(table[0], "string1");
}
C is pass by value.
The value assigned to table is lost on returning from InitStringTable().
Also when allocating pointers to char ask for room for pointers to char.
So this:
... = (char**)malloc(sizeof(char)*10);
shall at least be (assuming C):
... = malloc(sizeof(char*)*10);
A possible approach to this would be:
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int InitStringTable(char *** ppptable, const size_t n, const size_t l)
{
int result = 0;
if (NULL == ppptable)
{
result = -1;
errno = EINVAL;
}
else
{
(*ppptable) = malloc(n * sizeof(**ppptable));
if (NULL == (*ppptable))
{
result = -1;
}
else
{
size_t i = 0;
for(; i < n; ++i)
{
(*ppptable)[i] = calloc(l, sizeof(*(*ppptable)[i]));
if (NULL == (*ppptable)[i])
{
result = -1;
/* Failing in the middle requires clean-up. */
for (; i > 0; --i)
{
free((*ppptable)[i-1]);
}
free(*ppptable);
(*ppptable) = NULL;
break;
}
}
}
}
return result;
}
Call it like this:
#include <stdlib.h>
#include <stdio.h>
int InitStringTable(char *** ppptable, const size_t n, const size_t l);
int main(void)
{
int result = EXIT_SUCCESS;
char ** strTable = NULL;
if ( -1 == InitStringTable(&strTable, 10, 42)) //* Allocate array with 10 "strings" à 42 chars. */
{
perror("InitStringTable() failed");
result = EXIT_FAILURE;
}
else
{
strcpy(strTable[0], "abcdef");
strcpy(strTable[1], "xy");
}
return result;
}
And no, I won't get into this ridiculous "You don't wanna be a 3-star-programmer!" discussion.
You have a pointer issue.
It's like if you say:
void inc(int a){
a++;
}
int main(){
int a = 0;
inc(a);
printf ("%d\n", a); // will display 0, not 1
}
does not work.
You must pass &strTable instead of strTable as InitStringTable argument, and change other things in InitStringTable consequently ..
Or just do strTable = InitStringTable(); , and return a char** from InitStringTable.
The lines below InitStringTable() crash, because they are trying to perform operations
on a memory address that is neither in the same scope as theirs nor have any reference to
that memory address.
The function InitStringTable() allocates memory to the table, but cannot be accessed by the
calling function (here main), because the memory is local to the function in which it
allocated.
Therefore in order to use the same memory address for operations in the
calling function you must pass a reference of that address to the calling function.
In your program you can do it as under :
Declare the function as :-
char **InitStringTable(char **);
int main()
{
char** strTable;
strTable = InitStringTable(strTable);
strcpy(strTable[0], "abcdef");
strcpy(strTable[1], "xy");
}
char **InitStringTable(char** table)
{
int i = 0;
table = (char**)malloc(sizeof(char)*10);
for(i = 0; i < 10; i++)
{
table[i] = (char*)malloc(sizeof(char)*50);
}
for(i = 0; i < 10; i++)
{
memset(table[i], 0, 50);
}
strcpy(table[0], "string1");
/* after the function has finished its job, return the address of the table */
return table;
}

Does using calloc inside function, change the pointer passed as function argument

I do not understand why the second printf loop outputs different data than the first printf loop that was done inside the function scope. Can it be that the pointer is changed somehow inside the function so that when it returns it returns a different value?
Output:
First printf inside function:
Parts TMP|01245
Parts X|40001
Parts Y|98760
Second printf outside function, in main:
It returns jiberish and not the same as when printing inside the function.
I tried to fprintf so that I can quickly paste the results in here ,but then I received an uninformative call stack error.
#include <stdio.h>
#include <stdlib.h>
#include "string.h"
void ProtocolParse_Start(int *numParts,char **parts, char *str, const char* partsDelim )
{
int partCount = strChrCount(str,'~');
*numParts = partCount;
parts = (char**)calloc(partCount,sizeof(char));
char *tempPart;
tempPart = strtok (str,partsDelim);
parts[0] = (char*)calloc(strlen(tempPart),sizeof(char));
strcpy(parts[0],tempPart);
int i =1;
for(; i < partCount; i++)
{
tempPart = strtok (NULL, partsDelim);
parts[i] = (char*)calloc(strlen(tempPart),sizeof(char));
strcpy(parts[i],tempPart);
}
i =0;
for(; i < partCount; i++)
{
printf ("%Parts %s\n",parts[i]);
}
}
void ProtocolParse_End(int numParts,char **parts)
{
int i = 0;
for (; i < numParts; i++)
free (parts[i]);
free (parts);
}
int main()
{
char proto[32] = "TMP|01245~X|40001~Y|98760~";
char **parts;
int numParts;
ProtocolParse_Start(&numParts, parts,proto,"~");
int i =0;
for(; i < numParts; i++)
{
printf ("%Parts %s\n",parts[i]);
}
ProtocolParse_End(numParts,parts);
return 0;
}
Can anyone please shed some light onto my problem. Because I am not sure what I'm doing wrong ??
The assignment of parts inside the function has no effect on the char **parts from main. In order to modify it, you need to pass a pointer to parts, and add an extra level of indirection (yes, you'd get three asterisks now).
The code that partitions the data to strings is incorrect, too: you need to allocate an array of character pointers, and then copy each token into that array individually.
void ProtocolParse_Start(int *numParts, char ***parts, char *str, const char* partsDelim )
{
int partCount = strChrCount(str,'~');
*numParts = partCount;
*parts = malloc(partCount * sizeof(char*));
char *tempPart;
tempPart = strtok (str,partsDelim);
(*parts)[0] = malloc(strlen(tempPart)+1);
strcpy((*parts)[0], tempPart);
int i =1;
for(; i < partCount; i++)
{
tempPart = strtok (NULL, partsDelim);
(*parts)[i] = malloc(strlen(tempPart)+1);
strcpy((*parts)[i],tempPart);
}
i =0;
for(; i < partCount; i++) {
printf ("%Parts %s\n", (*parts)[i]);
}
}
I made three changes to your code:
Replaced calloc with malloc: you initialize every element anyway, so there is no reason to zero-fill the block
Removed casts in front of malloc - this is not necessary in C
Added one to strlen(tempPart) - you need this for null terminated strings.
There are different mistakes:
When you pass a parameter to a function it is always copied.
You gave a char **parts and it is copied.
Inside the function you overwrite the copied input with the new address of the calloced pointer.
Consider an easier example:
void doSomething(int a){
a=5;
}
///...
int b = 6;
doSomething(b);
When you call doSomething(b), your b is not changed.
If you want it to be changed, you have to pass a pointer to b.
void doSomething(int* a){
*a=5;
}
///...
int b = 6;
doSomething(&b);
The same is with your char*array.
You have char** partsin your main, that you want to be set to the allocated array.
so you have to pass its pointer. and write the obtained address to the dereferenced pointer.
The other big mistake is, that you gibe the wrong soze to the first calloc. It should be sizeof(char*).
Your routine should start like this:
void ProtocolParse_Start(int *numParts,char ***parts, char *str, const char* partsDelim )
{
int partCount = strChrCount(str,'~');
*numParts = partCount;
*parts = (char**)calloc(partCount,sizeof(char*));
char *tempPart;
//...
(all further accesses to parts in the function have to dereference parts)
and the call have to look like:
ProtocolParse_Start(&numParts, &parts,proto,"~");

Why does this program give me a "segmentation fault"?

So my brother was making a program to turn all words in a string to hashtag, but for some reason it always gives a "segmentation fault" error at the end of execution. I tried to find what may cause it, but haven't found. Here's the code:
#include <stdio.h>
#include <string.h>
char* setHashtag(char text[10000])
{
int i, j;
printf("Initial text = %s\n", text);
for (i = 9998; i >= 0; i--)
{
text[i+1] = text[i];
}
text[0] = ' ';
for (i = 0; text[i+1] != '\0'; i++)
{
if(text[i] == ' ' && text[i+1] != ' ')
{
for (j = 9998; j > i; j--)
{
text[j+1] = text[j];
}
text[i+1] = '#';
printf("Partial text = %s\n", text);
}
}
return text;
}
void execute() {
char text[5000], textFinal[10000];
gets(text);
strcpy(textFinal, setHashtag(text));
printf("%s\n", textFinal);
}
int main()
{
execute();
printf("Back to main\n");
return 0;
}
You pass an array of size 5000 into your function, yet you access 10000 elements inside. Of course, it will crash.
This size of the array specified in function declaration does not matter. It is ignored by the compiler. This
char* setHashtag(char text[10000])
is equivalent to this
char* setHashtag(char *text)
i.e. the function receives a pointer to the beginning of your original argument array, not a new local copy of the argument array (naked arrays in C are not copyable).
This means that when you call your function as
char text[5000];
...
setHashtag(text)
the text array does not magically become a char [10000] array. It remains a char [5000] array, as it was originally declared. Attempting to access text[9998] and such inside the function leads to undefined behavior.
Since your setHashtag function expects a fixed size array of size 10000, it might be a better idea to declare your function as
char* setHashtag(char (*text)[10000])
and pass in the array arguments as setHashing(&text). This will make sure you will not be able to pass in an array of wrong size. Inside the function you'll have to access the array as (*text)[i].

Resources