C90环境下程序出现段错误(Segmentation fault)的原因及字符串解析方案咨询
getFirstTok Function & String Parsing Options for a Two-Pass Assembler I'm working on a two-pass assembler and need to parse strings by delimiters: first extracting the command (like "add" separated by spaces), then extracting operands (like "r3" and "r5" separated by commas). I tried testing my getFirstTok function but hit a segmentation fault (exit code 139, SIGSEGV). Here's my code:
main.c:
int main() { char *x = "add r3,r5"; char *t; char **end; t = getFirstTok(x,end); printf("%s",t); }
getFirstTok implementation:
/* getFirstTok function returns a pointer to the start of the first token. */ /* Also makes *endOfTok (if it's not NULL) to point at the last char after the token. */ char *getFirstTok(char *str, char **endOfTok) { char *tokStart = str; char *tokEnd = NULL; /* Trim the start */ trimLeftStr(&tokStart); /* Find the end of the first word */ tokEnd = tokStart; while (*tokEnd != '\0' && !isspace(*tokEnd)) { tokEnd++; } /* Add \0 at the end if needed */ if (*tokEnd != '\0') { *tokEnd = '\0'; tokEnd++; } /* Make *endOfTok (if it's not NULL) to point at the last char after the token */ if (endOfTok) { *endOfTok = tokEnd; } return tokStart; }
What's causing the segmentation fault, and would strtok be a better fit for this parsing task?
Why You're Getting a Segmentation Fault
There are two critical issues in your code leading to the crash:
Modifying a read-only string literal
Yourxis initialized aschar *x = "add r3,r5";—this points to a string literal stored in read-only memory (usually the.rodatasection of your executable). WhengetFirstToktries to run*tokEnd = '\0';, it's attempting to write to this protected region, which triggers a SIGSEGV (segmentation fault).Fix this by declaring
xas a writable character array instead:char x[] = "add r3,r5";This copies the literal into a stack-allocated, writable array, allowing the necessary modifications.
Uninitialized double pointer
end
Inmain, you declarechar **end;but never initialize it—this is a wild pointer pointing to random, invalid memory. WhengetFirstTokexecutes*endOfTok = tokEnd;, it's writing to this undefined address, which also causes a segmentation fault.Fix this by declaring a single pointer and passing its address to
getFirstTok:char *end; // Single pointer, not double t = getFirstTok(x, &end);
Is strtok a Better Fit?
strtok can work for your assembler parsing needs, but it has tradeoffs you should consider:
- Pros: It handles basic tokenization by delimiters out of the box, which would simplify your code for both space-separated commands and comma-separated operands. You can switch delimiters by calling
strtok(NULL, ",")after initial tokenization with spaces. - Cons:
- It's not thread-safe (uses static internal state), which might be an issue if you ever expand your assembler to use concurrency. For a thread-safe alternative, use
strtok_r(POSIX) orstrtok_s(C11). - It modifies the original string (replaces delimiters with
\0), just like your currentgetFirstTokfunction—so you still need to ensure you're working with writable strings (not literals). - It skips consecutive delimiters automatically (which might be desired for spaces, but could be problematic if your assembler allows optional commas or other edge cases) and doesn't handle empty tokens well.
- It's not thread-safe (uses static internal state), which might be an issue if you ever expand your assembler to use concurrency. For a thread-safe alternative, use
For an assembler, where you might need precise control over parsing (e.g., handling comments, whitespace variations, or specific syntax rules), a fixed custom parser (like your getFirstTok with the above fixes) might be more flexible. You could extend it to accept a set of delimiters instead of just spaces, making it reusable for both command and operand parsing.
内容的提问来源于stack exchange,提问作者Dvir Peretz

