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
Related
char *test={"0x11","0x12","0x13","0x00","0x00"};
void change(char* test1, char* test2){
strncpy(test[3], test1, 4);
strncpy(test[4], test2, 4);
}
chage("0x55","0x66");
I can assign the characters to array element directly. However, it will cause the memory leak. That's why I use strncpy() instead.
Please advise if you know how to fix it.
There are at least three two you can get segfault here (one suggestion is to enable compiler warnings - they often pick up "stupid mistakes").
The problem is that test is probably misdeclared, it should probably have been:
char *test[]={"0x11","0x12","0x13","0x00","0x00"};
You initialize a char* with an array of char* which means that you initialize test with the first pointer in that array - which means that test will point to the string literal "0x11", so when you use test[3] as argument to strncpy you will send 1 which is converted to a pointer (probably to address 0x31). strncpy would then try to write to that address which is most probable not allowed. You had nearly a fourth reason here, if you had used test[5] you would asked to access beyond the end of the string which is disallowed (you can access test[4] becase it's the terminating null of the string).
Even if you fix those problems there is a problem because test[3] and test[4] are initialized using a string literal. Then strncpy would try to modify that string literal which is undefined behavior - the segfault is because test[3] and test[4] resides in read-only memory (allowing them to be in read-only memory is one reason why modifying string literals is undefined behavior).
What you instead could have done is to make sure that you have writable copies in test which is maybe not that straight forward in C. One normal solution is to have a function (that you have to call manually) that sets up test, and one that tears it down:
void init_test(void) {
int j;
for(j=0; j<sizeof(test)/sizeof(test[0]); j++)
test[j] = strdup(test[j]);
}
void init_fini(void) {
int j;
for(j=0; j<sizeof(test)/sizeof(test[0]); j++)
free(test[j]);
}
The other answer gives one good reason (never attempt to modify the contents of a string (str(n)cpy does that)).
I'm not even sure you want to represent "characters" as strings, especially as the first declaration doesn't work well (assigning an array of strings to a string).
It will take a lot of work to fix this for sure, but you shall begin by replacing "0x11" by '\x11' (I.E. actually use characters), replace strncpy by mere assignment (true characters are an atomic type which can be assigned directly) and finally change the parameters of the change function to get characters instead of strings.
I'm trying to mimic the way strcpy works, by writing my own function. My question is more specific to the size of an array.
I'm trying to copy contents of stringA into stringB, which I have declared as size of 1.
Shouldn't I get an error saying stringB is too small to hold stringA? The reason, I suspect I don't get an error is because an array name StringB is converted to a pointer?
Why is char str[1] = "abcd" illegal then ?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void strCopy(char *source,char *destination) {
printf("%p,%p\n",source,destination);
while (*source != '\0') {
*destination = *source;
printf("> %c,%p,%p\n",*source,source,destination);
source++;
destination++;
}
*destination = '\0';
}
int main(int argc,char *argv[]) {
char stringA[] = "To be or not to be.";
char stringB[1];
strCopy(stringA,stringB);
printf("StringB: %s\n",stringB);
return (0);
}
1) Shouldn't i get an error saying stringB is too small to hold stringA ?
you didn't get any error because of compilers memory allocation scheme. there is a good chance that compiler would have allocated memory to stringB first and stringA later. so consider if stringB is having memory location 1000 (only one byte), then stringA will be having memory locations from 1001 to 1020(including space for NULL). so when ever you try to copy contents from stringA to stringB into your function, it actually copies from location 1001 to 1000, then 1002 to 1001 and so on, so according to your program you must be having output as shown if this is the case. it seems that you are printing addresses of strings. see addresses of strings and check if this is the case. again this is merely consequence that string2 is allocated memory first than stringA. it is not neccesary that on all the variations of compilers, this will be the answer everytime.
stringB : To be or not to bee
stringA : o be or not to bee
now you are not getting error because both arrays are present in stack frame and both are accessed by pointers, so compiler doesn't care about sizes of array when data copy is done using pointers. it just copies till you are in allowed memory space. if this is not the case and stringA would have been present first in memory, then you would get segmentation fault.
2) Why is char str[1] = "abcd" illegal then ?
not this is very different case than your case, you are allocating only one byte to string, and initializing it with more characters than its size. note that your data copy is being done at run time, but this initialization is at compile time, so compiler knows size of array and will show you a warning, it is not illegal but compiler only assigns first character to string and you may get unpredictable result as there no space left for NULL character at last.
1) Shouldn't i get an error saying stringB is too small to hold stringA ?
You may not get an error depending on where in the memory space stringB was placed. If the stringB pointer was placed in the middle of the application's memory then you can certainly write values past its declared bounds. You'll just be overwriting memory that was used to store some other value or function. C/C++ never checks if you went past the array length like some other languages do, e.g. Java.
2) Why is char str1 = "abcd" illegal then ?
Since the behavior of your program is completely undefined based on your implementation it is difficult to describe exactly what is going on.
Also see the following post: why doesn't my program crash when I write past the end of an array?
#include<stdio.h>
#include<stdlib.h>
void main()
{
char *arr;
arr=(char *)malloc(sizeof (char)*4);
scanf("%s",arr);
printf("%s",arr);
}
In the above program, do I really need to allocate the arr?
It is giving me the result even without using the malloc.
My second doubt is ' I am expecting an error in 9th line because I think it must be
printf("%s",*arr);
or something.
do I really need to allocate the arr?
Yes, otherwise you're dereferencing an uninitialised pointer (i.e. writing to a random chunk of memory), which is undefined behaviour.
do I really need to allocate the arr?
You need to set arr to point to a block of memory you own, either by calling malloc or by setting it to point to another array. Otherwise it points to a random memory address that may or may not be accessible to you.
In C, casting the result of malloc is discouraged1; it's unnecessary, and in some cases can mask an error if you forget to include stdlib.h or otherwise don't have a prototype for malloc in scope.
I usually recommend malloc calls be written as
T *ptr = malloc(N * sizeof *ptr);
where T is whatever type you're using, and N is the number of elements of that type you want to allocate. sizeof *ptr is equivalent to sizeof (T), so if you ever change T, you won't need to duplicate that change in the malloc call itself. Just one less maintenance headache.
It is giving me the result even without using the malloc
Because you don't explicitly initialize it in the declaration, the initial value of arr is indeterminate2; it contains a random bit string that may or may not correspond to a valid, writable address. The behavior on attempting to read or write through an invalid pointer is undefined, meaning the compiler isn't obligated to warn you that you're doing something dangerous. On of the possible outcomes of undefined behavior is that your code appears to work as intended. In this case, it looks like you're accessing a random segment of memory that just happens to be writable and doesn't contain anything important.
My second doubt is ' I am expecting an error in 9th line because I think it must be printf("%s",*arr); or something.
The %s conversion specifier tells printf that the corresponding argument is of type char *, so printf("%s", arr); is correct. If you had used the %c conversion specifier, then yes, you would need to dereference arr with either the * operator or a subscript, such as printf("%c", *arr); or printf("%c", arr[i]);.
Also, unless your compiler documentation explicitly lists it as a valid signature, you should not define main as void main(); either use int main(void) or int main(int argc, char **argv) instead.
1. The cast is required in C++, since C++ doesn't allow you to assign void * values to other pointer types without an explicit cast
2. This is true for pointers declared at block scope. Pointers declared at file scope (outside of any function) or with the static keyword are implicitly initialized to NULL.
Personally, I think this a very bad example of allocating memory.
A char * will take up, in a modern OS/compiler, at least 4 bytes, and on a 64-bit machine, 8 bytes. So you use four bytes to store the location of the four bytes for your three-character string. Not only that, but malloc will have overheads, that add probably between 16 and 32 bytes to the actual allocated memory. So, we're using something like 20 to 40 bytes to store 4 bytes. That's a 5-10 times more than it actually needs.
The code also casts malloc, which is wrong in C.
And with only four bytes in the buffer, the chances of scanf overflowing is substantial.
Finally, there is no call to free to return the memory to the system.
It would be MUCH better to use:
int len;
char arr[5];
fgets(arr, sizeof(arr), stdin);
len = strlen(arr);
if (arr[len] == '\n') arr[len] = '\0';
This will not overflow the string, and only use 9 bytes of stackspace (not counting any padding...), rather than 4-8 bytes of stackspace and a good deal more on the heap. I added an extra character to the array, so that it allows for the newline. Also added code to remove the newline that fgets adds, as otherwise someone would complain about that, I'm sure.
In the above program, do I really need to allocate the arr?
You bet you do.
It is giving me the result even without using the malloc.
Sure, that's entirely possible... arr is a pointer. It points to a memory location. Before you do anything with it, it's uninitialized... so it's pointing to some random memory location. The key here is wherever it's pointing is a place your program is not guaranteed to own. That means you can just do the scanf() and at that random location that arr is pointing to the value will go, but another program can overwrite that data.
When you say malloc(X) you're telling the computer that you need X bytes of memory for your own usage that no one else can touch. Then when arr captures the data it will be there safely for your usage until you call free() (which you forgot to do in your program BTW)
This is a good example of why you should always initialize your pointers to NULL when you create them... it reminds you that you don't own what they're pointing at and you better point them to something valid before using them.
I am expecting an error in 9th line because I think it must be printf("%s",*arr)
Incorrect. scanf() wants an address, which is what arr is pointing to, that's why you don't need to do: scanf("%s", &arr). And printf's "%s" specificier wants a character array (a pointer to a string of characters) which again is what arr is, so no need to deference.
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.
I have this function which is called about 1000 times from main(). When i initialize a pointer in this function using malloc(), seg fault occurs, possibly because i did not free() it before leaving the function. Now, I tried free()ing the pointer before returning to main, but its of no use, eventually a seg fault occurs.
The above scenario being one thing, how do i initialize double pointers (**ptr) and pointer to array of pointers (*ptr[])?
Is there a way to copy a string ( which is a char array) into an array of char pointers.
char arr[]; (Lets say there are fifty such arrays)
char *ptr_arr[50]; Now i want point each such char arr[] in *ptr_arr[]
How do i initialize char *ptr_arr[] here?
What are the effects of uninitialized pointers in C?
Does strcpy() append the '\0' on its own or do we have to do it manually? How safe is strcpy() compared to strncpy()? Like wise with strcat() and strncat().
Thanks.
Segfault can be caused by many things. Do you check the pointer after the malloc (if it's NULL)? Step through the lines of the code to see exactly where does it happen (and ask a seperate question with more details and code)
You don't seem to understand the relation of pointers and arrays in C. First, a pointer to array of pointers is defined like type*** or type**[]. In practice, only twice-indirected pointers are useful. Still, you can have something like this, just dereference the pointer enough times and do the actual memory allocation.
This is messy. Should be a separate question.
They most likely crash your program, BUT this is undefined, so you can't be sure. They might have the address of an already used memory "slot", so there might be a bug you don't even notice.
From your question, my advice would be to google "pointers in C" and read some tutorials to get an understanding of what pointers are and how to use them - there's a lot that would need to be repeated in an SO answer to get you up to speed.
The top two hits are here and here.
It's hard to answer your first question without seeing some code -- Segmentation Faults are tricky to track down and seeing the code would be more straightforward.
Double pointers are not more special than single pointers as the concepts behind them are the same. For example...
char * c = malloc(4);
char **c = &c;
I'm not quite sure what c) is asking, but to answer your last question, uninitialized pointers have undefined action in C, ie. you shouldn't rely on any specific result happening.
EDIT: You seem to have added a question since I replied...
strcpy(..) will indeed copy the null terminator of the source string to the destination string.
for part 'a', maybe this helps:
void myfunction(void) {
int * p = (int *) malloc (sizeof(int));
free(p);
}
int main () {
int i;
for (i = 0; i < 1000; i++)
myfunction();
return 0;
}
Here's a nice introduction to pointers from Stanford.
A pointer is a special type of variable which holds the address or location of another variable. Pointers point to these locations by keeping a record of the spot at which they were stored. Pointers to variables are found by recording the address at which a variable is stored. It is always possible to find the address of a piece of storage in C using the special & operator. For instance: if location were a float type variable, it would be easy to find a pointer to it called location_ptr
float location;
float *location_ptr,*address;
location_ptr = &(location);
or
address = &(location);
The declarations of pointers look a little strange at first. The star * symbol which stands in front of the variable name is C's way of declaring that variable to be a pointer. The four lines above make two identical pointers to a floating point variable called location, one of them is called location_ptr and the other is called address. The point is that a pointer is just a place to keep a record of the address of a variable, so they are really the same thing.
A pointer is a bundle of information that has two parts. One part is the address of the beginning of the segment of memory that holds whatever is pointed to. The other part is the type of value that the pointer points to the beginning of. This tells the computer how much of the memory after the beginning to read and how to interpret it. Thus, if the pointer is of a type int, the segment of memory returned will be four bytes long (32 bits) and be interpreted as an integer. In the case of a function, the type is the type of value that the function will return, although the address is the address of the beginning of the function executable.
Also get more tutorial on C/C++ Programming on http://www.jnucode.blogspot.com
You've added an additional question about strcpy/strncpy.
strcpy is actually safer.
It copies a nul terminated string, and it adds the nul terminator to the copy. i.e. you get an exact duplicate of the original string.
strncpy on the other hand has two distinct behaviours:
if the source string is fewer than 'n' characters long, it acts just as strcpy, nul terminating the copy
if the source string is greater than or equal to 'n' characters long, then it simply stops copying when it gets to 'n', and leaves the string unterminated. It is therefore necessary to always nul-terminate the resulting string to be sure it's still valid:
char dest[123];
strncpy(dest, source, 123);
dest[122] = '\0';