1

Take a look at following code and output:

char *words[] = {"wehrmarcht", "collectorate", "hello", "hello","precorrection", "hello","wehrmarcht"};
char *wp;
cnode *np;
for(wp = *words; wp - *words < sizeof(words); wp += strlen(wp) + 1) {
    printf("wp -> %s\n", wp);
}
printf("==============================================\n");
for(int i = 0; i < sizeof(words) / sizeof(char *); i++) {
    printf("words[%d] -> %s\n", i,words[i]);
}

output:

wp -> collectorate
wp -> precorrection
wp -> wp -> %s

wp -> ==============================================

==============================================
words[0] -> wehrmarcht
words[1] -> collectorate
words[2] -> hello
words[3] -> hello
words[4] -> precorrection
words[5] -> hello
words[6] -> wehrmarcht

Process finished with exit code 0

Can someone explain what makes the wp points to some strings in code? Thanks in advance.

4
  • Were you under the assumption that the segment(s) containing your read-only string literals were somehow related to the order of appearance in your code? Commented Apr 19, 2020 at 7:01
  • when your program uses literal strings (eg "...") these string are part of the program it the area for the constant initialized data (you cannot modify them), you access this area, your for about wp starts from the address of "wehrmarcht" (so your output cannot be the one you give) then progress in that memory part, of course all depends on how the compiler/linker place data and the behavior is undefined Commented Apr 19, 2020 at 7:02
  • Some compilers have an option to share/merge duplicate string literals, and as "hello" appears three times that would really mess up the supposition of a regular sequence. Commented Apr 19, 2020 at 7:16
  • @WeatherVane the marked answer confirmed your idea, and that does make sense. Commented Apr 19, 2020 at 20:15

2 Answers 2

2

In order to experiment, I just changed your example to display the addresses of the strings.
You can see that we cannot make any assumption about the way each of these strings is stored relative to each other.

On my system (Linux 64-bit) I obtain:

$ ./prog_c
words[0] @ 0x5631c83b6080 -> wehrmarcht
words[1] @ 0x5631c83b60c0 -> collectorate
words[2] @ 0x5631c83b6100 -> hello
words[3] @ 0x5631c83b6100 -> hello
words[4] @ 0x5631c83b6140 -> precorrection
words[5] @ 0x5631c83b6100 -> hello
words[6] @ 0x5631c83b6080 -> wehrmarcht
/**
  gcc -std=c99 -o prog_c prog_c.c \
      -pedantic -Wall -Wextra -Wconversion \
      -Wc++-compat -Wwrite-strings -Wold-style-definition -Wvla \
      -g -O0 -UNDEBUG -fsanitize=address,undefined
**/

#include <stdio.h>

int
main(void)
{
  const char *words[]={"wehrmarcht", "collectorate", "hello", "hello", "precorrection", "hello", "wehrmarcht"};
  const int count=(int)(sizeof(words)/sizeof(words[0]));
  for(int i=0; i<count; ++i)
  {
    printf("words[%d] @ %p -> %s\n", i, (void *)words[i], words[i]);
  }
  return 0;
}
Sign up to request clarification or add additional context in comments.

Comments

2

How is array of string literal in C stored?

I think you are under the misunderstanding, that the string literals pointed to by the char pointers in the array words[] are stored subsequent in memory, which is not the case. Only the char pointers are stored in contiguous memory.

Also you seem to mix memory addresses like 0x764f73a1 with the size of objects or arrays in byte.


Thus, your first for loop:

for(wp = *words; wp - *words < sizeof(words); wp += strlen(wp) + 1) {
    printf("wp -> %s\n", wp);
}

invokes undefined behavior and does not make sense.

1.

wp = *words

wp gets assigned by the address of the first string literal.

2.

 wp - *words < sizeof(words)

This condition does not make sense. You compare the size of the array of pointer to char words with the address the pointer wp holds as value minus the address of the first string literal.

3.

 wp += strlen(wp) + 1

This doesn´t work as string literals do not have to be stored contiguous in memory.


As opposed to that, the second for loop:

for(int i = 0; i < sizeof(words) / sizeof(char *); i++) {
    printf("words[%d] -> %s\n", i,words[i]);
}

is correct as it only uses the char pointers in the array words and only iterate as many times as pointers are in words.

1 Comment

you're totally right. ` char **wp; for(wp = words; wp - words < sizeof(words)/ sizeof(char *); wp++) { printf("wp -> %s\n", *wp); }` this loop will also work. I am sorry I accepted another answer because the printed address made it very clear to me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.