-5

1. Which of the following has a null terminator character added at the end?

int main()
{
        char arr[]="sample";
        char arr2[6]="sample";
        char arr3[7]="sample";
        char* strarr="sample";  
        char* strarr1=arr;  
        char* strarr2=arr2; 
        char* strarr3=arr3; 

        return 0;
}

2. Would printf("%s",somestr) fail in case:

  • somestr is an array of char with no null termination character at end?
  • somestr is a char* pointing to a continuous location of chars with no null termination character at end?

Edit : Is there a way I can check in gdb if a char* or a char array is null terminated or not?

alk
  • 69,737
  • 10
  • 105
  • 255
anurag86
  • 1,635
  • 1
  • 16
  • 31
  • 6
    it looks like you copied your homework assigned to StackOverflow. sure, we could do this for you, but if you want to learn about programming, you should spend the time to figure this out yourself. – jdigital Jun 20 '19 at 04:55
  • No, this is not a homework. It's ok if you redirect me to a similar question too provided it answers my queries. I am also ok if you just answer the edit so i can figure out all answers on my own – anurag86 Jun 20 '19 at 04:56
  • having the skills to verify this with a debugger is a good thing, but you should be able to answer these questions based on your understanding of C. – jdigital Jun 20 '19 at 05:04
  • 1
    First of, terminating characters are dependent on the compiler. Also, take an example of `char foo[5] = "abcd";` This is a valid initialization but `char foo[4] = "abcd";` is not. Also, have a look into [this](https://stackoverflow.com/questions/7564033/difference-between-char-and-char) – kalpaj agrawalla Jun 20 '19 at 05:05
  • 4
    @kalpajagrawalla No, none of this is compiler dependent. And `char too[4] = "abcd"; is valid in C and had well-defined semantics. – Keith Thompson Jun 20 '19 at 06:10
  • @kalpajagrawalla quoting from C89 3.5.7 (not changed in subsequent versions): "Successive characters of the character string literal (including the terminating null character **if there is room** or if the array is of unknown size) initialize the members of the array." –  Jun 20 '19 at 06:22
  • 1
    I'm voting to close this question as off-topic because it's a zero-effort homework dump. – Lundin Jun 20 '19 at 06:51
  • @Lundin Thnx ludin but im no more a college going guy. It looks like a homework because i have collected all the confusion i have at one place and asked here. I could have pasted the research i did to get answers from various places but im sure you wouldn't care. – anurag86 Jun 20 '19 at 10:27
  • 2
    @anurag86 It doesn't matter _why_ you ask, if it's homework, something copied out of a book or some interview question. But you need to ask specific questions and you _should_ post your own research efforts and debug attempts, so that it becomes evident which specific part you don't understand. As it stands now, you are asking far too broad, basically "how do strings work in C", to which the answer is: read the chapter about strings in your beginner-level programming book. – Lundin Jun 20 '19 at 10:47

2 Answers2

-1

First, "sample" is called a string literal. It declares a const char array terminated with a null character.

Let us go on:

    char arr[]="sample";

The right hand part in a const char array of size 7 (6 characters and a '\0'. The dimension of arr is deduced from its initialization and is also 7. The char array is then initialized from the literal string.

    char arr2[6]="sample";

arr2 has a declared size of 6. It is initialized from a string literal of size 7: only the 6 declared position are initialized to {'s', 'a', 'm', 'p', 'l', 'e'} with no terminating null. Nothing is wrong here, except that passing arr2 to a function that expects a null terminated string invokes Undefined Behaviour.

    char arr3[7]="sample";

Declared size an initialization literal string size are both 7: it is just an explicit version of the first use case. Rather dangerous because if you later add one character to the initialization string you will get a not null terminated char array.

    char* strarr="sample";  

Avoid that. You are declaring a non const char pointer on a string literal. While the standard declares explicitely:

If the program attempts to modify such an array, the behavior is undefined.

strarr[3] = 'i' would then invoke Undefined Behaviour with no warning. That being said and provided you never modify the string, you have a nice null terminated string.

    char* strarr1=arr;

Ok, you declare a pointer to another string. Or more exactly a pointer to the first character of another string. And it is correctly null terminated.

    char* strarr2=arr2; 

You have a pointer to the first character of a not null terminated char array... You could not pass arr2 to a function expecting a null terminated char array, and you cannot either pass strarr2.

    char* strarr3=arr3;

You have another pointer pointing to a string. Same behaviour as strarr1.


As per how to check in gdb for the terminating null, you cannot print it directly, because gdb knows enough of C strings to automatically stop printing a string on first null character. But you can always use p arr[7] to see whether the character after the array is a null or not.

For arr2, arr2+7 is one past the array. So it is undefined what lies there and in a truely bad system, using p arr[7] could raise a signal because it could be after the end of a memory segment - but I must admit that I have never seen that...

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • 3
    `arr3` is NOT a "const object". And your considerations about `char *s = "foo"`, being something to avoid are quite dubious, too. Character string literals, though usually read-only, are not `const`. –  Jun 20 '19 at 06:47
  • 1
    @UncleBilly: On a language lawyer point of view you are absolutely right: a string literal is a char array and is never declared const. Simply any attempt to modify such an array is Undefined Behaviour so they must be handled as if they were const. That is the reason why `char arr = "foo";` is *extremely dangerous*: you can easily invoke undefined behaviour, with no compiler warning. Anyway I have edited my answer, hoping my intent is more clear. – Serge Ballesta Jun 20 '19 at 07:48
  • I upvoted it because i agree with what you said. But unfortunately Ludin voted to close thinking its a homework. – anurag86 Jun 20 '19 at 10:22
  • BTW, why did you say _"Declared size an initialization literal string size are both 7"_ for `char arr3[7]="sample";` . I included this example simply because even though "sample" is sized 6 there should be room for null terminating character in the arr3[6], and hence should be safe. I assumed that null terminating character was added in previous arr[6] as well "sample\0" but it is out of index. But for arr3 you wrote it is even more dangerous. Wouldnt the null terminating be added automatically well within the limits of arr3 and considered safe? – anurag86 Jun 20 '19 at 10:25
  • Also how do i see(literally) the null terminating char in gdb? I tried and it doesnt show simply with "p" command – anurag86 Jun 20 '19 at 10:29
  • `arr3` isn't a string literal either. `arr3` is a *modifiable* char array which *was initialized* from a char string literal. And `strarr3` and `arr3` do not have the same behaviour -- unlike `arr3`, `strarr3` is an lvalue, it could be assigned to, incremented, etc. Also, `strarr2` is not a pointer to a char array (for that it would've had to be declared as `char(*strarr2)[] = &arr2`-- but I'll stop here, since I'm not sure that anybody cares. –  Jun 20 '19 at 11:38
  • @UncleBilly: My bad. I was confusing `arr3` and `strarr`. Of course `strarr3` and `arr3` are fine! Really sorry to have required so long to see that... For the bad wordings, you are right too. I wanted to use simple words but it resulted in incorrect statements. I hope I have changed enough of my answer to make it correct. – Serge Ballesta Jun 20 '19 at 12:01
  • @Serge Ballesta : Did you miss my question? BTW, why did you say _"Declared size an initialization literal string size are both 7"_ for `char arr3[7]="sample"; `. I included this example simply because even though "sample" is sized 6 there should be room for null terminating character in the arr3[6], and hence should be safe. I assumed that null terminating character was added in previous arr[6] as well "sample\0" but it is out of index. But for arr3 you wrote it is even more dangerous. Wouldnt the null terminating be added automatically well within the limits of arr3 and considered safe? – anurag86 Jun 20 '19 at 14:45
  • @anurag86 For `arr3` there is no problem at all. As I have told UncleBilly I was making a confusion between `strarr` and `arr3` – Serge Ballesta Jun 20 '19 at 15:03
-2

Each of arr and arr3 contains a null terminated string allocated on the stack when the function is called.

strarr points to a null terminated string allocated in the read-only data section of the program.

strarr1 points to a null terminated string allocated on the stack when the function is called.

strarr3 points to a null terminated string allocated on the stack when the function is called.

str points to the same string as strarr1.

ikegami
  • 367,544
  • 15
  • 269
  • 518
goodvibration
  • 5,980
  • 4
  • 28
  • 61
  • thnx. Can you also answer about printf() and a way to check null terminated character in gdb? – anurag86 Jun 20 '19 at 04:58
  • @anurag86: The behavior of `printf` is undetermined in this case (the null character will most likely appear at some point in memory, so it depends on whether or not this point will be a readable memory area). – goodvibration Jun 20 '19 at 05:00
  • So, printf() for arr,strarr,strarr1 would not be undefined. However printf() for arr2,arr3 and strarr2,strarr3 would be undefined. Is that correct? – anurag86 Jun 20 '19 at 05:03
  • @anurag86: No, since "not defined" and "undefined" are generally the same thing. – goodvibration Jun 20 '19 at 05:26
  • No i meant arr,strr,strarr1 would be OK and NOT undefined behavior. – anurag86 Jun 20 '19 at 05:29
  • @alk: I initially wrote `arr7` by mistake (due to to the declaration of `arr3[7]`). @ikegami noted that mistake in a comment above (now deleted). Then this dude edited my answer and changed it to `arr4` for some reason... – goodvibration Jun 20 '19 at 06:50
  • 2
    There is no `arr4`. (I see your complaint about an edit, but fix it.) A C implementation might put `arr`, `arr2`, and `arr3` on the stack, but it might store them elsewhere if the other code in the function allows it due to C’s rules about observable behavior, so it is erroneous to assert they are on the stack. The memory `strarr` points to is not required by the C standard to be read-only. – Eric Postpischil Jun 20 '19 at 07:49
  • 1
    Stack and read-only segment are only *implementation details*. What is only required is the observable behaviour. Trivially simply implementations could have no read-only data. And if the compiler can detect that an automatic string in never modified it can store it in a fixed memory zone for optimization. – Serge Ballesta Jun 20 '19 at 07:54
  • @EricPostpischil, @Serge Ballesta: Yes, I understand the urge to "philosophize" about every detail, and emphasize that things like *stack* and *data section* are not something dictated by the language standard. It's a common fanatic attitude here on Stack Overflow. I understand that you prefer to just shout UNDEFINED BEHAVIOR and emphasize that "anything could happen, you could even get pregnant as a result of calling `printf` with an improper output" (yes, there is a real such answer here, which got a lot of likes if I remember correctly). I was just trying to "flavor my answer" with some... – goodvibration Jun 20 '19 at 08:46
  • more technical details, which even though are not "part of the language", still apply in most compilers and on most platforms in general. I did this in order for this dude to get a better (more practical) perspective. So feel free to go along with your *Undefined Behavior* religion, and I'll stick to my atheism. – goodvibration Jun 20 '19 at 08:46
  • @ikegami: Your edit from `arr7` to `arr4` has not improved the answer, since neither one of them is specified in the question :) – goodvibration Jun 20 '19 at 08:49
  • 1
    @goodvibration: I have repeatedly and emphatically argued against brushing off things as “undefined behavior.” That is not the issue with the problems I noted in your answer. Asserting without qualification that the arrays are stored on the stack is erroneous **as a matter of fact** and has nothing to do with undefined behavior. It teaches students false beliefs and makes teaching the truth harder. Mentioning storage choices is completely unnecessary in this case since the question does not ask about them at all and they are not relevant to the questions asked. – Eric Postpischil Jun 20 '19 at 08:57
  • 1
    @goodvibration: And no, those details do not apply in most compilers and platforms in general. In most compilers, optimization may result in arrays being stored other than in the stack or even removed completely or transformed unrecognizably when circumstances permit. E.g., if an array is not modified in a function and no pointer to it or its parts is available outside the function, it should be placed in a read-only section of the object module (if not optimized even further), as if it were `static const`, not placed on the stack. – Eric Postpischil Jun 20 '19 at 09:06