C - array of strings scope difference - c

I practiced an array of strings with no initial values.
Attempt 1
#include <stdio.h>
char *array[] = {};
int main(int argc, char *argv[]) {
array[0]="Hello";
array[1]="World";
char **i = array;
while (*i) {
printf("%d %s\n", i, *i);
i++;
}
}
$ gcc array_of_strings.c && ./a.out
6293704 Hello
6293712 World
It works fine.
Attempt 2
I thought I could move array pointer inside main function.
#include <stdio.h>
int main(int argc, char *argv[]) {
char *array[] = {};
array[0]="Hello";
array[1]="World";
char **i = array;
while (*i) {
printf("%d %s\n", i, *i);
i++;
}
}
$ gcc array_of_strings.c && ./a.out
-1899140568 (j͎?
-1899140560 World
-1899140552 ???%Y
-1899140544 1?I??^H??H???PTI???#
-1899140536 d?͎?
Segmentation fault
Huh, why it is not working? It causes "Segmentation fault" with ugly output.
Could somebody explain why I should not do this way?

You allocate an array with zero elements and then add two pointers to it. This writes outside of the array and causes a buffer overflow.
Incidentally, this overwrites unused memory if the array is allocated globally, but it overwrites the stack when it is allocated within main().

Two problems.
You aren't allocating space for the array items. With your empty initializer list you are allocating an empty array. When you write to array[0] and array[1] you are writing to memory you do not own.
You are getting lucky when you allocate the array globally. Global (aka statically-allocated) memory blocks tend to be filled with zeros. This is good for you because your while loop depends on their being a NULL pointer at the end of the array.
When you allocate on the stack and access memory past the end of the array you will get whatever happens to already be on the stack, which can be any arbitrary garbage. Your while (*i) loop doesn't get the NULL pointer it expects so it will keep on reading the garbage data until it finds some zeros that look like a NULL pointer.
To fix #1, give an explicit length to the array. To fix #2, you must explicitly add a NULL pointer to the end of the array.
char *array[3];
array[0]="Hello";
array[1]="World";
array[2]=NULL;
Also, for what it's worth, pointers aren't guaranteed to be the same size as ints. It is better to use %p to print pointers rather than %d.
printf("%p %s\n", i, *i);

In each of these cases, you are allocating an empty array, and then trying to insert items into it. C doesn't do any sort of resizing of arrays; if you insert items into an array beyond its length, it will just start overwriting any other data that might happen to come after the array. In your first case, when the array is a global, you manage to get lucky and apparently aren't breaking anything by writing past the end of the array, and furthermore are lucky that there is a null value just past the two that you insert, so your loop terminates at an appropriate place. In your second case, you happen to be overwriting your stack, which is used for storing local variables, passing arguments, return values, and return locations between functions. Thus, writing, and later reading, past the end of your array, is causing you to write all over your stack, and read random meaningless values.

Doing it on the second attempt declare the array on the stack and you then override arguments passed and at some point the return address at the end of the function.
The fact that it works in the first attempt is purely coincidental. You're still overriding memory you shouldn't but it currently does no harm.

You should not do it in both ways. In the first case, you were just lucky that you didn't overwrite some process-critical memory, in the second case you smashed the stack. Both cases might crash randomly because you are writing to memory that you did not reserve.
char *array[] = {};
This does reserve memory for zero entries, but with [0] = ... you're writing an element to a position for which you didn't allocate memory. You should read up about how to 1) define static arrays or 2) dynamically allocate arrays.

Related

why couldn't use a pointer in gets in C? such as char *str replace char str[40] in gets(str)

#include <stdio.h>
int main ()
{
char str[40];
printf("Enter a string : \n");
gets(str);
printf("You entered: %s\n", str);
return 0;
};
in above code, if replace str to a pointer, char *str. Then NULL is out. Suppose gets defined by char *gets(char *str), it should use a pointer instead of array. All examples I saw are array not pointers. Thanks.
function gets() is depracted your libc/compiler might ignore it. try use fgets() instead.
#include <stdio.h>
int main ()
{
char str[40];
printf("Enter a string : \n");
if (fgets(str, sizeof(str), stdin) != NULL)
{
printf("You entered: %s\n", str);
}
return 0;
};
also if you want to don't use stack you need to give pointer that points allocated space. in code str also can be char *str = malloc(40); then change sizeof(str) to 40 since str is no longer stack.
Really interesting question, I have been asked this question a lot!
you should have a bit background of pointers and memory to understand what is happening.
first let's have a brief review about pointers and memory:
our computer have some memory and we can use it in programming, anything that we store (in runtime) for example an int, array of doubles, some complex struct and strings(that they are array of characters) should be somewhere in memory.
pointers contain address of somewhere in memory, some of them know about that memory (how to read/write value) some of them don't.
there is a special value for pointers (NULL) that means nowhere, if pointer is pointing to NULL, that pointer is pointing not nowhere (obviously nowhere is not a valid address in memory)
array is specific type of pointer, a const pointer that is pointing to already allocated memory in stack.
and about gets function: let's think we want to re-implement such function (namely my_gets) , how we suppose to do that? how to return a string (array of characters)?
these are options (as far as i know):
creating a local array in our function and fill it. then we should return it? no we cant! because that array is in stack of our function and after ending the function, our function data including this array will be popped automatically (handled by compiler).
although nobody forbid us from returning that array, but that would cause dangling pointer problem.
allocating some space rather than stack (heap) and fill that. this is perfectly fine and there is methods and do this! for example readline (not in ansi c, you can find it here) will do this. the drawback of this method is that you should take care of that memory and free it later, it also may be not to optimum way and you may should copy that string to your already allocated memory
the last way (and way that gets use) is getting a pointer that is already pointing to a valid memory and fill that memory. you already know that gets want a pointer as input, I add that, that pointer should point to a valid and accessible memory that gets can fill it. if pointer is pointing to NULL (or maybe uninitialized and pointing to some where random) gets will fail writing and cause undefined behavior (segmentation fault for example)
some final points:
array solution work because array name is pointer that pointing to valid memory (array in stack) so it's OK and easy to understand.
If we don't want to use array, we can point our pointer to a valid memory, we need to use malloc/calloc to allocate a block of memory. see this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int size = 40 * sizeof(char);
char* p = malloc(size);
printf("Enter a string : \n");
if (fgets(p, size, stdin) != NULL) {
printf("You entered: %s\n", p);
}
free(p);
return 0;
}
gets is not secure because it doesn't care how much memory we have, it writes until and string ends and it may cause buffer overflow, better option (as people said) is fgets because it care memory size and will not exceed that. but my answer doesn't care it's fgets or gets.

Malloc array of characters dynamic vs static C

So I'm basically trying to take an input of scanf of letters (no spacing between them), place each letter into an array and spit out the corresponding letter to the array by using dynamically allocated arrays (malloc).
Crashes
#include <stdio.h>
#include <stdlib.h>
int main () {
char *userInput = malloc(sizeof(char)*3); /* dynamic */
scanf("%s", &userInput);
printf("user inputed %c", userInput[1]);
free(userInput);
return 0;
}
Runs
#include <stdio.h>
#include <stdlib.h>
int main () {
char userInput [3]; /* array */
scanf("%s", &userInput);
printf("user inputed %c", userInput[1]);
return 0;
}
Input:
asd
Output:
s
My understanding of dynamically allocated arrays was that char userInput [3]; is equivalent to char *userInput = malloc(sizeof(char)*3); but apparently from this case that isn't true? Anyone care to explain/help?
Welcome to Stack Overflow! Coincidentally, the main problem with your code is that it is vulnerable to a stack overflow. scanf has no way of knowing how big userInput is, because you didn't tell it, and will happily continue filling memory long past the end of your very short array.
If you want to capture exactly three characters (with no nul terminator), use scanf("%3c", userInput) instead. Note that without the NUL, you must not expect to treat userInput as a string; printing it via printf for example will result in a random amount of gibberish owing to the fact that C does not know where the string ended.
Now, to answer your actual question on "what's the difference between malloc and the static array": the difference is of scope. If you only ever use userInput before its creating function returns, there is no practical difference, but you're in trouble the minute you try to do something like this:
int function1 {
char my_string[3];
scanf("%3c", my_string);
return my_string; /* WRONG! DANGER! */
}
The return in the above example will happily return the pointer to my_string to the calling function. However, as soon as function1 returns, the stack is rolled back and the memory my_string occupied is essentially gone (and likely already re-used). The results are unpredictable but almost universally very bad for your program.
However, had you used malloc() instead, you could safely return the my_string pointer and the memory would persist until someone later called free(my_string) (where my_string is the pointer to the original my_string; it need not be named the same!).
This highlights another difference: with a stack variable such as char my_string[3];, you do not need to worry about (and indeed cannot) free() the memory, where as if the memory is malloc()'d instead, you must free() it if you wish to reclaim the memory.
There are some nuances to the above, such as file-scoped variables and static function variables, which I leave as topics for further reading.
As pointed in Giorgi's answer, the main problem is the incorrect usage of the address-of operator &.
However, the reason why it worked on one case and why it didn't work on another is very interesting.
char array[3]: When you declare that array, memory space will be allocated for it and array will be a label to that location(memory address). When you pass array to scanf (or use it anywhere else without subscripting []), you're passing an address to that function. Because of that, when you use the & operator on the label array, it returns the same address to you BUT with different type (T(*)[3]), which your compiler probably complained about. But, as the memory address is valid, it worked as expected.
char *array = malloc(): When you declare that variable, memory is also reserve for it, but this time in a different place and the space reserved is sizeof T(*), so it can hold a memory address. This variable also has an address in memory, which you can also get using &array. Then you malloc some memory and malloc returns to you an address of a memory block which you can now use. You can get that memory address by simply doing array. So, when you call scanf with the &array you're passing the variable address instead of the block address. That's why it crashes (I'm guessing you were not entering only two characters).
Check this code:
#include <stdio.h>
#include <stdio.h>
int main(void)
{
char *array[3];
char *ptr = malloc(3 * sizeof(char));
printf ("array : %p\n", array);
printf ("&array: %p\n\n", &array);
printf ("ptr : %p\n", ptr);
printf ("&ptr : %p\n", &ptr);
scanf("%s", &ptr);
printf ("ptr : %p\n", ptr);
return 0;
}
Which outputs:
$ ./draft
array : 0x7ffe2ad05ca0
&array: 0x7ffe2ad05ca0
ptr : 0x19a4010
&ptr : 0x7ffe2ad05c98
ABCD
ptr : 0x44434241
scanf got the address of the pointer, so when it saves the value it reads from stdin, it overwrites the address we had from malloc! The memory block we had is now gone, memory is leaking... Now, this is bad because we're overwriting stuff on our stack, memory is leaking, and it will crash.
Observe the last output: the value of ptr (which previously was the address of an allocated block) is now 0x44434241 (DCBA, ASCII Table)! How nice is that?

Accessing members of a passed struct array in C

I have a method levenshtein that populates a 2D array of structs w/ info and returns a pointer to that array. When I send it to another method, I get a Segmentation Fault (core dumped) error at runtime. Please help me w/ this hopefully obvious error.
struct chartEntry
{
int num;
bool left,
up,
diag;
};
struct chartEntry** levenshtein(char *s1, char *s2, bool toPrint)
{
unsigned int s1Len,
s2Len,
i, //rows, general purpose index
j; //columns, general purpose index
s1Len = strlen(s1);
s2Len = strlen(s2);
/***********************************
Create and populate traceback chart
***********************************/
struct chartEntry chart [s1Len+1][s2Len+1];
//
// code to populate chart here
//
//prints expected number
printf("chart[3][3].num is %d", chart[3][3].num);
return chart;
}
void testFunction(char*s1,char*s2)
{
// both of these give segmentation faults
printf("[3][3].num is %d", levenshtein(s1,s2,false)[3][3].num);
struct chartEntry ** tmp = levenshtein(s1,s2,false);
printf("[3][3].num is %d", tmp[3][3].num);
}
There's 2 problems here. Firstly, chart is an array of arrays. This cannot be converted to a pointer-to-a-pointer. Arrays and pointers are different. Your line return chart; must give you a compilation error which you should not ignore.
Secondly, even if it could be converted, chart's memory is local to the levenshtein function and will no longer exist when that function returns. So you would be returning a wild pointer.
You have two options:
allocate memory for chart using malloc and return a pointer to that (either one large block, or with two levels of indirection)
have the caller allocate the array and the levenshtein function just writes values into it.
If you use the first option then you should not use the printf as you have done the first time in testFunction, because the memory would not be freed. You have to save the returned pointer, printf it, and then execute a sequence of free that is the reverse of the malloc sequence you used to allocate it.
In your code, you're trying to return a pointer to an array that's declared inside the function:
struct chartEntry** levenshtein(char *s1, char *s2, bool toPrint)
{
// ...
struct chartEntry chart [s1Len+1][s2Len+1];
// ...
return chart;
}
However, as soon as the program exits this function, this array falls out of scope and is destroyed, leaving you with a pointer pointing to invalid memory. This leads to undefined behavior: Maybe it works, maybe it doesn't, maybe it puts your computer on fire. Okay, that last one is pretty unlikely, but the point is, anything can happen.
There are two ways to deal with this problem:
Create a static array before calling the function, and then pass a pointer to this array in the function call.
Dynamically allocate memory in the function, which can then be returned as a normal pointer. (The calling function has to make sure the memory is freed after use, though, otherwise this may lead to memory leaks, which is a bad, bad thing.)

Access violation while reading an array

I am trying to print an array of structs and receiving an access violation. Not sure how to fix this. i, j, k are 0 in at the break. Any help is appreciated.
Update:Rephrasing the question, What is the correct way to access the data inside the struct? Also qwr's answer looks promising, I will have time to test later, thanks.
About access violation:
Access Violation is generally an attempt to access memory that the CPU cannot physically address.
Common causes:
Dereferencing NULL pointers . (THIS IS YOUR CASE see picture). You want to access to 0x000(NULL) location
Attempting to access memory the program does not have rights to (such
as kernel structures in process context)
Attempting to access a
nonexistent memory address (outside process's address space)
Attempting to write read-only memory (such as code segment)
More :more here in wikipedia
How you should allocate (using your structure):
First You should allocate memory;And dont forget you should write its free function,too
Simple allocation would be such:
//instead I advice PCurrentData notation
CurrentData AllCurrentData=malloc(NumProduct* sizeof *CurrentData);
//memset so we can then check it with null
memset(AllCurrentData,0,NumProduct* sizeof *CurrentData);
int i,y;
for(i=0;i<NumProduct;i++){
//Noncontiguous allocation.Suits to string allocation,cause string lens differs
AllCurrentData[i].data=malloc(COLUMNS*sizeof(char**));
memset(AllCurrentData[i].data,0,COLUMNS*sizeof(char**));
for(j=0;j<COLUMNS;j++){
//this is just example
//probably you want to allocate null terminating string
int size=strlen(your_null_terminating_string)+1;//+1 for adding null,too
AllCurrentData[i].data[j]=malloc(size*sizeof(char));
memcpy(AllCurrentData[i].data[j],your_null_terminating_string,size);
}
}
Additionaly, What else is wrong in your code and proper way
Plus you are doing wrong. Looking at your structure you hold char**.But you try to access it with 2D [][] array. Why we can not? Cause there is no guarantee that char** reference to continguous allocation, or only it done ,by manually, the way that compiler can access to it with [][].
Plus for char** mostly allocation done with noncontinguous way.cause strings len differs
So Note these:
char** is not equal to 2D array char v[][] array. So doing AllCurrentData[i].data[j][k] is wrong to address char**.
only char* can be equally treated as one dimensional char v[] array. char[] decay to char*
So accessing should be done this way:
#define NULL 0
if(AllCurrentData[i]!=NULL && AllCurrentData[i].data[j]!=NULL){
char* str=AllCurrentData[i].data[j];
if(str!=NULL)
while (str[k]!='\0'){
printf("%c ",str[k]);++k;
}
}
/*or
while (*str){
printf("%c ",*str);++str;
} */
/*but actualy you can print null terminating string directly
(assuming you wanted this)
if(str!=NULL)
printf("%s",str);
*/
more to learn about arrays and pointers

Memory assignment in C through pointers

I am learning how to use pointers, so i wrote the below program to assign integer values in the interval [1,100] to some random locations in the memory.
When i read those memory locations, printf displays all the values and then gives me a segmentation fault. This seems an odd behavior, because i was hoping to see either all the values OR a seg fault, but not both at the same time.
Can someone please explain why i got to see both?
Thanks. Here is the code
#include <stdio.h>
#include <stdlib.h>
int main()
{
char first = 'f';
char *ptr_first = &first;
int i=1;
for(i=1;i<101;i++)
*(ptr_first+i) = i;
for(i=1;i<101;i++)
printf("%d\n", *(ptr_first+i));
return EXIT_SUCCESS;
}
Not odd at all. You are using your variable first, which is on the stack. What you essentially do is happily overwriting the stack (otherwise known from buffer overflows on the stack) and thus probably destroying any return address and so on.
Since main is called by the libc, the return to libc would cause the crash.
You're accessing memory past beyond that assigned to first. It is just one character, and, through the ptr_first pointer, you're accessing 100 positions past this character to unreserved memory. This may lead to segfaults.
You have to ensure the original variable has enough memory reserved for the pointer accesses. For example:
char first[100];
This will convert first in an array of 100 chars (basically a memory space of 100 bytes that you can access via pointer).
Note also that you're inserting int into the char pointer. This will work, but the value of the int will be truncated. You should be using char as the type of i.
since ptr_first pointer is pointing to a char variable first. Now when you are incrementing ptr_first, so incremented memory address location can be out of process memory address space, thats why kernel is sending segmentation fault to this process.

Resources