How does go represent slice of strings in memory? [duplicate] - c

This question already has answers here:
Displayed size of Go string variable seems unreal
(3 answers)
Are len(string) and len(slice)s O(1) operation in Go?
(1 answer)
Closed 3 months ago.
I am trying to understand how go represents slice of strings in memory (They are not aligned in close proximity to each other). First of all, looking at this C code
#include <stdio.h>
int main(int argc, char **argv) {
char *x[3];
x[0] = "hi";
x[1] = "foo";
x[2] = "bar";
printf("%p\n", x[0]);
printf("%p\n", x[1]);
printf("%p\n", x[2]);
}
Output on my computer:
0x1068d0fa0
0x1068d0fa3
0x1068d0fa7
0x1068d0fa0 -> h
0x1068d0fa1 -> i
0x1068d0fa2 -> '\0'
0x1068d0fa3 -> f
0x1068d0fa4 -> ... till the last character in x[2] they all have a byte difference
But in golang, it is not clear to me how this work,
package main
import (
"fmt"
)
func main() {
k := []string{"hi", "there", "how", "are", "you"}
fmt.Printf("\n%p", &k[0])
fmt.Printf("\n%p", &k[1])
fmt.Printf("\n%p", &k[2])
fmt.Printf("\n%p", &k[3])
fmt.Printf("\n%p", &k[4])
}
Output on my computer:
0x430050
0x430060
0x430070
0x430080
They all have 10-byte difference, how does go represent this in memory?

Actually, there is a 16 byte difference (since the addresses are in hex), which would correspond to the slice layout described in here, that is:
Data pointer (8 bytes)
Length (int, 4 bytes)
Capacity (int, 4 bytes)

Related

Array becomes larger than declared [duplicate]

This question already has answers here:
How do I determine the size of my array in C?
(24 answers)
Closed 5 years ago.
I'm writing a function that is supposed to split a string on "-" and return and array containing the parts from the string, so if the string is:
2017-10-23
I want the array to have three elements populated like:
arr[0] = 2017, arr[1] = 10, arr[2] = 23
This is the function:
/*
* return a array of the parts of date_string
*/
int * to_date_array(char *date_string)
{
int i = 0;
int f = 0;
char *tokens = strtok(date_string, "-"); /* get initial token */
static int arr[3] = {0, 0, 0};
char *ptr;
int val;
/* init static arr */
for (f = 0; f < sizeof(arr); f++)
arr[f] = 0;
/* do the split */
while (tokens != NULL) {
val = strtol(tokens, &ptr, 10);
arr[i++] = val;
tokens = strtok(NULL, "-");
}
/*
* for some reason arr becomes 12 elements long?
* I expected it to have 3 elements
*/
puts("func: to_date_array");
puts("------------------------");
for (f = 0; f < sizeof(arr); f++)
printf("arr[%d]: %d\n", f, arr[f]);
return arr;
}
The function works but I'm really puzzled by the "arr" array. I expect it to be three elements long but when I iterate through it and print every element, it show 12 elements?
$ gcc -Wall main.c arguments.c -o timespan
$ ./timespan 2015-08-10 2017-10-18
func: to_date_array
------------------------
arr[0]: 2015
arr[1]: 8
arr[2]: 10
arr[3]: 0
arr[4]: 0
arr[5]: 0
arr[6]: 0
arr[7]: 0
arr[8]: 0
arr[9]: 0
arr[10]: 0
arr[11]: 0
The sizeof operand returns a size in bytes (where by definition a char takes one byte). On your (and mine) machine, sizeof(int) is 4, hence an array of 3 int takes 12 bytes. See nucleon's answer.
Your to_date_array is not reentrant. It would be nicer to return a dynamically allocated array (e.g. with calloc ....). Of course you need then to adopt the convention that its result has to be later free-d (e.g. by the caller).
You could consider also returning a pointer to some struct ending with a flexible array member.
You could also pass arr (and its length) to the to_date_array and have it been filled by that function.
sizeof computes the size of the array in bytes, thus you have to divide by the size of a single element to get the number of elements, thus use
sizeof(arr)/sizeof(*arr)
sizeof returns the number of bytes in the array, not the number of elements. On your system, an int is 4 bytes wide, so the array takes up 12 bytes.
You need to divide the size of the array by the size of a single element to get the number of elements:
sizeof arr / sizeof *arr
C does not do any bounds checking on array access - the array is only three elements wide, but you won't get any sort of OutOfBounds exception if you attempt to access elements outside of that range. The behavior is undefined - your code may crash, it may produce unexpected results, it may work as intended, but the results won't necessarily be repeatable or predictable.
sizeof int arr[3] is sizeof(int) * 3 equals to 4*3 = 12

Unexpected results when using memcpy

Hi i came across with this simple c program but i cant understand how this code works:
#include <string.h>
#include <stdio.h>
char *a = "\0hey\0\0"; /* 6 */
char *b = "word\0up yo"; /* 10 */
char *c = "\0\0\0\0"; /* 4 */
int main(void)
{
char z[20];
char *zp = z;
memcpy(zp, a, strlen(a)+1);
memcpy(zp, b, strlen(b)+1);
memcpy(zp, c, strlen(c)+1);
/* now z contains all 20 bytes, including 8 NULLs */
int i;
for(i = 0; i < 20; i++){
if (z[i] == 0){
printf("\\0");
}
printf("%c", z[i]);}
return 0;
}
I was expecting that printing z the output would be :
\0hey\0\0\0word\0up yo\0\0\0
But instead I am getting :
\0ord\0\0\0\0\0\0\0\0\0\0\0\0???Z
Finally , when i print a instead of z i get the right output.
Can anyone explain to me why this happens ? Thanks in advance.
EDIT: How i could concatenate such strings?
Strings in C are zero-terminated; the functions in the standard C library assume this property. In particular, the function strlen returns the number of non-zero characters from the start of the string. In your example, strlen(a) is equal to 0, already as the first character of a is zero.
The code will have the following effect:
memcpy(zp, a, strlen(a)+1);
Now zp still contains \0, because strlen(a) is 0, so 1 character is copied.
memcpy(zp, b, strlen(b)+1);
Now zp contains word\0: five characters copied.
memcpy(zp, c, strlen(c)+1);
Now just the first character of zp is overwritten, so it contains \0ord\0.
Finally , when i print a instead of z i get the right output. Can anyone explain to me why this happens ? Thanks in advance.
That's because a, b, and c happen to be allocated sequentially in the memory. When you print "20 bytes starting from the start of a", you're actually looking at the memory past the latest byte of a. This memory happens to contain b. So you actually start reading b. Same goes for b and c. Note that this is by no means guaranteed. Looking past the memory allocated for a char * is in fact an instance of undefined behaviour.
How i could concatenate such strings?
In general, there is no way how to find the length of such "strings" in the runtime. I would not call them strings as such, since "string" has a specific meaning in the C language - it refers to zero terminated strings, while your's are simply regions of memory.
However, since you know the size at compile time, you can use that. To avoid magic numbers in the code, it's better to use char arrays instead of char pointers, because then you can use the sizeof operator. However, note that all string literals in C are implicitly zero terminated! To fit the result in the 20-byte buffer, you'll want to use sizeof(x) - 1:
char a[] = "\0hey\0\0"; /* 6 */
char b[] = "word\0up yo"; /* 10 */
char c[] = "\0\0\0\0"; /* 4 */
memcpy(zp, a, sizeof(a) - 1);
zp += sizeof(a) - 1;
memcpy(zp, b, sizeof(b) - 1);
zp += sizeof(b) - 1;
memcpy(zp, c, sizeof(c) - 1);

sizeof dynamic array is not correct [duplicate]

This question already has answers here:
How to find the size of an array (from a pointer pointing to the first element array)?
(17 answers)
Closed 7 years ago.
In array there are four element so it size should be 4bit*4 = 16. (An int data type take 4 bit in my system to store the value.) But when i ran this code i only got 8 bit as the size of dynamicArray.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
//Dynamic arrays save memory by creating a pointer that stores
//the beginning of the array
int *dynamicArray = malloc(20 * sizeof(int));
*dynamicArray = 10;
printf("Address %x stores value %d\n", dynamicArray, *dynamicArray);
dynamicArray[1] = 20;
printf("dynamicArray[1] stores value %d\n", dynamicArray[1]);
dynamicArray[2] = 45;
printf("dynamicArray[2] stores value %d\n", dynamicArray[2]);
dynamicArray[3] = 34;
printf("dynamicArray[3] stores value %d\n", dynamicArray[3]);
printf("The size of dynamicArray is %d\n", sizeof(dynamicArray));
// Release unused memory:
free(dynamicArray);
return EXIT_SUCCESS;
}
Here is the image of output.
Also suggest me website for C to check the in-built function properties or to know about them more.
Thank you.
You don’t have an array; you have a pointer.
The size of the pointer is measured in bytes, not bits.
sizeof is evaluated at compile time and is constant for any given expression or type. It does not depend on the number of “filled” elements in an array (or pointer to some space that holds those elements, for that matter).
Your expression is equivalent to sizeof(int*), and pointers are 8 bytes in your environment.
I ran your code on my 32-bit computer and the value of sizeof(dynamicArray) does report 4. I bet your computer is 64-bits which is why the value is 8 instead.
Take a look at: http://www.viva64.com/en/a/0004/ and look for the table titled "Table N2. 32-bit and 64-bit data models.". That would help explain why some systems report 4 and some report 8 for the value for sizeof(dynamicArray).

Why do I get these memory addresses?

I was wondering why I get these memory addresses in this simple program.
#include <stdio.h>
int main() {
char *a = "buffera";
char *b = "bufferbb";
printf("%p %p\n", a, b);
return 0;
}
Output I get is.
00403064 0040306C
Supposedly each character occupies one byte in memory (two hex numbers), then if the string a occupy 7 + 1 = 8 bytes in memory and the address of a starts at 0x00403064, then according to me it should end at 0x00403079 and not at 0x0040306B.
0043064 + 8 = 0040306C; I don't know where you get 00403079 from.
0x00403064 + 0x8 == 0x0040306C
Note that these numbers are in hexadecimal.
But either way, while these strings can't overlap, they don't need to be placed anywhere near each other in memory.

Subtracting two strings in C

Well , I was actually looking at strcmp() , was confused about its working . Anyways I wrote this code
#include <stdio.h>
main()
{
char a[5] = "ggod";
char b[5] = "ggod";
int c = 0;
c = b - a;
printf("%d value", c);
}
and I get the output as
16
Can anyone explain Why is it 16 ?
What you have subtracted there are not two strings, but two char *. c holds the memory address difference between a and b. This can be pretty much anything arbitrary. Here it just means that you have 16 bytes space between the start of the first string and the start of the second one on your stack.
c = b - a;
This is pointer arithmetic. The array names it self points to starting address of array. c hold the difference between two locations which are pointed by b and a.
When you print those values with %p you will get to know in your case
if you print the values looks like this a==0x7fff042f3710 b==0x7fff042f3720
c= b-a ==>c=0x7fff042f3720-0x7fff042f3710=>c=0x10 //indecimal the value is 16
Try printing those
printf("%p %p\n",a,b);
c=b-a;
if you change size of array difference would be changed
char a[120]="ggod";
char b[5]="ggod";
b is an array object
a is also an array object
an array object is a static address to an array.
so b-a is adifference between 2 addresses and not between the 2 strings "ggod"-"ggod"
If you want to compare between 2 string you can use strcmp()
strcmp() will return 0 if the 2 strings are the same and non 0 value if the 2 strings are different
here after an example of using strcmp()

Resources